对 Traceparent Header
理解有误
Trace Context (w3.org)
故需要解析 TraceHeader
才能获取trace_id、parent_id
func (profileCtx *ProfileContext) UnpackKafkaMessage(ctx context.Context) (needBreak bool, tpsStatus string, contextErr error) {
var traceID trace.TraceID
var parentID trace.SpanID
headers := profileCtx.msg.Headers
for _, h := range headers {
key := h.Key
value := string(h.Value)
if key == "Traceparent" {
// eg: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
split := strings.Split(value, "-")
traceID, _ = trace.TraceIDFromHex(split[1])
parentID, _ = trace.SpanIDFromHex(split[2])
break
}
}
log.Logger.Info("[UnpackKafkaItem] parse header traceparent",
zap.String("traceId", traceID.String()),
zap.String("parentID", parentID.String()),
)
//otel.GetTextMapPropagator().Extract(profileCtx.Ctx, header)
ctx = trace.ContextWithRemoteSpanContext(ctx,
trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
}))
var span trace.Span
profileCtx.Ctx, span = consumerTracer.Start(ctx, "UnpackKafkaMessage")
//profileCtx.Ctx, span = consumerTracer.Start(profileCtx.Ctx, "UnpackKafkaMessage")
defer span.End()
// ...
return
}
参考 passthrough
在 Venus
服务中初始化 TextMapPropagator
func initPassthroughGlobals() {
// We explicitly DO NOT set the global TracerProvider using otel.SetTracerProvider().
// The unset TracerProvider returns a "non-recording" span, but still passes through context.
log.Logger().Info("Register a global TextMapPropagator, but do not register a global TracerProvider to be in \"passthrough\" mode.")
log.Logger().Info("The \"passthrough\" mode propagates the TraceContext and Baggage, but does not record spans.")
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
}
再根据 Fiber 的 Context 和 Header 来解包出 Context ,创建 Span
var (
traceparent string
producerTracer = otel.Tracer("venus-producer",
trace.WithInstrumentationAttributes(attribute.String("venus.work", "producer")))
)
func SplitAndValidate(c *fiber.Ctx) error {
traceparent = c.Get("Traceparent", "default")
log.Logger().Info("Traceparent", zap.Any("Traceparent", traceparent))
log.Logger().Debug("split and validate", zap.String("client", c.IP()), zap.String("agent", string(c.Context().UserAgent())))
header := make(propagation.HeaderCarrier)
for k, v := range c.GetReqHeaders() {
header.Set(k, v)
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
ctx := otel.GetTextMapPropagator().Extract(c.Context(), header)
_, span := producerTracer.Start(ctx, "SplitAndValidate")
defer span.End()
// ...
return c.Next()
}
在Venus
中注入,ctx 为 Kafka 的 WriteMessages 的,携带 TraceParentHeader
【感觉没有必要,确实我移除这部分代码正常运行】
TraceParent
TraceParent
包含了 trace-id、parent-id
共4个字段Extract
方法应该可以根据这个TraceParent
的值来解析出trace
和span
的关系以相同的方式在 Profile
中处理,关于traceID、parentID
的代码就可以移除了
现在的 venus 和 profile 是同一级,是因为 traefik 传播的 traceparent 没有修改,parent-id 是相同的,应该需要 venus 将最后一个 span 的 span_id 更新到 traceparent 的 parent-id 的部分,然后再用 kafka 的 header 传播下来