OpenTelemetry链路追踪需初始化全局TracerProvider和Exporter,用otelhttp.NewHandler包裹HTTP handler,手动传context保span连续性,避免goroutine中断;采样与队列参数需调优防丢trace。

Go Web服务里怎么加OpenTelemetry链路追踪
直接上手:用 otelhttp.NewHandler 包裹 HTTP handler,再用 otel.Tracer 手动埋点关键逻辑。不装 SDK 就跑不起来,必须初始化全局 trace provider 和 exporter。
常见错误是只注册了 exporter(比如 otlphttp.NewExporter),却忘了调用 otel.SetTracerProvider —— 这会导致所有 Tracer().Start() 返回空 span,日志里完全看不到链路,但也不报错,非常难排查。
- HTTP 层推荐用
otelhttp.NewHandler,别自己写中间件去解析 header;它自动处理traceparent注入和传播 - 数据库、Redis、gRPC 调用要各自配对应的 instrumented client,比如
go.opentelemetry.io/contrib/instrumentation/database/sql,原生sql.Open不会自动埋点 - 本地开发时 exporter 用
stdout(stdouttrace.NewExporter)比 OTLP 更直观,避免过早折腾 collector 配置
为什么 Span 总是断在 HTTP 调用之后
本质是 context 没传下去。Go 的 OpenTelemetry 默认不自动跨 goroutine 传递 span,哪怕你用了 req.Context(),一旦进 goroutine 或新协程(比如 go func() {}()),span 就丢了。
典型场景:HTTP handler 里启动一个异步任务,那个任务里的 Tracer.Start() 生成的是 root span,而不是 child span。
立即学习“go语言免费学习笔记(深入)”;
- 必须显式把带 span 的 context 传进去:
go doWork(ctx),而不是go doWork(context.Background()) - 第三方库如果没适配 OpenTelemetry(比如某些老版本的
ent或gorm),它的回调函数里拿不到有效 span,得手动用otel.GetTextMapPropagator().Inject()补 header -
http.Client发请求前,记得用req = req.WithContext(ctx),否则otelhttp.Transport拿不到 parent span
OTLP exporter 连不上 collector 怎么快速定位
不是代码问题,八成是网络或配置。OpenTelemetry Go SDK 默认超时短(5s)、失败静默,连不上 collector 就丢 trace,不会 panic 也不会 log 错误。
错误现象:本地能看到 stdout 输出 span,但 Jaeger / Grafana Tempo 里空空如也。
- 先确认 collector 地址写对了:
http://localhost:4318(HTTP)或localhost:4317(gRPC),注意端口和协议别混 - 用
curl -v http://localhost:4318/v1/traces测试 collector 是否响应 200;返回 404 是正常,返回 connection refused 就说明 collector 没起来 - 给 exporter 加日志:用
WithLogger(zap.NewExample())或类似方式注入 logger,能捕获 “failed to export traces” 类错误 - 别用
localhost在 Docker 容器里连 host,换成host.docker.internal(Mac/Win)或宿主机真实 IP(Linux)
并发高时 trace 数据大量丢失怎么办
不是性能瓶颈,是默认采样器太激进。Go SDK 默认用 ParentBased(AlwaysSample),但如果你用了 BatchSpanProcessor(推荐),它的队列满了就会丢 span —— 默认队列大小才 2048。
现象是 QPS 上去后,trace 数量卡在某个值不再增长,或出现 dropped spans 日志(需开启 debug logger)。
- 增大 batch 处理器参数:
WithMaxQueueSize(10000)、WithBatchTimeout(5 * time.Second) - 换采样器:生产环境建议用
TraceIDRatioBased(0.01)控制量,而不是全量采集 - 避免在 hot path(如 for 循环里)频繁调用
Tracer.Start();合并逻辑或用一次 span 记录多个事件 - exporter 线程数默认 1,高吞吐下可考虑用
WithNumWorkers(2)(仅限 OTLP exporter)
链路追踪真正难的不是加 SDK,而是让 span 在 goroutine、channel、定时任务、中间件嵌套里不断裂——context 传到哪,span 才跟到哪。漏传一次,整条链就断了,而且很难回溯。










