跳转至

OpenTelemetry Go(otelc)

OpenTelemetry Go Compile-Time Instrumentation 使用 otelc 在 Go 编译阶段自动注入 OpenTelemetry SDK 初始化和组件插桩逻辑。应用不需要修改业务代码,只需将原来的 go build 替换为 go tool otelc go build,即可通过 OTLP 将遥测数据上报到 DataKit,并转发至 观测云。

本文以 otelc v1.1.0、主机安装的 DataKit 和 OTLP/gRPC 为例,完成 Go HTTP 服务的 Trace 接入:

Go 源码 -- go tool otelc go build --> 插桩后的 Go 二进制 -- OTLP --> DataKit --> 观测云

说明:otelc 的“零代码”表示业务代码不需要手动引入和初始化 OpenTelemetry SDK,并不表示无需重新构建。已经生成的普通 Go 二进制不能直接附加插桩,必须使用 otelc 重新编译并部署新产物。

前置条件

  • Go 1.25 或更高版本;
  • 项目使用 Go Module,并且可以通过普通 go build 正常编译;
  • 已安装 DataKit,且 DataKit 已连接到目标 观测云 工作空间;
  • Go 应用到 DataKit 的网络可达:OTLP/gRPC 默认使用 4317,OTLP/HTTP 使用 DataKit HTTP 端口 9529
  • 应用使用的框架或组件已被 otelc v1.1.0 支持;
  • 应用没有重复初始化 OpenTelemetry SDK。需要自行控制 SDK 生命周期的项目应使用 OpenTelemetry Go SDK 接入方式。

本文使用 Linux 主机和 net/http 服务进行说明,不包含 Kubernetes 部署。

一、开启 OpenTelemetry 采集器

进入 DataKit 的 OpenTelemetry 采集器目录。如果尚未创建配置文件,复制示例配置:

cd /usr/local/datakit/conf.d/opentelemetry
sudo cp opentelemetry.conf.sample opentelemetry.conf

确认 opentelemetry.conf 至少包含以下配置:

[[inputs.opentelemetry]]
  # 需要保留为 观测云 标签的自定义属性白名单。
  customer_tags = ["team", "project"]

  [inputs.opentelemetry.http]
    http_status_ok = 200
    trace_api = "/otel/v1/traces"
    metric_api = "/otel/v1/metrics"

  [inputs.opentelemetry.grpc]
    addr = "127.0.0.1:4317"

以上配置对应以下接收地址:

协议 数据类型 DataKit 接收地址
OTLP/gRPC Trace、Metric http://<DataKit-IP>:4317
OTLP/HTTP + Protobuf Trace http://<DataKit-IP>:9529/otel/v1/traces
OTLP/HTTP + Protobuf Metric http://<DataKit-IP>:9529/otel/v1/metrics

应用与 DataKit 不在同一主机时,将 gRPC 的 addr 调整为应用可访问的监听地址,例如 0.0.0.0:4317,并同步配置防火墙或其他网络访问控制。不要将 OTLP 接收端口直接暴露到公网。

重启 DataKit 使配置生效:

sudo datakit service restart

检查 DataKit 及 gRPC 端口:

curl http://127.0.0.1:9529/v1/ping
ss -lnt | grep 4317

二、应用接入 OpenTelemetry

插桩前检查

进入应用的 Go Module 根目录,先确认原始项目可以正常构建:

go version
go build ./...

如果当前目录还没有 go.mod,先初始化 Module:

go mod init example.com/my-service

检查项目是否已经直接依赖 OpenTelemetry SDK 或 Contrib 插桩库:

go list -m all | grep 'go.opentelemetry.io'

otelc 会注入 SDK 初始化逻辑。项目中已有另一套 SDK 初始化或重复的 HTTP instrumentation 时,可能产生重复 Span、Provider 被覆盖或依赖版本冲突。本文推荐业务代码不直接接入 SDK。

安装 otelc

使用 Go tool 指令安装并固定 otelc v1.1.0

go get -tool go.opentelemetry.io/otelc/tool/cmd/otelc@v1.1.0
go mod tidy

确认工具版本:

go tool otelc version

预期输出:

otelc version v1.1.0

生产构建应在 go.modgo.sum 中固定版本,不要使用未固定版本的 @latest

使用 otelc 编译

先保持原有构建参数不变,仅在 go build 前增加 go tool otelc

go tool otelc go build -o my-service .

带有常用构建参数的示例:

mkdir -p ./bin
go tool otelc go build \
  -trimpath \
  -ldflags="-s -w" \
  -o ./bin/my-service \
  ./cmd/my-service

otelc go 当前支持 go buildgo installgo test。第一次插桩构建需要下载并编译 OpenTelemetry 依赖,通常明显慢于普通 go build;看到终端重新出现命令提示符后,才表示构建完成。

构建完成后,.otelc-build/matched.json 中会记录匹配的规则。检查 HTTP 服务端 Hook:

jq -e '[.. | objects | .name?] | index("server_hook") != null' \
  .otelc-build/matched.json >/dev/null

注意:发布流程必须部署 go tool otelc go build 生成的二进制。后续如果使用普通 go build 覆盖产物,运行时将不包含自动插桩。

配置 OTLP/gRPC 并启动

以下配置只启用 net/http Trace,并通过 OTLP/gRPC 上报到本机 DataKit:

export OTEL_SERVICE_NAME="my-service"
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=prod,service.version=1.0.0,team=backend"

export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"

export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4317"
export OTEL_EXPORTER_OTLP_INSECURE="true"

export OTEL_GO_ENABLED_INSTRUMENTATIONS="nethttp"

./my-service

运行参数必须配置在插桩后二进制的实际运行环境中,而不只是配置在编译主机上。应用启动后,请求一个由受支持组件处理的接口,以生成可验证的 Span。

生产环境应使用 TLS endpoint,并通过 Secret 管理证书和认证 Header。http://127.0.0.1:4317 仅适用于本机接入。

使用 OTLP/HTTP

如需改用 OTLP/HTTP + Protobuf,替换协议和 endpoint:

export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:9529/otel"
export OTEL_EXPORTER_OTLP_INSECURE="true"

Exporter 会根据数据类型追加 /v1/traces/v1/metrics。仅设置 Trace endpoint 时,也可以直接使用:

export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://127.0.0.1:9529/otel/v1/traces"

三、数据上报参数

资源和 Exporter 参数

环境变量 说明 建议值或示例
OTEL_SERVICE_NAME 观测云 中 APM 服务归属的核心字段 my-service,必须显式设置
OTEL_RESOURCE_ATTRIBUTES 资源属性,多个 key=value 使用逗号分隔 deployment.environment.name=prod,service.version=1.0.0
OTEL_TRACES_EXPORTER Trace Exporter 上报到 DataKit 时设置为 otlp
OTEL_METRICS_EXPORTER Metric Exporter 不采集时设置为 none
OTEL_LOGS_EXPORTER Log Exporter 不通过 OTLP 采集应用日志时设置为 none
OTEL_EXPORTER_OTLP_PROTOCOL 通用 OTLP 协议 grpchttp/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT 各 OTLP 信号共用的 endpoint gRPC:http://datakit-host:4317
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT 仅 Trace 使用的 endpoint,优先于通用值 HTTP:http://datakit-host:9529/otel/v1/traces
OTEL_EXPORTER_OTLP_INSECURE 是否使用非 TLS 连接 本地明文连接设置为 true
OTEL_EXPORTER_OTLP_HEADERS OTLP 请求认证 Header 通过 Secret 注入,不写入代码或镜像

插桩、采样和调试参数

环境变量 说明 建议值或示例
OTEL_GO_ENABLED_INSTRUMENTATIONS 运行时插桩白名单 HTTP 服务使用 nethttp
OTEL_GO_DISABLED_INSTRUMENTATIONS 运行时插桩黑名单 按需禁用,例如 redis
OTEL_TRACES_SAMPLER Trace 采样器 接入验证使用 parentbased_always_on
OTEL_TRACES_SAMPLER_ARG 比例采样参数 例如 0.10,配合 parentbased_traceidratio
OTEL_PROPAGATORS Trace Context 传播格式 tracecontext,baggage
OTEL_LOG_LEVEL otelc 注入运行时的日志级别 默认 info,排障时使用 debug
OTEL_GO_SIMPLE_SPAN_PROCESSOR 是否逐条立即导出 Span 仅本地排障时设置为 true
OTEL_SDK_DISABLED 是否禁用注入的 SDK true 会停止采集和上报
OTELC_DEBUG 是否记录详细构建日志 排障时设置为 1

OTEL_GO_ENABLED_INSTRUMENTATIONSOTEL_GO_DISABLED_INSTRUMENTATIONS 只控制已经编译进二进制的插桩。两个变量同时存在时,先应用白名单,再排除黑名单内容。

生产环境应根据流量和数据预算设置采样率。应用侧采样和 DataKit 侧采样同时开启时,最终保留率会叠加降低,应统一规划采样位置。

支持的组件

otelc v1.1.0 内置规则覆盖以下常见组件:

类型 组件
HTTP net/http 客户端与服务端、Gin
RPC gRPC 客户端与服务端
数据库 database/sql、Redis v9、MongoDB
消息队列 Kafka Go
云和基础设施 Kubernetes client-go、AWS SDK for Go v2、Linode Go v2
GenAI OpenAI Go v1/v2/v3、Anthropic Go SDK
日志关联 标准库 loglog/slog、Logrus

实际支持范围还会受到组件版本和构建方式影响。升级应用依赖或 otelc 后,应重新检查 .otelc-build/matched.json 并执行链路回归测试。

字段映射

DataKit OpenTelemetry 采集器会将常见 OpenTelemetry Span Attributes 转换为 观测云 链路字段:

OpenTelemetry 属性 DataKit 字段
http.request.method http_method
http.response.status_code http_status_code
network.protocol.name net_protocol_name
network.protocol.version net_protocol_version
db.system.name db_system
db.operation.name db_operation
db.query.text db_statement
rpc.system.name rpc_system
rpc.method rpc_method

如需将其他 Attributes 保留为 观测云 标签,可在 DataKit opentelemetry.conf 中配置 customer_tags。不要把用户 ID、订单号等高基数值批量提升为标签,也不要上报密码、Token、完整数据库连接串等敏感信息。

验证接入

  1. 确认工具版本和插桩构建均成功:
go tool otelc version
test -x ./my-service
  1. 启动应用,确认日志中出现以下内容,并且没有 OTLP export error:
trace provider initialized with auto-export
OpenTelemetry initialized
HTTP server instrumentation initialized
  1. 请求应用接口产生 Trace:
curl http://127.0.0.1:18080/ping
  1. 检查构建规则包含 server_hook
jq -e '[.. | objects | .name?] | index("server_hook") != null' \
  .otelc-build/matched.json
  1. 使用 OTLP/gRPC 时,可以在 DataKit 主机观察接收计数是否增长:
curl -fsS http://127.0.0.1:9529/metrics \
  | grep 'opentelemetry.proto.collector.trace.v1.TraceService/Export'
  1. 进入 观测云「应用性能监测 > 链路」,按 service:my-service 查询,确认能够看到刚才请求产生的 Trace。

常见问题

go.mod file not found

go get -tool 必须在 Go Module 中执行。进入项目根目录,或者先执行:

go mod init example.com/my-service

编译停在 WORK=/tmp/go-build...

第一次插桩构建会编译较多依赖。只要 go tool otelc go build 进程仍在运行,就继续等待;终端重新出现命令提示符后才表示构建结束。不要在编译过程中提前执行应用二进制。

请求端口连接失败

先确认编译已经结束并启动插桩后的二进制,再检查监听端口:

ss -lntp | grep 18080

应用正常但 观测云 没有 Trace

依次检查:

  • 部署的是否为 go tool otelc go build 生成的二进制;
  • OTEL_SERVICE_NAME、Exporter、协议和 endpoint 是否配置在实际运行进程中;
  • .otelc-build/matched.json 是否包含预期规则;
  • OTEL_GO_ENABLED_INSTRUMENTATIONS 是否包含目标组件;
  • DataKit OpenTelemetry 采集器是否开启并重启生效;
  • 应用到 DataKit 的网络和 43179529 端口是否可达。

构建问题可以临时启用详细日志:

OTELC_DEBUG=1 go tool otelc go build -o my-service .

详细日志位于 .otelc-build/debug.log。排障结束后关闭 Debug,避免日志持续增长。

第一次 Ctrl+C 后应用没有退出

otelc v1.1.0 注入的运行时会监听 SIGINTSIGTERM,第一次信号用于刷新遥测数据,但应用仍负责自己的退出流程。未实现优雅关闭的简单应用可能需要再次发送信号。生产服务应使用 Go 标准库实现 HTTP Server 优雅退出,并预留遥测刷新时间。

参考

文档评价

文档内容是否对您有帮助?