OpenTelemetry Go Jaeger Exporter 实战指南:配置、环境变量与 Span 转换原理(含弃用迁移说明)
2026/9/14 0:01:54 网站建设 项目流程

OpenTelemetry Go Jaeger Exporter 实战指南:配置、环境变量与 Span 转换原理(含弃用迁移说明)

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

本指南以仓库中 vendored 的go.opentelemetry.io/otel/exporters/jaeger模块官方 README(vendor/go.opentelemetry.io/otel/exporters/jaeger/README.md)为骨架,结合该模块源码展开。你将掌握:如何用 Go 将 OpenTelemetry Span 导出到 Jaeger Agent(UDP/compact thrift)与 Jaeger Collector(HTTP/thrift),五个OTEL_EXPORTER_JAEGER_*环境变量的完整语义与优先级规则,以及 Span 在导出链路上的序列化与分包细节,同时明确该模块的弃用状态与 OTLP 迁移路径。

注意:本文面向当前仓库(Loki)中 vendor 依赖树内锁定的该 OpenTelemetry 模块版本,所有 API、默认值与行为均以仓库内实际源码为准。

模块定位与弃用状态(必读)

go.opentelemetry.io/otel/exporters/jaeger是 OpenTelemetry Go SDK 官方提供的 Jaeger Span Exporter 实现,负责把 SDK 采集到的 Span 转换为 Jaeger 数据结构并上报。但该模块目前处于已弃用(Deprecated)状态

  • OpenTelemetry 于 2023 年 7 月停止对该 Jaeger Exporter 的支持;
  • Jaeger 官方已接受并推荐使用 OTLP 作为上报协议;
  • 官方建议改用 OTLP Trace Exporter,即go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttpgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc

尽管如此,该模块仍随依赖树 vendored 于当前仓库的 vendor/go.opentelemetry.io/otel/exporters/jaeger 目录下(完整实现仅约 10 个 Go 源文件:jaeger.goenv.goagent.gouploader.goreconnecting_udp_client.godoc.go等,并内嵌 Apache Thrift v0.14.1 的 vendored 副本与生成的internal/gen-go代码)。对于仍在维护存量 Jaeger 链路的读者,理解其配置方式与内部机制仍有现实意义;对新项目则建议直接走 OTLP。

安装

该模块的获取命令为:

go get -u go.opentelemetry.io/otel/exporters/jaeger

由于当前仓库通过 vendor 机制固化依赖,实际使用以 vendor/go.opentelemetry.io/otel/exporters/jaeger 目录中的版本为准。该模块依赖 OpenTelemetry SDK 的sdktracego.opentelemetry.io/otel/sdk/trace)与语义约定包semconv/v1.21.0,并提供trace.SpanExporter接口实现,可直接挂接到sdktrace.NewTracerProviderWithSpanProcessor上(仓库内 pkg/xcap/tracer_test.go 展示了 TracerProvider + SpanProcessor 的标准装配方式,可参考其中的sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(recorder))用法)。

快速上手示例

New是模块的入口函数,签名如下(见 jaeger.go):

func New(endpointOption EndpointOption) (*Exporter, error)

它接收一个EndpointOption(通过WithAgentEndpointWithCollectorEndpoint构造),并会从默认resource.Default()中读取service.name作为兜底服务名——若默认资源中也取不到服务名,New会直接返回错误failed to get service name from default resource。下面是一个完整的可运行用法示例(基于模块公开 API 编写):

package main import ( "context" "log" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/jaeger" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func main() { // 方式一:上报到 Jaeger Agent(UDP,compact thrift 协议) exp, err := jaeger.New(jaeger.WithAgentEndpoint( jaeger.WithAgentHost("localhost"), jaeger.WithAgentPort("6831"), )) // 方式二:上报到 Jaeger Collector(HTTP thrift 协议) // exp, err := jaeger.New(jaeger.WithCollectorEndpoint( // jaeger.WithEndpoint("http://localhost:14268/api/traces"), // jaeger.WithUsername("admin"), // jaeger.WithPassword("secret"), // )) if err != nil { log.Fatal(err) } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exp), // 挂接为批量 SpanProcessor ) otel.SetTracerProvider(tp) // ... 业务代码产生 Span ... // 优雅关闭,刷新并释放导出器资源 _ = tp.Shutdown(context.Background()) }

导出器实现sdktrace.SpanExporter接口(源码中以var _ sdktrace.SpanExporter = (*Exporter)(nil)静态断言),因此可与sdktrace.WithBatcher等标准处理器组合使用。ExporterExportSpans(jaeger.go)会先检查 context 是否已取消或导出器是否已 Shutdown(通过内部stopCh通道),随后将 spans 按 Resource 分组、逐个 batch 上传;Shutdown(jaeger.go)使用sync.Once关闭stopCh并调用底层 uploader 的shutdown释放连接。

两种上报端点与配置选项

导出器支持两种目标端点,各自对应不同的传输协议(见 README 的 Configuration 一节,及 uploader.go 实现):

端点协议构造选项说明
Jaeger Agentjaeger.thriftovercompact thrift(UDP)WithAgentEndpoint应用内联 sidecar/同机 Agent,低延迟、易丢包
Jaeger Collectorjaeger.thriftoverHTTPWithCollectorEndpoint直连 Collector,可靠传输,支持认证

Agent 端点选项(AgentEndpointOption)

WithAgentEndpoint默认启用 UDP 断线自动重连(AttemptReconnecting: true),其可配置选项(均实现在 uploader.go):

  • WithAgentHost(host string):覆盖OTEL_EXPORTER_JAEGER_AGENT_HOST,默认localhost
  • WithAgentPort(port string):覆盖OTEL_EXPORTER_JAEGER_AGENT_PORT,默认6831
  • WithLogger(*log.Logger)/WithLogr(logr.Logger):设置 Agent 客户端日志,二者互相覆盖;
  • WithDisableAttemptReconnecting():关闭 UDP 重连客户端;
  • WithAttemptReconnectingInterval(d time.Duration):设置重新解析 Agent 地址的间隔,默认 30 秒;
  • WithMaxPacketSize(size int):设置最大 UDP 包大小。

Collector 端点选项(CollectorEndpointOption)

WithCollectorEndpoint支持:

  • WithEndpoint(url string):覆盖OTEL_EXPORTER_JAEGER_ENDPOINT,默认http://localhost:14268/api/traces
  • WithUsername(username string)/WithPassword(password string):覆盖同名环境变量,用于向 Collector 发送 Basic 认证;两者均无默认值,只有同时非空时才会设置Authorization头;
  • WithHTTPClient(client *http.Client):自定义 HTTP 客户端,默认使用http.DefaultClient

优先级规则

README 明确指出:通过选项对象(Options)进行的配置优先于环境变量。即配置解析顺序为:显式 Option > 环境变量 > 内置默认值。以WithAgentEndpoint为例,源码先以envOr(envAgentHost, "localhost")读取环境变量兜底,再依次应用传入的 Options 覆盖之(见 uploader.go)。

环境变量完整对照表

以下是 README 中给出的官方环境变量表(可同时对照 env.go 中声明的常量名):

环境变量对应选项默认值
OTEL_EXPORTER_JAEGER_AGENT_HOSTWithAgentHostlocalhost
OTEL_EXPORTER_JAEGER_AGENT_PORTWithAgentPort6831
OTEL_EXPORTER_JAEGER_ENDPOINTWithEndpointhttp://localhost:14268/api/traces
OTEL_EXPORTER_JAEGER_USERWithUsername(无默认值,不设置)
OTEL_EXPORTER_JAEGER_PASSWORDWithPassword(无默认值,不设置)

源码中envOr(key, defaultValue)(env.go)的判定逻辑是:os.Getenv返回非空字符串时采用环境变量值,否则回退到默认值。这意味着空字符串环境变量会被当作未设置处理。注意OTEL_EXPORTER_JAEGER_USEROTEL_EXPORTER_JAEGER_PASSWORD属于 Collector HTTP 端点配置,对 UDP Agent 端点无效。

典型使用方式(无需改代码,纯环境变量驱动):

export OTEL_EXPORTER_JAEGER_AGENT_HOST=jaeger-agent.default.svc.cluster.local export OTEL_EXPORTER_JAEGER_AGENT_PORT=6831 # 或直连 Collector: # export OTEL_EXPORTER_JAEGER_ENDPOINT=http://jaeger-collector:14268/api/traces

源码级原理:Span 如何变成 Jaeger Batch

理解导出链路有助于排查“字段丢失”“trace 对不上”等问题。核心转换逻辑集中在 jaeger.go:

  1. 分组(jaegerBatchList,jaeger.go):按 Span 的 Resource 去重(resourceKey := ss.Resource().Equivalent())聚合成多个gen.Batch,每个 Batch 携带一个Process(即资源信息)和若干 Span;空的 span 列表直接返回 nil。
  2. Resource → Process(process 函数,jaeger.go):遍历 Resource 属性,service.name被特殊提取为Process.ServiceName(不再作为普通 tag),其余属性转换为 Process tags;若 Resource 中没有service.name,则用New时从默认资源取到的服务名兜底。
  3. Span → Thrift Span(spanToThrift,jaeger.go)
    • TraceID 与 SpanID 均以binary.BigEndian.Uint64拆分为TraceIdHigh/TraceIdLow/SpanId三个 int64 字段,ParentSpanId 取父 SpanID;时间戳与 Duration 统一以**微秒(µs,UnixNano/1000)**为单位——这解释了 Jaeger UI 中时间精度与原始纳秒的差异;
    • Attributes 按类型映射为 thrift Tag:STRING→VStrBOOL→VBoolINT64→VLongFLOAT64→VDouble,切片类型(bool/int64/float64/string 切片)会被json.Marshal成字符串后作为VStr写入(keyValueToTag,jaeger.go#L231-L275);
    • 附加约定 tag:otel.library.name/otel.library.version(来自 InstrumentationScope)、span.kind(非 Internal 时)、otel.status_code(OK/ERROR)、error=true(Error 状态时)、otel.status_description
    • Events(日志)转换为gen.Log,字段包含event(事件名,同名 attribute 会覆盖之)以及otel.event.dropped_attributes_count(被丢弃属性计数,jaeger.go#L192-L194);
    • Links 全部以FOLLOWS_FROM类型的SpanRef导出(不保留CHILD_OF之外的原始关系语义)。

传输层细节:UDP 分包与 HTTP 上传

Agent(UDP + compact thrift)

agent.go 实现agentClientUDP,关键常量与行为:

  • udpPacketMaxLength = 65000:单个 UDP 报文最大字节数(与 jaeger-agent 同步);
  • emitBatchOverhead = 70:数据报封装额外开销,实际可用载荷上限为65000 - 70
  • 序列化采用 compact thrift 协议(thrift.NewTCompactProtocolFactoryConf),并用TMemoryBuffer先计算每个 Span 的序列化大小;
  • EmitBatch会做逐 span 分包:单个 Span 超过包上限则直接丢弃并记录错误;累计大小接近上限时先flush当前批次再开启新包(agent.go#L123-L178);
  • 默认开启重连 UDP 客户端(newReconnectingUDPConn,位于 reconnecting_udp_client.go),会在 Agent 主机名对应的 DNS 记录变化时自动重新解析连接,重连间隔默认 30 秒。

Collector(HTTP + binary thrift)

uploader.go 中collectorUploader.upload的行为:

  • 使用binary thrift协议序列化整个 Batch(thrift.NewTBinaryProtocolConf),与 Agent 端的 compact 协议不同;
  • 发起POST请求到配置的 Endpoint,Content-Type固定为application/x-thrift
  • 仅当 username 与 password同时非空时才调用req.SetBasicAuth设置 Basic 认证;
  • 响应体被读取并丢弃(io.Copy(io.Discard, resp.Body)),只要 HTTP 状态码不在[200, 300)区间即返回failed to upload traces; HTTP status code: %d错误;
  • shutdown为空操作——HTTP 无长连接需要关闭。

从 Jaeger Exporter 迁移到 OTLP

鉴于模块已弃用,README 给出的官方迁移方向是改用 OTLP Trace Exporter:

  • otlptracehttpgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp,基于 HTTP/protobuf 上报,适合直连 Collector 或网关;
  • otlptracegrpcgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc,基于 gRPC 上报。

迁移时需同步调整 Jaeger 侧配置(启用 OTLP 接收端口),并将原有jaeger.New(jaeger.WithAgentEndpoint(...))等调用替换为 OTLP 对应的New/WithEndpoint选项;环境变量OTEL_EXPORTER_JAEGER_*也应替换为 OTLP 标准变量(如OTEL_EXPORTER_OTLP_ENDPOINT)。当前仓库的 vendor 依赖中已包含 OTLP 相关模块,可参照 vendor 目录确认可用的 OTLP exporter 版本后平滑切换。

参考资料与源码导航

  • 模块官方文档:vendor/go.opentelemetry.io/otel/exporters/jaeger/README.md
  • 入口与 Span 转换:vendor/go.opentelemetry.io/otel/exporters/jaeger/jaeger.go
  • 环境变量定义:vendor/go.opentelemetry.io/otel/exporters/jaeger/env.go
  • UDP Agent 客户端:vendor/go.opentelemetry.io/otel/exporters/jaeger/agent.go、vendor/go.opentelemetry.io/otel/exporters/jaeger/reconnecting_udp_client.go
  • 端点选项与 HTTP 上传:vendor/go.opentelemetry.io/otel/exporters/jaeger/uploader.go
  • Thrift 生成代码:vendor/go.opentelemetry.io/otel/exporters/jaeger/internal/gen-go/jaeger、vendor/go.opentelemetry.io/otel/exporters/jaeger/internal/gen-go/agent
  • SDK 装配参考:pkg/xcap/tracer_test.go(展示 TracerProvider + SpanProcessor 的标准用法)

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询