Jaeger tracer初始化必须早于Echo启动且调用opentracing.SetGlobalTracer(),否则opentracing.StartSpan()因全局tracer为nil触发nil pointer dereference;ServiceName须为稳定非空字符串,UDP地址需可达,HTTP透传须正确注入/提取context并绑定至request.Context。

初始化 Jaeger tracer 必须早于 Echo 启动
漏掉 opentracing.SetGlobalTracer() 是最常见 panic 根源,错误信息通常是 nil pointer dereference。Echo 中间件或业务逻辑一旦调用 opentracing.StartSpan(),就会因全局 tracer 为 nil 崩溃。
- 初始化代码必须放在
main()函数最开头,且在echo.New()之前 -
serviceName不可为空或动态生成(如带 PID),应设为稳定字符串,例如"user-service" - 使用
jaeger.NewUDPTransport("localhost:6831", 0)时,确认本地 Jaeger Agent 正在监听 UDP 6831(jaegertracing/all-in-one默认支持);Mac 上 Docker Desktop 可能需加--network=host - 检查
jaeger.NewTracer()返回的tracer是否为nil,尤其当 agent 地址不可达时它不会 panic,只静默返回nil
Echo 中间件要正确提取并绑定 span 到 context.Context
仅调用 tracer.StartSpan() 不够——生成的 span 必须注入到 *http.Request 的 Context 中,否则下游 handler、中间件或 HTTP 客户端无法派生子 span。
- 从请求 header 提取时,必须用
opentracing.HTTPHeaders类型和opentracing.HTTPHeadersCarrier(r.Header),key 固定为uber-trace-id,不是X-Trace-ID或traceparent - 提取失败(如 header 为空)时,应新建 root span;成功则用
opentracing.ChildOf(wireCtx)创建 child span - 务必调用
r = r.WithContext(opentracing.ContextWithSpan(r.Context(), span)),把 span 绑定进 request context - 别在
defer span.Finish()前写响应体或修改 header,某些中间件(如 CORS)会提前关闭 writer 导致 panic
HTTP 客户端出向请求需自动注入 trace header
Echo 自身不处理 outbound 请求的透传,必须显式包装 http.Client 或用 otelhttp 等工具,否则链路在第一个外部调用就断裂。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
- 推荐用
otelhttp.NewClient()替代原生http.Client,它会自动注入uber-trace-id - 若坚持用原生 client,每次发请求前需手动调用:
tracer.Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header)) - 发起请求时必须用
http.NewRequestWithContext(r.Context(), ...),确保 outbound request 携带当前 span context - 注意:
req.Header.Set("uber-trace-id", ...)手动拼接极易格式错误(如少一个字节),Jaeger 会直接丢弃整个 span
gRPC 或 MQ 调用不能依赖 HTTP 中间件
Echo 中间件只覆盖 HTTP 流量。只要服务里有 gRPC 调用、Kafka 消息发送等非 HTTP 出向行为,就必须单独处理 trace context 透传,否则链路在第一跳就断开。
立即学习“go语言免费学习笔记(深入)”;
- gRPC client 端需注册
otgrpc.OpenTracingClientInterceptor(tracer);server 端对应注册otgrpc.OpenTracingServerInterceptor(tracer) - Kafka 生产者发消息前,用
tracer.Inject(span.Context(), opentracing.TextMap, carrier)写入message.Headers;消费者收消息后反向Extract - 所有异步 goroutine(如
go func() { ... }())必须显式传入带 span 的 context,不能直接读opentracing.GlobalTracer().StartSpan() - 避免在 span 上打
Log()时传指针或nil值,Jaeger SDK 可能 panic 或静默丢弃 log entry

















