如何从gin.Context获取OpenTelemetry链路追踪详情信息?
使用otelgin从gin.Context获取链路追踪信息
问题描述
我正尝试用otelgin给项目做链路追踪,官方说追踪信息可以从gin.Context.Request.Context()里拿,但不知道怎么从中提取TraceID、SpanID这类详细信息来验证功能是否正常。
官方用stdout作为导出器初始化Tracer Provider的代码如下:
func initTracer() (*sdktrace.TracerProvider, error) { // stdout as exporter exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) return tp, nil }
现在命令行已经能输出部分追踪内容:
"Name": "/users/:id", "SpanContext": { "TraceID": "e7a43d30c0e507b4c59fd65dc3bc6d77", "SpanID": "636c22201c903573", "TraceFlags": "01", "TraceState": "", "Remote": false }, "Parent": { "TraceID": "00000000000000000000000000000000", "SpanID": "0000000000000000", "TraceFlags": "00", "TraceState": "", "Remote": false }, "SpanKind": 2, "StartTime": "2022-11-12T16:02:07.871843+08:00", "EndTime": "2022-11-12T16:02:07.871843+08:00",
但我写的中间件直接打印c.Request.Context()时,得到的是:
(type *http.contextKey, val <not Stringer>).WithValue(type *http.contextKey, val [::1]:8088).WithCancel.WithCancel.WithValue(type trace.traceContextKeyType, val <not Stringer>)
想知道怎么从gin.Context里提取这些追踪信息,以及能不能获取导出器的详细信息。
解决方法
一、提取TraceID、SpanID等追踪信息
不能直接打印Context对象,要借助OpenTelemetry的trace包从Context中提取当前Span的上下文。修改中间件代码:
import ( "fmt" "github.com/gin-gonic/gin" "go.opentelemetry.io/otel/trace" ) func TracerGetMiddleware(c *gin.Context) { // 从request context中取出当前span的上下文 spanCtx := trace.SpanContextFromContext(c.Request.Context()) if spanCtx.IsValid() { // 提取并打印关键追踪信息 traceID := spanCtx.TraceID().String() spanID := spanCtx.SpanID().String() traceFlags := spanCtx.TraceFlags().String() fmt.Printf("TraceID: %s, SpanID: %s, TraceFlags: %s\n", traceID, spanID, traceFlags) } else { fmt.Println("当前上下文没有有效追踪信息") } c.Next() }
这段代码会输出和stdout导出器里一致的TraceID、SpanID,用来验证链路追踪是否正常工作。
二、关于获取导出器信息
导出器属于Tracer Provider的一部分,不会存在gin.Context里。如果需要用到导出器相关内容:
- 初始化
initTracer时把导出器(或Tracer Provider)存成全局变量,后续直接调用即可 - 要是只是验证导出器是否正常,看stdout的输出就够了,没必要从Context里拿
三、注意事项
- 必须先注册otelgin中间件,否则
c.Request.Context()里不会有追踪信息:r := gin.Default() r.Use(otelgin.Middleware("your-service-name")) // 先注册otelgin中间件 r.Use(TracerGetMiddleware) // 再注册自定义的获取追踪信息中间件 - 只有当
spanCtx.IsValid()返回true时,才能拿到有效的TraceID和SpanID
内容的提问来源于stack exchange,提问作者Ltd
相关产品推荐
相关产品推荐

