优先选编译时插桩(Loongsuite Go Agent),因其无需改代码、避免手动埋点易遗漏和性能压测问题,而SDK手动集成易因初始化时机、context传递、endpoint配置等毛刺导致链路断裂。

Go 应用接入 OpenTelemetry,优先选编译时插桩(Loongsuite Go Agent),不是 SDK 手动埋点——后者要改代码、易遗漏、上线前还得压测性能影响;前者加个 otel 前缀就能跑,连 tracer.Start 都不用写。
为什么别一上来就 go.opentelemetry.io/otel/sdk?
SDK 手动集成看似“标准”,但真实项目里容易卡在三件事上:
-
TracerProvider初始化时机不对,比如在init()里建,但context尚未传播到 HTTP handler,导致 span 丢失 - HTTP 中间件里漏传
r.Context(),或没用httptrace拦截底层连接,DB 和 DNS 调用就断链 - 上报 endpoint 配错成
http://localhost:4318却没起 collector,日志只打Exporting span failed,不报具体错误码
这些不是概念问题,是每家自建 pipeline 都会撞上的配置毛刺。SDK 适合你已有 collector、明确要控制 span 层级、且能接受业务函数里塞 span.SetAttributes 的场景。
otelsql、otelhttp 这类子包怎么选?
它们是 OpenTelemetry 官方维护的“增强适配器”,不是必须装,但装了能省掉大量重复逻辑:
-
otelsql:自动包装database/sql的Query/Exec,记录 SQL 模板(非参数值)、执行耗时、行数;但默认不采集慢查询阈值,得自己调WithQueryFormatter -
otelhttp:拦截http.ServeMux或chi.Router,自动抓 path、status_code、method;但它不处理http.Client发出的请求,得额外套一层otelhttp.NewTransport - 注意:
otelhttp默认把整个 request body 当 attribute 记录,线上务必关掉——用WithFilter排除Content-Type: application/json等大体积请求
如果你用的是 Gin,别直接套 otelhttp 中间件,Gin 的 c.Request 是复用对象,得用 ginotel 这类社区封装,否则 span context 会在并发请求中错乱。
Loongsuite Go Agent 编译时插桩要注意什么?
它本质是 go toolchain 的 wrapper,靠重写 AST 注入 instrumentation,所以有硬性约束:
- 必须用
go build,不能用go run—— 后者跳过编译阶段,插桩失效 - 不支持 CGO enabled 的模块(比如用了
sqlite3或某些加密库),会报plugin not supported - 生成的二进制体积增加约 12%~18%,主要是嵌入了轻量 collector;若已有统一 collector,可通过
OTEL_EXPORTER_OTLP_ENDPOINT环境变量关闭内置上报 - HTTP handler 函数签名必须是标准
func(http.ResponseWriter, *http.Request),带额外参数(如func(w, r, logger))的会被跳过
它不会动你的 go.mod,也不 require import _ "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" 这类隐式依赖,这点比 SDK 更干净。
本地调试链路数据时,collector 怎么最小化启动?
别从 GitHub 下完整版 otel-collector 编译,太重。用官方预编译的 otelcol-contrib + 最小配置就行:
receivers:
otlp:
protocols:
http:
exporters:
logging:
loglevel: debug
verbose: true
service:
pipelines:
traces:
receivers: [otlp]
exporters: [logging]
然后 OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 otelcol-contrib --config ./config.yaml 启起来,再跑你的 Go 程序。关键点:
- 确保 Go 程序里设置了
OTEL_EXPORTER_OTLP_PROTOCOL=grpc或http,和 collector 的协议对齐 - 如果看到
connection refused,先curl -v http://localhost:4318/version看 OTLP/HTTP 是否监听成功 - logging exporter 默认不打印 span attributes,加
verbose: true才能看到 SQL、URL 等字段
真正难的不是连通,而是 span 名称语义是否一致——比如一个 DB 查询在服务 A 叫 user.select_by_id,到了服务 B 却变成 db.query,这种断裂只能靠团队约定命名规范,工具救不了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











