jaeger ui空白是因为tracerprovider未初始化:必须在main()开头调用otel.settracerprovider(),否则otel.tracer()返回noop,span丢失且无报错;禁用jaeger-client-go,改用opentelemetry sdk+jaegerexporter。

Jaeger UI 空白?先确认 OpenTelemetry TracerProvider 是否初始化
Jaeger UI 显示 trace 列表为空,但程序无报错——大概率是 otel.GetTracerProvider() 返回 <nil></nil>。这不是配置问题,而是初始化时机错误。
-
TracerProvider必须在main()最早几行完成初始化,紧随flag.Parse()或viper.ReadInConfig()之后 - 绝不能塞进某个
init()函数、中间件或 handler 里;延迟注册等于全程使用 noop provider - 加一行
log.Printf("tracer provider: %v", otel.GetTracerProvider())验证,输出必须是非<nil></nil>值 - 新项目禁用已归档的
jaeger-client-go,改用go.opentelemetry.io/otel+go.opentelemetry.io/otel/exporters/jaeger
Gin 中间件必须用 otelgin.Middleware(),别手写 Extract/Inject
手动解析 traceparent 或 X-B3-* 头极易出错:大小写错、漏字段、carrier 类型不匹配,Jaeger 就静默丢弃整个 span,UI 里连根 trace 都没有。
- 直接用
otelgin.Middleware(),它自动调用otel.GetTextMapPropagator().Extract()并把 span 注入到req.Context() - 不要自己调
tracer.Extract(opentracing.HTTPHeaders, ...)—— OpenTracing 已淘汰,且语义与 W3C Trace Context 不兼容 - 确保中间件注册在 Gin router 的最外层,早于所有业务 handler
- 验证方式:在 handler 里打印
span := trace.SpanFromContext(c.Request.Context()),非 nil 才有效
goroutine 和 DB 调用必须显式透传带 span 的 context
90% 的“链路只有一跳”问题,根源都是 Go 不自动继承 context:启动 goroutine 时用了 context.Background(),或 DB 查询没 wrap,导致子 span 变成孤立 root。
- 异步任务必须写成
go doWork(ctx),其中ctx是从c.Request.Context()拿来的,不是context.Background() - SQL 查询如
db.QueryRowContext(ctx, ...)、redis.Client.Do(ctx, ...)等,所有支持Context参数的调用都必须传 - HTTP client 别用
http.DefaultClient,改用otelhttp.NewClient()实例,否则下游服务收不到 trace 上下文 - gRPC client 必须套
otelgrpc.UnaryClientInterceptor,server 端注册otelgrpc.UnaryServerInterceptor
本地开发时 Reporter 端口配错会导致 span 静默丢失
常见错误:Jaeger 容器用的是 all-in-one 镜像(默认监听 6832/udp),但代码里还配着 LocalAgentHostPort: "127.0.0.1:6831",结果 span 全部丢弃,UI 里什么也看不到。
- 确认 Jaeger 容器启动命令是否包含
-p 6832:6832/udp,对应代码中jaeger.WithAgentHostPort("127.0.0.1:6832") - 生产环境建议直连 Collector,用 HTTP 协议:
jaeger.WithCollectorEndpoint("http://jaeger-collector:14268/api/traces") - 调试阶段开启
reporter.LogSpans: true,控制台会打印 span 内容,看到日志才说明上报通了 - UDP 报文易被防火墙拦截,若本地测试失败,优先检查是否放行对应 UDP 端口
TracerProvider 初始化位置和 goroutine context 透传这两处——它们不报错,但让整条链路彻底失效,且难以定位。











