我知道我们要使用上下文传播来获取作为彼此子级创建的父级 Traceid 和 Span,但我的发布者正在使用标头(nats 不是 http)
我的消息代理使用标头,我将traceid和spanid设置为出站请求中的标头,发送消息,然后订阅者应该能够创建一个新的span,将父traceid设置为请求中的traceid。将它们链接起来
我的出站请求如下所示:
msg := new(nats.Msg)
msg.Data = []byte("new request being sent!")
msg.Subject = subject
getTraceID := requestSpan.SpanContext().TraceID().String()
header := make(nats.Header)
msg.Header = header
header.Set("traceid", getTraceID)
getSpanID := requestSpan.SpanContext().SpanID().String(
header.Set("spanid", getSpanID)
msg.Header = header
reply, err := nc.RequestMsg(msg, time.Duration(5*time.Second))
这有效,在订阅者端我可以获取跟踪和跨度 ID 的标头值
如何使用traceid在订阅者端构建上下文/跨度?
我相信我可以在频道内做这样的事情:
var traceID trace.TraceID
traceID, err = trace.TraceIDFromHex(request.TraceID)
if err != nil {
fmt.Println("error: ", err)
continue
}
var spanID trace.SpanID
spanID, err = trace.SpanIDFromHex(request.SpanID)
if err != nil {
fmt.Println("error: ", err)
continue
}
spanContext := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: 01,
})
ctx := context.Background()
ctx = trace.ContextWithSpanContext(ctx, spanContext)
var requestInLoopSpan trace.Span
ctx2, requestInLoopSpan := otel.Tracer("requestInLoop").Start(ctx, "requestInLoopSpan")
requestInLoopSpan.AddEvent("processing....") // NOT WORKING
明白了!
顺便说一句,输入 NewRequest:
type NewRequest struct {
Requestid string `json: "requestid"`
TraceID string
SpanID string
}
您需要将构造 spanContext 的代码包装在函数内:
func constructNewSpanContext(request NewRequest) (spanContext trace.SpanContext, err error) {
var traceID trace.TraceID
traceID, err = trace.TraceIDFromHex(request.TraceID)
if err != nil {
fmt.Println("error: ", err)
return spanContext, err
}
var spanID trace.SpanID
spanID, err = trace.SpanIDFromHex(request.SpanID)
if err != nil {
fmt.Println("error: ", err)
return spanContext, err
}
var spanContextConfig trace.SpanContextConfig
spanContextConfig.TraceID = traceID
spanContextConfig.SpanID = spanID
spanContextConfig.TraceFlags = 01
spanContextConfig.Remote = false
spanContext = trace.NewSpanContext(spanContextConfig)
return spanContext, nil
}
然后你调用包含跟踪和跨度 ID 的传递内容
然后使用函数返回的 spanContext 来丰富上下文:
spanContext, err := constructNewSpanContext(request)
if err != nil {
fmt.Println("ERROR: ", err)
}
fmt.Println("IS VALID? ", spanContext.IsValid()) // check if okay
requestContext := context.Background()
requestContext = trace.ContextWithSpanContext(requestContext, spanContext)
var requestInLoopSpan trace.Span
childContext, requestInLoopSpan := otel.Tracer("inboundmessage").Start(requestContext, "requestInLoopSpan")
requestInLoopSpan.AddEvent("processing....") // WORKING
这是我用来创建与另一个微服务中创建的跟踪/跨度关联的跨度的 java 函数:
import io.opentelemetry.api.trace.*;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
private Span createSpanLinkedToParent(String traceId, String spanId) {
SpanContext remoteContext = SpanContext.createFromRemoteParent(
traceId,
spanId,
TraceFlags.getSampled(),
TraceState.getDefault());
Tracer t = otel.getTracer("second-service");
SpanBuilder sb= t.spanBuilder("some-operation");
sb.setParent(Context.current().with(Span.wrap(remoteContext)));
return sb.startSpan();
}
(使用 OpenTelemetry 1.36 测试)