为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 NATS 正确传递远程父跨度?

如何使用 NATS 正确传递远程父跨度?

Go
Cats萌萌 2023-02-21 16:38:58
我在这个 repo上有一个虚拟示例我试图将当前跨度上下文传递给远程上下文,以便它可以正确显示跟踪,我所做的是:go func() {    _, span := otel.Tracer("natsC").Start(context.Background(), "publish")    defer span.End()    // send current span context as header    spanCtx := span.SpanContext()    spanJson, _ := spanCtx.MarshalJSON()    log.Println(string(spanJson))    msg, err := nc.RequestMsg(&nats.Msg{        Subject: topic1, Data: []byte("whatever"), Header: nats.Header{            "otelTrace": []string{string(spanJson)},        },    }, 2*time.Second)    if L.IsError(err, `nc.Publish`) {        return    }    log.Println(`reply:`, msg)}()在接收方服务器上:_, err = nc.QueueSubscribe(topic1, "my-queue", func(msg *nats.Msg) {    // take header and deserialize back to spanContext    rsc := msg.Header.Get(`otelTrace`)    parentSpanCtx := trace.SpanContext{}    err := json.Unmarshal([]byte(rsc), &parentSpanCtx)    L.IsError(err, `json.Unmarshal`)    // use remote context as parent context    _, span := otel.Tracer(`natsC`).Start(trace.ContextWithRemoteSpanContext(context.Background(), parentSpanCtx), topic1)    defer span.End()    data := string(msg.Data)    fmt.Println(data)    err = msg.Respond(msg.Data)    L.IsError(err, `msg.Respond`) // ignore error})然后我使用这个命令运行它go run main.go natsC。Jeager (localhost:16686) 上显示的两个跨度都是单独的跨度,不像 http/grpc 示例中那样相关,我应该修改什么才能将其视为父跨度?等效的 http/grpc 示例:
查看完整描述

1 回答

?
慕斯709654

TA贡献1840条经验 获得超5个赞

go.opentelemetry.io/otel/trace@v1.11.1/trace.go正确定义了上下文,您可以调用 MarshalJSON 并让它吐出一些看起来有用的东西,但这就是事情。没有等效的解组函数,输出是一个字符串,而内部格式是一个固定长度的字节数组......


因此,要使其正常工作,只需将跟踪和跨度 ID 转储为您喜欢的任何格式:


// Attach telemetry headers

headers := nats.Header{}

headers.Set(otelTraceID, span.SpanContext().TraceID().String())

headers.Set(otelSpanID, span.SpanContext().SpanID().String())

然后在接收端,您必须手动将其重建为 SpanContext:


func getParentContext(msg *nats.Msg) (spanContext trace.SpanContext, err error) {

    var traceID trace.TraceID

    traceID, err = trace.TraceIDFromHex(msg.Header.Get(otelTraceID))

    if err != nil {

        return spanContext, err

    }

    var spanID trace.SpanID

    spanID, err = trace.SpanIDFromHex(msg.Header.Get(otelSpanID))

    if err != nil {

        return spanContext, err

    }

    var spanContextConfig trace.SpanContextConfig

    spanContextConfig.TraceID = traceID

    spanContextConfig.SpanID = spanID

    spanContextConfig.TraceFlags = 01

    spanContextConfig.Remote = true

    spanContext = trace.NewSpanContext(spanContextConfig)

    return spanContext, nil

}

然后实际使用它:


remoteCtx, err := getParentContext(msg)

if err != nil {

    logrus.Fatal(err)

}


_, span := otel.Tracer(fqpn).Start(trace.ContextWithRemoteSpanContext(context.Background(), remoteCtx), msg.Subject)

defer span.End()

//img1.sycdn.imooc.com//63f483760001223008960384.jpg

查看完整回答
反对 回复 2023-02-21
  • 1 回答
  • 0 关注
  • 129 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号