如何从Spring Boot单例类中采集Prometheus的Summary指标
这个问题我之前也碰到过,核心原因是指标注册的上下文不对,或者说没有和Spring Boot的监控体系正确整合。下面给你两种解决方案,优先推荐第一种官方规范的方式:
方案1:使用Spring Boot官方推荐的Micrometer集成Prometheus
Spring Boot官方是通过Micrometer来对接各种监控系统(包括Prometheus)的,这种方式能完美和Spring生态整合,避免原生API的兼容性问题。
步骤1:添加依赖
首先确保你的项目里有这两个依赖(Maven示例):
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
步骤2:配置暴露Prometheus端点
在application.properties(或application.yml)里开启Actuator的Prometheus端点:
# 暴露prometheus端点 management.endpoints.web.exposure.include=prometheus # 启用Prometheus指标导出 management.metrics.export.prometheus.enabled=true
步骤3:在@Component类中使用Micrometer的Summary
通过构造注入MeterRegistry,用Micrometer的API创建和管理指标:
@Component public class SomeClass { private final Summary apiLatencySummary; private SimpleTimer timer; // 构造注入Spring管理的MeterRegistry public SomeClass(MeterRegistry meterRegistry) { this.apiLatencySummary = Summary.builder("api_latency") .description("elapsed time in call to api") .register(meterRegistry); } @Scheduled(cron = "${scheduled.job.time}") public void run() { timer = new SimpleTimer(); // 执行你的API调用逻辑 apiLatencySummary.record(timer.elapsedSeconds()); } }
这样配置后,启动项目访问/actuator/prometheus就能看到api_latency指标了,Prometheus配置好采集这个端点就能拿到数据。
方案2:使用Prometheus原生Java Client(不推荐,但可以解决)
如果你一定要用原生的Prometheus Java Client,核心是要把指标注册到Spring Boot Actuator使用的CollectorRegistry,而不是默认的全局注册表。
修改后的代码示例
@Component public class SomeClass { private final Summary summary; private SimpleTimer timer; // 注入Spring提供的CollectorRegistry public SomeClass(CollectorRegistry collectorRegistry) { this.summary = Summary.build() .name("api_latency") .help("elapsed time in call to api") .register(collectorRegistry); } @Scheduled(cron = "${scheduled.job.time}") public void run() { timer = new SimpleTimer(); // 执行你的API调用逻辑 summary.observe(timer.elapsedSeconds()); } }
为什么之前的代码不行?
你之前用静态变量直接调用Summary.build().register()时,指标被注册到了CollectorRegistry.defaultRegistry这个全局默认注册表,但Spring Boot Actuator暴露的是自己管理的独立CollectorRegistry,两者不互通,所以Prometheus采集不到默认注册表的指标。另外静态变量的初始化时机在Spring实例化Bean之前,根本拿不到Spring管理的注册表,自然就注册错地方了。
内容的提问来源于stack exchange,提问作者kramsiv94

