在我的 golang 应用程序中,我使用
otelmux
中间件和 ddotel
跟踪器提供程序来检测 OTEL 跟踪中间件:
package tracing
import (
"github.com/gorilla/mux"
"go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
ddotel "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentelemetry"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
)
// Middleware returns a tracing middleware that will add a span for each request.
func Middleware(t *TraceProvider) mux.MiddlewareFunc {
sampler := tracer.NewRateSampler(0.1)
provider := ddotel.NewTracerProvider(
tracer.WithSampler(sampler),
tracer.WithRuntimeMetrics(),
)
return otelmux.Middleware("my-service", otelmux.WithTracerProvider(provider))
}
每当跟踪附加到请求时(考虑采样率),我想从根跨度中提取跟踪 ID,这样我就可以将其注入到日志记录 API 中,以便将该请求的日志与来自同一请求的跟踪。
到目前为止,我还没有找到直接从请求上下文中获取跟踪 ID 的方法。
如何提取跟踪 ID?
感谢 @hamed-n 评论的最佳解决方案:
这是一个使用跟踪包从 span 上下文中提取跟踪 ID 的函数:“go.opentelemetry.io/otel/trace”:
func GetTraceID(ctx context.Context) string {
spanCtx := trace.SpanContextFromContext(ctx)
if spanCtx.HasTraceID() {
traceID := spanCtx.TraceID()
return traceID.String()
}
return ""
}
就我而言,由于我使用的提供程序是 DataDog,因此我必须将跟踪 ID 转换为 uint64 big endian:
func GetTraceID(ctx context.Context) string {
spanCtx := trace.SpanContextFromContext(ctx)
if spanCtx.HasTraceID() {
// Since datadog trace provider (ddtrace) uses big endian uint64 for the trace ID, we must first to first convert it back to uint64.
traceID := spanCtx.TraceID()
traceIDRaw := [16]byte(traceID)
traceIDUint64 := byteArrToUint64(traceIDRaw[8:])
traceIDStr := strconv.FormatUint(traceIDUint64, 10)
return traceIDStr
}
return ""
}
func byteArrToUint64(buf []byte) uint64 {
var x uint64
for i, b := range buf {
x = x<<8 + uint64(b)
if i == 7 {
return x
}
}
return x
}