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

15 分钟接入 OpenTelemetry:Java 应用链路追踪实战

不改业务代码,用 Java Agent 自动埋点把 Spring Boot 应用接入 OBSERVE 链路追踪,含启动参数、Logback 日志关联 trace_id 的完整配置和常见坑。

你要准备什么

  • JDK 8 及以上,一个 Spring Boot 2.x/3.x 应用
  • OBSERVE 的 OTLP 接入地址(形如 otel.example.com:4317
  • 15 分钟时间

全程不需要改业务代码,通过 Java Agent 自动埋点完成。Agent 会在类加载时自动织入埋点,覆盖 HTTP 客户端、数据库驱动、消息队列、Spring MVC 等常见组件。

第一步:下载 Java Agent

从 OpenTelemetry 官方 Release 页下载 opentelemetry-javaagent.jar,放到应用机器的固定目录,比如 /opt/otel/。建议锁定版本,生产环境不要追最新版;升级前先在测试环境跑一轮,确认传播格式与下游兼容。

第二步:配置启动参数

在 JVM 启动参数里加上:

java -javaagent:/opt/otel/opentelemetry-javaagent.jar   -Dotel.service.name=order-service   -Dotel.exporter.otlp.endpoint=http://otel.example.com:4317   -Dotel.traces.exporter=otlp   -Dotel.metrics.exporter=otlp   -Dotel.logs.exporter=otlp   -Dotel.propagators=tracecontext,baggage   -jar app.jar

几个参数说清楚:

  • otel.service.name:服务名,决定你在 OBSERVE 里看到的名字,务必全局唯一,建议和注册中心里的服务名一致;
  • otel.exporter.otlp.endpoint:OBSERVE 采集网关地址;
  • otel.propagators:传播协议,默认 tracecontext 即可,跨服务透传靠它。

生产环境建议把这些参数收敛到统一的启动脚本或 K8s Deployment 的 env 里,避免每个服务各自为政、名字和采样率不一致。

第三步:给日志挂上 trace_id

链路和日志打通的关键在日志。以 Logback 为例,在 logback.xml 的 pattern 里注入 MDC:

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%X{trace_id}] [%X{span_id}] %logger{36} - %msg%n</pattern>
  </encoder>
</appender>

Agent 会自动把 trace_idspan_id 注入 MDC,日志里就会带上这两个字段,OBSERVE 采集后即可与 Trace 关联。如果日志已经用 JSON 格式输出,记得把这两个字段加到 JSON 里,否则关联会断。

第四步:验证

发一个请求,然后在 OBSERVE 的链路查询页按 service.name = order-service 检索。能看到 Span 就说明通了。点开任意 Span,应该能看到它对应的日志;反过来,在日志里点 trace_id 也能回到整条链路。

建议再压一轮流量,观察 Span 数量、采样比例、错误率是否和预期一致,避免"看起来通了、实际大量数据被丢"。

常见坑

  • 采样率:高流量服务建议 -Dotel.traces.sampler=parentbased_traceidratio 配合 -Dotel.traces.sampler.arg=0.1,先采 10%,别把存储打爆;
  • 跨域传播:有网关或消息队列时,确认中间件透传了 traceparent 头;
  • 版本:Agent 与 SDK 版本尽量一致,避免传播格式不兼容;
  • 批量与重试:网络抖动时 OTLP 导出会有重试,注意 Agent 的 OTEL_BSP_* 批量参数,别让导出队列无限堆积。

为什么用 Agent 而不是 SDK

只给一个服务接链路追踪,手动集成 SDK 也不难。但当你有一批 Java 服务、还想统一采样率和服务命名时,Agent 的优势就出来了:配置集中在启动参数里,升级 Agent 就是换个 jar,不用重新发布业务代码。缺点是 Agent 拿不到业务语义,比如订单号、用户 ID。所以建议是:框架层面的埋点用 Agent 自动搞定,业务维度再手动加少量 Span 属性,两者互补。