必须在main()开头注册tracerprovider和settextmappropagator,否则所有span为nil、日志无trace_id、http中间件不生效、数据库调用不进链路且全程静默失败。

能快速接入,但“快”不等于“跳过初始化”。最常卡住的不是写代码,而是 otel.SetTracerProvider 没在 main() 开头调用——所有 span 都是 nil,日志没 trace_id、HTTP 中间件不生效、数据库调用不进链路,全程静默失败。
必须在 main() 开头注册 TracerProvider 和 Propagator
这不是可选项,是启动链路追踪的硬性前提。Go 的 otel.Tracer() 不报错也不 panic,但没注册就永远返回空 span。
-
otel.SetTracerProvider(tp)必须在http.ListenAndServe或框架启动(如gin.Run())之前执行,且只调一次 -
otel.SetTextMapPropagator(propagation.TraceContext{})必须同步设置,否则跨服务 header 传播失效,traceparent不会自动注入/提取 - Resource(如
service.name)要作为选项传给sdktrace.NewTracerProvider(),顺序写反会导致后台无法聚合服务名 - 别写在
init()函数里——单元测试并发运行时可能 panic
HTTP 入口和出口必须统一用 otelhttp
只包 server 端、client 还用 http.DefaultClient,链路一定断在第一个出站请求。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 入口:用
otelhttp.NewHandler(yourHandler, "api")包裹最终 handler;Gin 用户用ginotel.Middleware("my-service"),别用裸gin.Use() - 出口:client 必须用
&http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)},或直接用otelhttp.NewClient(http.DefaultClient) - 别自己解析
traceparent手动tracer.Start()——中间件已处理,重复做反而破坏上下文 - 路径匹配问题:chi 用户要用
chi.WrapHandler(otelhttp.NewHandler()),不是chi.Use()
数据库调用不能手动 Start/End,得换驱动
在 db.Query() 前后手动 tracer.Start()/span.End() 是典型错误:duration 错、context 不透、事务信息全丢——因为 database/sql 驱动根本不读 context 里的 span。
- MySQL:用
otelsql.InjectDriver("mysql", &mysql.MySQLDriver{})替换原 driver - PostgreSQL(pgx):用
pgxpool.NewWithConnConfig(...).WithTracer(&otelpgx.Tracer{}) - GORM:必须显式调
db.WithContext(ctx).Query(...),不能只传context.Background() - 别漏掉
otelsql的 import 和 init 注册(如_ "go.opentelemetry.io/contrib/instrumentation/database/sql")
OTLP exporter endpoint 路径必须写全
本地跑通、上 K8s 就断连,90% 是因为 OTLP HTTP exporter endpoint 配置不对。
- OpenTelemetry Collector 默认监听
http://localhost:4318/v1/traces - Go client 的
otlphttp.NewClient默认发到/v1/traces,所以 endpoint 必须写成http://collector:4318/v1/traces,不能只写http://collector:4318 - K8s 场景下,endpoint 别写
localhost或 IP,要用 service name(如http://otel-collector:4318/v1/traces) - TLS 问题常见于自签名证书——加
otlphttp.WithInsecure()临时绕过,生产环境需配otlphttp.WithTLSCredentials()
真正难的不是埋点,是 context 是否贯穿每个 goroutine 启动点、每个日志打点、每条消息队列消费逻辑。漏掉任意一处,链路就断成碎片。别依赖闭包捕获 context,go doWork(ctx) 才是唯一安全写法。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










