Go 中的 OpenTelemetry——链路追踪、指标、日志与 Collector
内容提要
本文介绍在Go HTTP服务中集成OpenTelemetry,统一采集链路追踪、指标和日志。通过SDK与OTLP协议将数据发送至Collector,再分发到Jaeger和Prometheus。日志借助slog桥接自动携带TraceID实现关联。文章还演示Docker Compose完整栈部署,并对比OTel与Prometheus客户端库的差异。
延伸解读
为什么用 Collector 而不是直连后端
文章中的架构是应用通过 OTLP 将数据推送到 Collector,再由 Collector 分发到 Jaeger 和 Prometheus。这样做的好处是解耦:如果以后想把链路追踪从 Jaeger 换成 Tempo,只需修改 Collector 配置,应用代码不用动。Collector 还能做批处理、扇出到多个后端、在后端故障时缓冲数据。代价是多了一个需要运维的组件,但换来了后端选择的灵活性。
日志关联的关键:必须用带 Context 的方法
文章强调,使用 otelslog 桥接后,只有调用 slog.InfoContext(ctx, ...) 这类带 Context 的方法,日志记录才会自动附带当前 span 的 TraceID 和 SpanID。如果直接用 slog.Info(),日志就不会有追踪上下文,无法与链路关联。因此在请求处理链路中,应始终传递 context.Context 并使用对应的 Context 变体方法。
OTel 指标与 Prometheus 客户端库的取舍
文章对比了两者:Prometheus 客户端库只支持指标,采用拉取模型,直接暴露 /metrics 端点,与 Prometheus 绑定;OpenTelemetry 同时覆盖指标、链路和日志,采用推送模型,通过 Collector 解耦后端,并内置追踪关联。如果只需要指标且基础设施全是 Prometheus,用 Prometheus 客户端库更简单;如果需要多信号关联或希望避免供应商锁定,则选 OTel。
指标命名转换与查询注意点
OTel 指标名使用点号(如 books.created),进入 Prometheus 后会由 Collector 的 Prometheus exporter 自动转换:点号变下划线,Counter 加 _total 后缀,时长直方图加 _seconds 后缀,并加上配置的 namespace 前缀。例如 books.created 变为 bookstore_books_created_total。查询时需使用转换后的名称,否则会找不到指标。
Q&A
OpenTelemetry 在 Go 中如何实现链路追踪、指标和日志的关联?
OpenTelemetry 通过共享同一个 trace ID 实现三种信号的关联。每个日志记录自动携带产生它的请求的 trace ID 和 span ID,指标也通过上下文与追踪关联。这样,你可以从日志跳转到完整的追踪,查看请求流程,无需手动传递关联 ID。
在 Go 中如何为 HTTP 服务添加自动链路追踪?
使用 otelhttp.NewHandler 包装你的 http.Handler,例如:otelHandler := otelhttp.NewHandler(mux, "bookstore"),然后将其设置为 http.Server 的 Handler。这会为每个传入请求自动创建根 span,添加 HTTP 属性(如 http.method、http.route、http.status_code),并将 5xx 响应标记为错误。
OpenTelemetry 的 Collector 有什么作用?为什么需要它?
Collector 是一个独立的代理,接收、处理和导出遥测数据。它提供解耦(切换后端只需改配置)、处理(批处理、丢弃噪声 span、添加属性)、扇出(发送到多个后端)和缓冲(后端故障时缓存数据)等好处。
如何用 Docker Compose 部署完整的 OpenTelemetry 可观测性栈?
使用 Docker Compose 运行四个服务:bookstore 应用、otel-collector(使用 contrib 镜像并挂载配置文件)、jaeger(all-in-one 镜像,启用 OTLP)、prometheus。应用通过 OTEL_EXPORTER_OTLP_ENDPOINT 环境变量指向 Collector,Collector 将追踪发送到 Jaeger,指标暴露给 Prometheus 抓取。
OpenTelemetry 的指标 API 和 Prometheus 客户端库有什么区别?
Prometheus 客户端仅支持指标,采用拉取模型(暴露 /metrics 端点),与 Prometheus 绑定,无追踪关联。OpenTelemetry 支持指标、追踪和日志,采用推送模型(通过 OTLP 发送到 Collector),供应商中立,内置追踪关联。OTel 指标名称中的点会转换为下划线,计数器添加 _total 后缀。
在 Go 中如何让日志自动携带 TraceID 和 SpanID?
使用 otelslog 桥接器将 slog 日志发送到 OTel 管道,并始终使用带 Context 的方法(如 slog.InfoContext(ctx, ...))。桥接器会从上下文中提取活动 span,并自动将 trace ID 和 span ID 附加到日志记录。