HTTP server端无span的根本原因是otelhttp.NewHandler未正确包裹并注册到路由链,导致server端trace逻辑未执行。

为什么 HTTP server 端没 span?
根本不是 SDK 没装好,而是 otelhttp.NewHandler 包裹后的 handler 没被真正注册进路由链。常见现象:只看到 client span,server 端完全空白。
- 用标准库时,必须写
http.Handle("/api", otelhttp.NewHandler(myHandler, "api")),不能漏掉包裹;写成http.Handle("/api", myHandler)就等于没接入 - 用
chi要调chi.WrapHandler(otelhttp.NewHandler(...));用gin得用gin.WrapH(otelhttp.NewHandler(...)),直接传原始 handler 会跳过所有 OTel 中间逻辑 - 检查中间件顺序:如果有自定义中间件提前
return或 panic,span.End()就不会执行,span 被静默丢弃 -
otelhttp.NewHandler第二个参数(span name)不能是空字符串,Jaeger 等 exporter 会直接过滤掉
context 里的 traceID 怎么透传到 goroutine 和 DB?
Go 的 context 不自动跨 goroutine 继承,DB 驱动也不读 context —— 不显式传,链路立刻断裂。
- 起新 goroutine 时,必须写
go doWork(ctx),而不是go doWork();ctx是带 span 的那个,不是context.Background()或context.TODO() - 数据库操作必须用带 context 的方法:
db.QueryContext(ctx, ...)、db.ExecContext(ctx, ...);ORM 如gorm要链式调用.WithContext(ctx) - 日志打点想带 trace_id,别用全局 logger,改用
log.WithValues("trace_id", trace.SpanContext().TraceID().String());或者集成otellogrus这类桥接器
采样器和传播器初始化顺序为什么关键?
这两处一错,整条链路在第一个服务就断了,后面全白搭。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
-
otel.SetTextMapPropagator(...)必须在任何 handler 启动前完成,否则propagation.TraceContext{}.Extract()解析不到traceparent头,下游收不到 context -
sdktrace.AlwaysSample()别在生产环境开——QPS 上千时 exporter 积压、重试风暴、CPU 扛不住;推荐sdktrace.ParentBased(sdktrace.TraceIDRatioBased(0.1)) -
TraceIDRatioBased(0.01)是按 trace ID 哈希后取 1%,不是“每 100 个请求采 1 个”,低频服务可能连续几小时没数据,上线前务必验证
OTLP exporter 连不上 collector 怎么排查?
错误信息如 failed to export trace: rpc error: code = Unavailable desc = connection closed,基本就是网络或协议没对上。
立即学习“go语言免费学习笔记(深入)”;
- OpenTelemetry Go SDK 默认走 gRPC 协议(端口
4317),不是 Jaeger 的6831或14250;确认 collector 是否监听了0.0.0.0:4317并启用了 gRPC 接收器 - 用
otlptracegrpc.NewClient时,如果 collector 开了 TLS,就不能加otlptracegrpc.WithInsecure();反之没开 TLS 却强制走安全通道,也会连不上 - Docker 部署 collector 时,别只暴露 UI 端口(
16686),必须暴露4317(gRPC)或4318(HTTP/JSON)并映射到宿主机

















