← 返回文章列表
使用指南 4 分钟阅读 炬鲸团队

OpenTelemetry 接入指南:零侵入埋点与自定义 Span

从选型理由到落地步骤:为什么用 OTel 而不是厂商 SDK、Java/Node 等自动埋点零改代码、业务逻辑内部耗时用自定义 Span 补齐、trace_id 打进日志串起追踪,附排错清单。

为什么选 OpenTelemetry 而不是自研 SDK

接入可观测系统,第一个决定是"用谁家的 SDK"。自研或绑定某家厂商的 SDK,意味着以后换后端要重写埋点。OpenTelemetry(OTel)是 CNCF 的标准项目,一套 API 打天下:埋一次点,数据可以同时发给 OBSERVE、Jaeger、Prometheus 多个后端。OBSERVE 原生支持 OTel 协议(OTLP),这是接入成本最低、也最不容易被绑死的一条路。

第一步:自动埋点,零改代码

Java、Node、Python、Go 都有 OTel 的自动埋点 Agent,原理是字节码注入或猴子补丁,在框架的收口处(HTTP 入口、DB 驱动、消息队列客户端)自动创建 Span,应用代码一行不改。

Java 举例,启动参数加一个 javaagent:

java -javaagent:opentelemetry-javaagent.jar \
  -Dotel.exporter.otlp.endpoint=https://ob.jjhub.cn/ingest/otlp \
  -Dotel.service.name=order-service \
  -jar order-service.jar

起来之后,HTTP 请求、JDBC 查询、Redis 调用会自动产生 Span 并上报。先跑自动埋点,能覆盖 80% 的常见场景,剩下的 20% 是业务逻辑内部的耗时,要靠自定义 Span。

第二步:自定义 Span 补业务细节

自动埋点看不到业务函数内部的耗时,比如"这个函数里有一段循环算优惠券,跑了 800ms"。这时需要手动埋点:

Span span = tracer.spanBuilder("calc-coupon")
    .setAttribute("coupon.count", 5)
    .startSpan();
try (Scope scope = span.makeCurrent()) {
    calculateCoupons(order);
} finally {
    span.end();
}

命名要有意义、能直接回答"这是什么操作",别叫 span1、span2。给 Span 加属性时,注意别把用户手机号、身份证这类敏感数据当属性打进去——属性会被存储和检索,等于把敏感数据写进了追踪库。

第三步:把 trace_id 打进日志

链路追踪和日志要串起来,最实用的做法是在日志里带上 trace_id。用 OTel 的日志桥接或直接在日志 pattern 里加 %X{trace_id}(Logback MDC),之后在 OBSERVE 里看到一条报错日志,就能用它的 trace_id 反查整条链路。

采样与资源消耗

自动埋点会有性能开销,一般每请求增加 1-5% 的 CPU,网络上是每个 Span 一次小包。生产环境建议:核心服务采样率 100%(配合尾采样),边缘服务 10%-30%;Agent 用异步批量上报,避免同步阻塞业务线程。

排错清单

  • 数据没到 OBSERVE:先看 Agent 日志,九成是 endpoint 配错或 token 没配;
  • Span 有但没连成链路:检查上下文传播,跨服务要传 traceparent 请求头,网关或中间件有没有把它丢掉;
  • 属性缺失:确认自动埋点版本和框架版本匹配,低版本框架可能拿不到某些属性。