Go语言 如何使用NATS正确传递远程父范围?

kmpatx3s  于 2022-12-16  发布在  Go
关注(0)|答案(1)|浏览(175)

我有一个关于this repo的虚拟示例
我尝试将当前的span上下文传递给一个远程上下文,这样它就可以正确地显示跟踪,我所做的是:

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命令运行它。
两个span在Jeager(localhost:16686)上显示为单独的span,不像http/grpc示例中那样相互关联,我应该修改什么才能将其视为父span的子span?
第一节第一节第一节第一节第一次
等效的http/grpc示例:

4nkexdtk

4nkexdtk1#

go.opentelemetry.io/otel/trace@v1.11.1/trace.go有正确的上下文定义,你可以调用MarshalJSON,让它吐出一些看起来有用的东西,但事情是这样的。没有等效的解组函数,输出是字符串,而内部格式是固定长度的字节数组...
因此,要使其工作,只需将跟踪ID和范围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()

相关问题