
Go 服务启动时就该注册 TracerProvider
不注册 TracerProvider,后续所有 Tracer.Span() 调用都会返回空 span,日志里看不到任何 trace_id,但程序也不报错——这是最常被忽略的“静默失效”。
必须在 main() 最早期完成注册,且全局唯一。别在某个 handler 里临时 new 一个,也别用 init() 函数分散注册逻辑。
- 用
otel.SetTextMapPropagator配合propagation.TraceContext{}支持 HTTP header 中的traceparent透传 - 导出器(如
otlphttp.NewClient)要显式设置超时和重试,否则网络抖动时 span 会直接丢弃 - 本地开发可先用
stdoutexporter,但注意它默认只打 span 结束事件,不打 start,容易误判 span 未生效
HTTP 中间件里必须调用 otelhttp.NewHandler
手写 req.Header.Get("traceparent") + tracer.Start() 是错的:漏掉 span context 的跨 goroutine 传播、丢掉 server span 的 net.peer.ip 等语义属性、无法自动记录 4xx/5xx 状态码。
otelhttp.NewHandler 不是“可选增强”,它是 Go 生态中唯一正确绑定 HTTP 生命周期的封装。
立即学习“go语言免费学习笔记(深入)”;
- 它会自动把 inbound request 包装成 server span,并在 response 写完后结束 span
- 若用了 Gin/Echo,别直接 wrap
http.Handler;Gin 要用ginotel.Middleware,Echo 要用echootel.Middleware,否则 span name 会是GET /而不是实际路由名 - 自定义中间件里如果要创建 child span,必须从
r.Context()拿 context,不能用context.Background()
数据库调用必须用 OpenTelemetry 插件,不是手动埋点
看到有人在 db.Query() 前后自己调 tracer.Start()/End(),结果 span duration 比实际 SQL 执行时间短一大截——因为没捕获连接池等待、驱动解析等耗时。
OpenTelemetry 官方维护的 go.opentelemetry.io/contrib/instrumentation/database/sql 才能真正 hook 到 driver.Conn 底层。
- 注册时用
sql.OpenDB(driver)而非sql.Open(),否则插件不生效 - MySQL 驱动要用
github.com/go-sql-driver/mysql,不能用modernc.org/sqlite这类纯 Go 驱动的变体,部分变体不兼容插件 hook 点 - span 名默认是
SELECT FROM users这种,敏感字段不会脱敏,生产环境需配置WithSpanNameFormatter替换为固定名
ctx 传递断裂是 80% 的 span 丢失原因
典型表现:上游有 trace_id,下游 span 的 trace_id 变成全 0,或 parent_span_id 为空。不是 SDK bug,是 Go 的 context 传递断了。
常见断裂点:goroutine 启动时没传 ctx、channel receive 后没用 context.WithValue 补上下文、第三方库(如某些 redis client)内部新建了 context。
- 所有
go func() { ... }()必须带参数ctx context.Context,并在 goroutine 内部用span := trace.SpanFromContext(ctx)续上链路 - 用
otel.GetTextMapPropagator().Inject()把 context 写进 HTTP header 或 MQ message 时,确保目标服务也调用了Extract(),两边 propagator 类型必须一致 - logrus/zap 日志里想打 trace_id?别依赖全局变量,用
trace.SpanFromContext(ctx).SpanContext().TraceID().String()显式取,否则异步日志可能拿到错误的 trace_id
链路追踪不是加几个包就能跑通的事,context 就像水,断一节,整条河就干了。最稳的做法:每个函数签名都带 ctx context.Context,拒绝裸 go func(),拒绝任何隐式 context 创建。










