go项目集成opentelemetry需四步:1.安装otel sdk及导出器;2.初始化tracerprovider并显式配置采样策略(如traceidratiobased);3.用otelhttp等中间件自动注入trace上下文;4.配置otlp或jaeger导出器将数据发至collector。

go.opentelemetry.io/otel/sdk/trace 初始化必须配 sampler
不设 sampler 时默认是 ParentBased(AlwaysSample),但实际行为常被误读为“全量上报”——它只对有父 Span 的请求采样,根 Span(如 HTTP 入口)反而可能被丢弃,导致链路开头断裂。线上环境务必显式配置,否则 Jaeger 或 CLS 里看不到首跳 Span。
推荐做法:
- 开发/测试用
otlptracehttp.NewExporter+sdktrace.WithSampler(sdktrace.AlwaysSample()) - 生产环境用
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.1))(10% 采样率),避免压垮 Collector 或 CLS 接入点 - 若需按路径动态采样(如 /health 不采、/api/order 100% 采),得自己实现
sdktrace.Sampler接口,检查sc.SpanKind()和sc.SpanName()
otlpmetrichttp.Exporter 需手动调用 periodic reader
go.opentelemetry.io/otel/sdk/metric 的 HTTP 导出器不自带轮询机制,不像 gRPC 版本会自动重连和 flush。如果你只注册了 exporter 却没启动 periodic.Reader,Metric 数据永远不会发出——现象是 Prometheus 拉不到指标,CLS 里也查不到 metric 日志。
关键代码段:
controller := metric.NewController( metric.NewPeriodicReader( exporter, metric.WithInterval(30*time.Second), // 必须设,不能为 0 ), )
注意:WithInterval 小于 10s 容易触发 CLS 的限流(错误码 429 Too Many Requests),腾讯云文档明确建议 ≥30s;同时别忘了在 main() 结束前调用 controller.Shutdown(context.Background()),否则最后一轮数据可能丢失。
HTTP 中间件 otelhttp.NewHandler 要传 *http.ServeMux
很多 Go 项目直接用 http.ListenAndServe(":8080", nil),此时默认 handler 是 http.DefaultServeMux。但 otelhttp.NewHandler 第二个参数必须是具体 handler 实例,传 nil 会导致 panic:panic: http: nil Handler。
正确写法分两种场景:
- 用默认 mux:先声明变量
var mux = http.NewServeMux(),注册路由后传otelhttp.NewHandler(mux, "my-service") - 用 Gin/Echo 等框架:别套
otelhttp.NewHandler,改用对应框架的 OTel 插件(如ginotel.Middleware),否则 context 无法透传,Span 名固定为HTTP GET,丢失路径信息 - 若坚持裸用 net/http,记得把所有
http.HandleFunc改成mux.HandleFunc,否则中间件不生效
CLS 上报要拼接 Authorization Header,不是硬编码 AK/SK
向 ap-guangzhou.cls.tencentcs.com 这类 CLS Endpoint 发送 OTLP/HTTP 请求时,otlpmetrichttp.NewExporter 或 otlptracehttp.NewExporter 不会自动加鉴权头。漏掉 Authorization 直接返回 401 Unauthorized,且错误日志极不明显(常卡在 timeout 后报 context deadline exceeded)。
必须手动构造 header:
headers := map[string]string{
"Authorization": fmt.Sprintf("TC3-HMAC-SHA256 Credential=%s/%s/cls/tc3_request, SignedHeaders=content-type;host;x-tc-date, Signature=%s",
os.Getenv("TENCENTCLOUD_SECRET_ID"),
time.Now().UTC().Format("2006-01-02"),
signature,
),
"Content-Type": "application/x-protobuf",
"X-TC-Date": time.Now().UTC().Format(http.TimeFormat),
}
exporter, _ := otlpmetrichttp.NewExporter(
otlpmetrichttp.WithEndpoint("ap-guangzhou.cls.tencentcs.com"),
otlpmetrichttp.WithHeaders(headers),
)
签名计算较复杂,建议直接用腾讯云官方 tcutils 工具包生成 signature;更稳妥的做法是走内网接入点 + VPC service role,完全规避 AK/SK 注入问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











