Java OpenTelemetry 监控实战:Spring Boot 指标接入完整教程
为 Java/Spring Boot 应用接入 OpenTelemetry 指标:依赖引入、Counter/Gauge/Histogram 实现、用属性为指标添加上下文维度、外部 API 调用监控,以及导出到观测云实现看板与告警。附 Filter 与 Service 完整代码。
Java 的 OpenTelemetry 指标接入有两种路线:零代码的 Java Agent(自动埋点主流框架)与显式的 SDK 编程(完全掌控业务指标)——生产实践通常是两者结合:Agent 兜底框架层,手写代码覆盖核心业务指标。
核心要点速览
- Spring Boot 场景用 Filter/拦截器统一埋点 HTTP 指标;
- Counter 记总量、Gauge 记水位、Histogram 记延迟分布;
- Attributes 为指标加维度(端点/方法/状态码),但要防高基数;
- 导出端点指向观测云 DataKit,指标告警看板一站搞定。
引入依赖
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
或者更简单——直接用 Java Agent(-javaagent:opentelemetry-javaagent.jar),通过环境变量配置 OTLP 端点,HTTP/数据库/消息队列指标自动产出。
封装指标 Service
@Service
public class MetricsService {
private final LongCounter requestCounter;
private final LongUpDownCounter activeRequests;
private final DoubleHistogram requestDuration;
public MetricsService(MeterProvider meterProvider) {
Meter meter = meterProvider.get("shop-service");
this.requestCounter = meter.counterBuilder("http.server.requests.total")
.setDescription("Total HTTP requests").setUnit("requests").build();
this.activeRequests = meter.upDownCounterBuilder("http.server.active_requests")
.setDescription("Active HTTP requests").build();
this.requestDuration = meter.histogramBuilder("http.server.request.duration")
.setDescription("Request latency").setUnit("s").build();
}
public void incrementRequestCounter(Attributes attrs) { requestCounter.add(1, attrs); }
public void incrementActiveRequests(Attributes attrs) { activeRequests.add(1, attrs); }
public void decrementActiveRequests(Attributes attrs) { activeRequests.add(-1, attrs); }
public void recordDuration(double seconds, Attributes attrs) { requestDuration.record(seconds, attrs); }
}
用 Filter 统一埋点并附加属性
@Component
public class MetricsFilter extends OncePerRequestFilter {
private final MetricsService metricsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
Attributes attrs = Attributes.builder()
.put("endpoint", request.getRequestURI())
.put("method", request.getMethod())
.build();
metricsService.incrementRequestCounter(attrs);
metricsService.incrementActiveRequests(attrs);
long start = System.nanoTime();
try {
chain.doFilter(request, response);
} finally {
metricsService.decrementActiveRequests(attrs);
metricsService.recordDuration(
(System.nanoTime() - start) / 1e9,
attrs.toBuilder().put("status", response.getStatus()).build());
}
}
}
基数警告:request.getRequestURI() 若含路径参数(/user/12345)会让每个用户一个标签组合——务必改用路由模板(Spring 的 HandlerMapping 最佳匹配模式),把维度数控制在几十个以内。
监控外部 API 调用
对下游依赖单独建指标,出问题时分得清"是我慢还是它慢":
public Product fetchProduct(String id) {
long start = System.nanoTime();
try {
Product p = restTemplate.getForObject("/products/" + id, Product.class);
productApiCalls.add(1, Attributes.builder()
.put("api", "product-service").put("result", "success").build());
return p;
} catch (Exception e) {
productApiCalls.add(1, Attributes.builder()
.put("api", "product-service").put("result", "failure").build());
throw e;
} finally {
productApiDuration.record((System.nanoTime() - start) / 1e9,
Attributes.of(AttributeKey.stringKey("api"), "product-service"));
}
}
Java Agent 与手写指标的分工
| 层 | 推荐手段 |
|---|---|
| HTTP/JDBC/Redis/MQ 框架指标 | Java Agent 自动埋点 |
| JVM 运行时(GC/堆/线程) | Agent 自带 |
| 业务指标(订单量、转化率) | 手写 SDK 代码 |
Agent 的 OTLP 端点用环境变量配置:OTEL_EXPORTER_OTLP_ENDPOINT=http://datakit:4318。
观测云落地:Java 应用的完整监控栈
OTLP 端点指向观测云 DataKit 后,指标进入观测云指标模块——用 DQL 按 endpoint 聚合出各接口的 QPS/错误率/P95,场景视图搭建服务总览看板,监控器配置"active_requests 突增""外部 API 失败率"等告警直达钉钉/企微/飞书。Java Agent 同时会产出链路数据,观测云 APM 中的服务拓扑、火焰图开箱即有,指标异常一键下钻到具体 Trace。
常见问题(FAQ)
Q:有了 Micrometer 还需要 OTel 指标吗? Micrometer 是门面、OTel 可以是其实现之一;新项目直接用 OTel API 更简单,存量 Micrometer 代码可通过桥接迁移。
Q:Agent 和 SDK 同时用会重复上报吗? 框架层指标由 Agent 产出、业务指标由手写代码产出,名称空间不同不冲突;注意别让手写代码重复统计 Agent 已覆盖的 HTTP 指标。
Q:Histogram 桶边界怎么定? 按 SLO 定:如接口要求 P99 < 1s,桶边界围绕 0.1/0.3/0.5/1/2s 分布,让关键区间分辨率足够。
Q:多实例部署指标怎么区分? OTel 资源属性自动带 service.instance.id,观测云中按实例标签过滤或聚合即可。