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

十分钟接入 OpenTelemetry:从零到可观测

手把手教程:容器里的 Java/Python 服务如何用 OpenTelemetry 自动埋点,把 Trace、指标、日志接入 OBSERVE,并补上业务手工埋点与 trace_id 关联,附常见踩坑清单。

目标与前置条件

目标很具体:一个跑在容器里的 Java 或 Python 服务,十分钟内把 Trace、指标、日志接进 OBSERVE,并能在页面上看到完整调用链。前置条件只有一个:OBSERVE 已部署,且你能拿到 OTLP 上报地址和访问 token。本文假设你的服务已经跑在容器里、有办法改启动命令或环境变量,其余步骤零业务代码改动。

第一步:装 SDK 并开启自动埋点

Java 服务不用改业务代码,加一个 -javaagent 参数即可:

java -javaagent:opentelemetry-javaagent.jar   -Dotel.exporter.otlp.endpoint=http://observe-host:4317   -Dotel.resource.attributes=service.name=order-api,deployment.environment=prod   -Dotel.metrics.exporter=otlp   -jar order-api.jar

Python 用自动插桩,先装依赖再启动:

pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
opentelemetry-instrument   --traces_exporter otlp --metrics_exporter otlp   --exporter_otlp_endpoint http://observe-host:4317   python app.py

关键点:上报端点统一走 OTLP(gRPC 4317 或 HTTP 4318),OBSERVE 侧同时接收 Trace 和 Metrics,不需要维护两套 exporter 配置。service.name 一定要显式设置,否则默认取进程名或 jar 名,检索时对不上。生产环境建议再带上 deployment.environment,方便按环境过滤。

第二步:给关键业务补手工埋点

自动埋点覆盖框架和库,但业务语义(下单、支付、退款)需要手动 Span:

from opentelemetry import trace
tracer = trace.get_tracer("order-api")

with tracer.start_as_current_span("create_order") as span:
    span.set_attribute("order.amount", 128.0)
    span.set_attribute("user.id", uid)
    # ...业务逻辑

给 Span 打上业务属性,排查时才能按金额、用户 ID 过滤到具体请求。Java 侧同理,用 Span.current().setAttribute(...) 即可。一个建议:把业务属性的 key 统一成团队约定(如 user.idorder.amount),不要张三写 userId、李四写 user_id,否则检索时漏数据。

第三步:关联日志与链路

把 trace_id 注入日志格式,让每行日志都能和调用链对上:

import logging
from opentelemetry import trace

class TraceIdFilter(logging.Filter):
    def filter(self, record):
        ctx = trace.get_current_span().get_span_context()
        record.trace_id = format(ctx.trace_id, '032x')
        return True

logging.basicConfig(format='%(asctime)s [trace_id=%(trace_id)s] %(message)s')

如果日志已经用 Filebeat 之类的采集器收进 OBSERVE,只要日志里带 trace_id= 字段,平台就会自动识别并关联到对应链路,不用再配映射。

采样策略:别一上来就全采

Trace 全量采样成本高,默认建议先用「头部采样 + 保留错误和慢请求」的策略:

  • 正常请求按 10% 采样。
  • HTTP 状态码 >= 500 的请求 100% 保留。
  • 耗时超过 500ms 的慢请求 100% 保留。

这样既控制住了存储和采集开销,又保证出问题时关键样本都在。OBSERVE 侧还支持尾采样,按错误率和慢请求比例在 Agent 端二次过滤。

资源属性:别只留一个服务名

除了 service.name,把部署相关的元数据也补齐,排查时能少问一句「这是哪个环境哪台机器」:

  • service.version:版本号,回滚排查时能对号入座。
  • host.name / container.id:定位到具体实例。
  • deployment.environment:区分 prod / staging。

这些属性会随每条 Span 上报,检索时可直接过滤。补齐之后,一个「哪个版本的 order-api 在报错」的问题,一条查询就能回答,不用去翻发布记录。属性命名同样建议团队约定,避免各自为政。

可选:加一层 OpenTelemetry Collector

当服务多了以后,直接让每个进程连 OBSERVE 不太好管理,建议在中间加一层 Collector 做批量、脱敏和路由:

receivers:
  otlp:
    protocols: { grpc: { endpoint: 0.0.0.0:4317 }, http: { endpoint: 0.0.0.0:4318 } }
processors:
  batch: {}
  attributes:
    actions:
      - key: user.phone
        action: delete
exporters:
  otlp:
    endpoint: observe-host:4317
    headers: { authorization: "Bearer ${TOKEN}" }
service:
  pipelines:
    traces: { receivers: [otlp], processors: [attributes, batch], exporters: [otlp] }
    metrics: { receivers: [otlp], processors: [batch], exporters: [otlp] }

Collector 三个好处:统一加 token、集中做字段脱敏、批量压缩降低网络开销。Kubernetes 环境建议以 DaemonSet 部署。

验证与常见坑

接完后发几条真实请求,到 OBSERVE 的 Trace 页按服务名检索,确认能看到完整调用链;再切到指标页确认 http.server.duration 等指标有值。三个高频坑:一是 exporter 端点拼错(漏路径或写错端口);二是网络不通,先 telnet observe-host 4317 确认;三是采样率过低看不到低频请求,排查时先临时改成 always_on。另外记得确认 OTLP 上报带上了 token,否则会被网关静默拒绝。还有两个高频问题:一是 Java Agent 版本和业务 JDK 不匹配时会静默不埋点,先看启动日志里有没有 OpenTelemetry 相关输出;二是 HTTP/1.1 上报在大流量下会排队积压,生产环境尽量用 gRPC(4317)。如果 Trace 页能看到数据但指标页是空的,多半是 metrics exporter 没开启,检查 otel.metrics.exporter 配置。

接入完成只是第一步。真正让可观测性持续起作用的,是不断给关键链路补埋点、补齐业务属性,并按团队规范统一命名。建议把接入步骤写成脚本固化进 CI/CD,新服务启动时自动带上 Agent,避免每个服务都手工配一遍。