4. 创建基础 TracerProvider:初始化、Resource 与 Propagator
在 OpenTelemetry Go SDK 中,TracerProvider 是整个追踪体系的起点。它负责创建 Tracer、管理 Span 的导出行为,并承载服务标识与上下文传播策略。本章将手把手搭建一个生产可用的基础 TracerProvider,涵盖三个核心步骤:初始化 Provider、配置 Resource 属性、设置默认 TextMapPropagator。
4.1 初始化 TracerProvider
OpenTelemetry Go SDK 通过 sdktrace.NewTracerProvider() 创建 Provider 实例。初始化时通常需要指定 SpanProcessor 与 Exporter,但在基础阶段,我们可以先使用 Noop 导出 或 内存导出 来验证链路结构。
关键概念: TracerProvider 是全局唯一的追踪工厂。每个服务只应初始化一次,并在进程生命周期内复用。
以下代码展示了最简初始化方式:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/trace"
)
func initTracerProvider() *trace.TracerProvider {
// 使用默认配置创建 TracerProvider
tp := trace.NewTracerProvider(
// 后续会添加 Resource、Processor 等选项
)
// 设置为全局 TracerProvider
otel.SetTracerProvider(tp)
return tp
}
| 初始化选项 | 作用 | 推荐场景 |
|---|---|---|
trace.WithSampler(sampler) |
设置采样策略(如 AlwaysSample、RatioBased) | 控制数据量,生产环境必配 |
trace.WithSpanProcessor(processor) |
注册 Span 处理器(如 BatchSpanProcessor) | 异步导出到 Collector 或后端 |
trace.WithResource(resource) |
绑定服务标识元数据 | 区分不同服务/环境 |
trace.WithIDGenerator(idGen) |
自定义 TraceID/SpanID 生成器 | 兼容已有追踪系统 |
4.2 配置 Resource 属性
Resource 是描述服务运行环境的元数据集合,每个 Span 都会携带这些属性。OpenTelemetry 定义了标准资源属性(如 service.name、service.version、host.name),也支持自定义标签。
配置 Resource 的推荐方式是通过 resource.New() 合并多个来源:
import (
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)
func newResource() *resource.Resource {
r, _ := resource.New(
context.Background(),
resource.WithAttributes(
semconv.ServiceNameKey.String("go-web-demo"),
semconv.ServiceVersionKey.String("1.0.0"),
semconv.DeploymentEnvironmentKey.String("production"),
),
resource.WithHost(),
resource.WithOS(),
resource.WithContainer(),
)
return r
}
最佳实践: 始终使用
semconv 包中的常量键名,确保跨服务语义一致性。自定义属性建议加命名空间前缀,如 team.owner。
将 Resource 注入 TracerProvider:
tp := trace.NewTracerProvider(
trace.WithResource(newResource()),
)
4.3 设置默认 TextMapPropagator
Propagator 负责在服务间传递追踪上下文。OpenTelemetry 支持多种传播协议,最常用的是 W3C TraceContext(traceparent / tracestate 头)。
设置全局 Propagator 的代码:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
func initPropagator() {
// 组合 W3C TraceContext 与 Baggage
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
),
)
}
| Propagator 类型 | HTTP Header | 适用场景 |
|---|---|---|
TraceContext{} |
traceparent / tracestate |
W3C 标准,推荐默认 |
Baggage{} |
baggage |
传递业务上下文(如用户ID) |
JaegerPropagator{} |
uber-trace-id |
兼容 Jaeger 旧版 |
注意: 如果服务同时接收外部请求并发出下游调用,必须确保 Propagator 在 HTTP 中间件和 HTTP Client 中一致使用,否则链路会断裂。
4.4 完整初始化流程
将上述三个步骤整合为一个函数,形成基础 TracerProvider 的完整初始化:
func InitOpenTelemetry() (*trace.TracerProvider, error) {
// 1. 创建 Resource
res, err := resource.New(
context.Background(),
resource.WithAttributes(
semconv.ServiceNameKey.String("go-web-demo"),
semconv.ServiceVersionKey.String("1.0.0"),
),
resource.WithHost(),
)
if err != nil {
return nil, err
}
// 2. 创建 TracerProvider
tp := trace.NewTracerProvider(
trace.WithResource(res),
// 生产环境应替换为 BatchSpanProcessor
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exporters)),
)
// 3. 设置全局 Provider 和 Propagator
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
),
)
return tp, nil
}
4.5 基础架构图
下图展示了 TracerProvider 初始化后,在 Go Web 服务中的核心位置与数据流向:
4.6 初始化检查清单
- Resource 完整性: 至少包含
service.name和service.version,建议添加deployment.environment。 - Propagator 一致性: 全局 Propagator 必须与 HTTP 中间件和 HTTP Client 使用的传播器一致。
- Provider 生命周期: 在
main()或服务启动阶段初始化,并在进程退出前调用Shutdown()刷新缓冲。 - 采样策略: 生产环境不要使用
AlwaysSample,推荐ParentBased(TraceIDRatioBased(0.1))。
验证方法: 初始化后,通过
otel.GetTracerProvider() 获取全局 Provider,调用 Tracer("test").Start() 创建 Span,检查 Span 的 Resource 属性是否包含预期标签。