必须在main()开头注册TracerProvider并设置传播器,否则链路静默失效;Echo中需用echootel.Middleware作为最外层中间件,禁用otelhttp.NewHandler,出向调用须用instrumented client。

不配 echootel.Middleware,所有 span 都是 root;不提前注册 TracerProvider,整个链路静默失效——这不是报错,是“看起来正常,实则没数据”。
echootel.Middleware 必须作为最外层中间件
它依赖 echo.Context 的生命周期自动注入 span 并传播上下文。如果先经过自定义 auth 或 logging 中间件,且这些中间件未调用 c.SetRequest(c.Request().WithContext(...)),trace context 就断了。
- 正确顺序:
e.Use(echootel.Middleware())放在e.Use(...)最前面 - 不能把
otelhttp.NewHandler塞进e.Use():Echo 不是标准http.Handler,直接套用会导致路由参数(如:id)丢失、span.Name退化为HTTP GET - 若需过滤健康检查路径(如
/health),用echootel.WithFilter(func(c echo.Context) bool { return c.Path() != "/health" })
TracerProvider 必须在 main() 开头注册
延迟注册或放在 init() 里,会导致单元测试并发 panic;放 middleware 或 handler 里 new,则多个 provider 冲突、采样错乱、exporter 连接泄漏。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
- 必须在
main()第一行(或紧随init()后)执行:sdktrace.NewTracerProvider()+otel.SetTracerProvider()+otel.SetTextMapPropagator(propagation.TraceContext{}) -
Resource必须显式传入:tracesdk.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String("my-echo-svc"))),否则 Jaeger 里看不到service.name - 漏掉
otel.SetTextMapPropagator,上游 traceparent header 就无法解析,所有 span 都变成 root
出向调用必须用 instrumented client
手动在 http.Client.Do() 前后 span.Start()/End() 是典型误区:只覆盖业务代码执行时间,漏掉 DNS、连接池等待、TLS 握手、网络往返等真实耗时。
- HTTP 出向:用
otelhttp.NewTransport(http.DefaultTransport)构造 client,不是改http.DefaultClient - 数据库:用
otelsql.InjectDriver("mysql", mysqlDriver)注册驱动,再sql.OpenDB();纯 Go 驱动(如modernc.org/sqlite)不兼容 - Goroutine 跨协程传播:必须用
req.Context()派生子 context,不能用context.Background()
最容易被忽略的是 Resource 初始化和 propagator 设置——它们不报错、不 panic,但 service.name 缺失、traceparent 解析失败,Jaeger 里就只剩一堆无归属的 root span。










