必须在main()开头注册tracerprovider并调用otel.settracerprovider和otel.settextmappropagator,否则所有span为nil;http需用otelhttp.newhandler和otelhttp.transport,数据库用otelsql.injectdriver,goroutine和日志须显式传递context。

别再用 jaeger-client-go 初始化 tracer
它已归档,不支持 Go 的 context 透传模型,goroutine 中 span 极易断裂或丢失。otel.SetTracerProvider(tp) 必须在 main() 开头完成,否则所有 Tracer().Start() 都退化为 noop —— 这是 80% 的“没数据”问题根源。
- 新项目必须用
go.opentelemetry.io/otel+go.opentelemetry.io/otel/exporters/jaeger或更推荐的go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp - 本地调试优先启用
stdoutexporter.NewUnstarted(),看到 JSON 输出再切回 OTLP,避免盲调 - 生产环境 endpoint 必须显式指定,比如
otlptracehttp.WithEndpoint("otel-collector:4317");若 collector 启用了 TLS 或 Basic Auth,得配otlptracehttp.WithTLSClientConfig()或otlptracehttp.WithHeaders()
HTTP 和 gRPC 入口必须走标准中间件
手动在每个 handler 里 StartSpan 不仅遗漏风险高,还无法对齐请求生命周期。OpenTelemetry 的自动注入只发生在中间件层,原生 http.ServeMux 或 gin.Engine 不触发 span 创建。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- Gin 服务用
otelgin.Middleware(),它内部封装了otelhttp.NewHandler()行为,自动 extracttraceparent、创建 root span、注入 context 到 request - gRPC 服务必须同时启用
otelgrpc.UnaryServerInterceptor()和otelgrpc.UnaryClientInterceptor();只加 server 端拦截器,下游调用仍无子 span - 自定义 mux 时,每个 route 都要显式 wrap:
http.Handle("/api", otelhttp.NewHandler(http.HandlerFunc(handler), "api"))
下游 HTTP 调用必须用 otelhttp.NewClient() 或手动 inject
req.WithContext(ctx) 只传 context,不传 trace 上下文 —— 这是最常被忽略的断链原因。Go SDK 不会自动把当前 span 注入 outbound 请求。
- 禁用
http.DefaultClient,改用otelhttp.NewClient()实例,它自动完成 inject + extract - 若用带 retry 的自定义 client,务必封装
DoWithContext(ctx, req)工具函数,在每次Do()前调用otel.GetTextMapPropagator().Inject() - 跨语言调用(如 Python/Node.js)前,确认 propagator 类型一致;启动时可加日志打印
otel.GetTextMapPropagator().Fields()查看生效 header 名
DB 和异步任务的 span 生命周期必须显式管理
90% 的“单服务链路”问题源于 context 未正确传递或 span 提前结束。异步任务里 start 了 span 却忘了 span.End(),会导致数据卡在 batch exporter 缓冲区,内存缓慢上涨,几小时后 OOM。
- MySQL 用
otelmysql.Wrap(),PostgreSQL 用otelpostgresql.Wrap(),否则 SQL 执行不计入 span - goroutine 启动必须写成
go doWork(req.Context()),而非go doWork() - time.AfterFunc 回调中 context 可能已被 cancel,应在函数内重新获取 span,或用
otel.WithSpanFromContext()显式传入 - 所有
Tracer.Start()必须配对span.End(),defer span.End()是底线,不是可选
propagation.HTTPTraceContext{},不是靠 header 名字硬编码;手动 inject 时漏掉 otel.GetTextMapPropagator().Inject() 这一步,链路就断在第一个出站请求。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










