Springboot整合Prometheus-自定义指标

依赖

// actuator依赖提供指标
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
  <version>2.6.3</version>
</dependency>

// 将指标转换成prometheus可使用的格式
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
  <version>1.8.2</version>
</dependency>
ps:
1、以下指标名称都为prometheus接收的指标名称
2、http://ip:port/actuator/prometheus 此为prometheus默认开放接口,输出prometheus格式
3、http://localhost:11130/actuator/metrics 此为actuator的指标接口,输出当前开放的指标

SpringBoot自定义指标

注入依赖

要注册自定义指标,需要注入MeterRegistry到你的组件

import io.micrometer.core.instrument.MeterRegistry;

@Autowired
private MeterRegistry meterRegistry;

Meters(指标)

Counter(计数器)

Counter是一种比较简单的Meter,它是一种单值的度量类型,或者说是一个单值计数器。Counter接口允许使用者使用一个固定值(必须为正数)进行计数。准确来说:Counter就是一个增量为正数的单值计数器。这里举个很简单的使用例子:
1、使用meterRegistry创建指标

Counter counter = meterRegistry.counter("http.request", "createOrder", "/order/create");
counter.increment();

2、使用Counter内部建造器类Counter.Builder去实例化Counter

Counter counter = Counter.builder("name")  //名称
                .baseUnit("unit") //基础单位
                .description("desc") //描述
                .tag("tagKey", "tagValue")  //标签
                .register(meterRegistry);//绑定的MeterRegistry
        counter.increment();

3、FunctionCounterCounter的特化类型,它把计数器数值增加的动作抽象成接口类型ToDoubleFunction,这个接口JDK1.8中对于Function的特化类型接口。FunctionCounter的使用场景和Counter是一致的。FunctionCounter使用的一个明显的好处是,我们不需要感知FunctionCounter实例的存在,实际上我们只需要操作作为FunctionCounter实例构建元素的AtomicInteger实例即可,这种接口的设计方式在很多框架里面都可以看到。

AtomicInteger n = new AtomicInteger(0);
        //这里ToDoubleFunction匿名实现其实可以使用Lambda表达式简化为AtomicInteger::get
        FunctionCounter.builder("functionCounter", n, AtomicInteger::get)
                .baseUnit("unit") //基础单位
                .description("desc") //描述
                .tag("tagKey", "tagValue")  //标签
                .register(meterRegistry);
        n.incrementAndGet(); // 仅对自增api有效
使用场景:

Counter的作用是记录XXX的总量或者计数值,适用于一些增长类型的统计,例如下单、支付次数、Http请求总量记录等等,通过Tag可以区分不同的场景,对于下单,可以使用不同的Tag标记不同的业务来源或者是按日期划分,对于Http请求总量记录,可以使用Tag区分不同的URL。

gauge(量规)

Gauge是获取当前度量记录值的句柄,也就是它表示一个可以任意上下浮动的单数值度量Meter。Gauge通常用于变动的测量值,测量值用ToDoubleFunction参数的返回值设置,如当前的内存使用情况,同时也可以测量上下移动的”计数”,比如队列中的消息数量。Gauge的典型使用场景是用于测量集合或映射的大小或运行状态中的线程数。Gauge一般用于监测有自然上界的事件或者任务,而Counter一般使用于无自然上界的事件或者任务的监测,所以像Http请求总量计数应该使用Counter而非GaugeMeterRegistry中提供了一些便于构建用于观察数值、函数、集合和映射的Gauge相关的方法:
1、使用meterRegistry创建指标

List<String> list = registry.gauge("listGauge", Collections.emptyList(), new ArrayList<>(), List::size); 
List<String> list2 = registry.gaugeCollectionSize("listSize2", Tags.empty(), new ArrayList<>()); 
Map<String, Integer> map = registry.gaugeMapSize("mapGauge", Tags.empty(), new HashMap<>());

上面的三个方法通过MeterRegistry构建Gauge并且返回了集合或者映射实例,使用这些集合或者映射实例就能在其size变化过程中记录这个变更值。更重要的优点是,我们不需要感知Gauge接口的存在,只需要像平时一样使用集合或者映射实例就可以了。此外,Gauge还支持java.lang.Number的子类,java.util.concurrent.atomic包中的AtomicInteger和AtomicLong,还有Guava提供的AtomicDouble:

AtomicInteger n = registry.gauge("numberGauge", new AtomicInteger(0));
n.set(1);
n.set(2);

2、建造器流式创建:

List<Integer> list = new ArrayList<>();
//一般我们不需要操作Gauge实例
Gauge gauge = Gauge.builder("gauge", list, List::size)
         .baseUnit("unit") //基础单位
         .description("desc") //描述
         .tag("tagKey", "tagValue")  //标签
         .register(meterRegistry);
使用场景:

1、有自然(物理)上界的浮动值的监测,例如物理内存、集合、映射、数值等。
2、有逻辑上界的浮动值的监测,例如积压的消息、(线程池中)积压的任务等,其实本质也是集合或者映射的监测。

timers(计时器)

Time适用于记录耗时比较短的事件的执行时间,通过时间分布展示事件的序列和发生频率。所有的Timer的实现至少记录了发生事件的数量和这些事件的总耗时,从而生成一个时间序列。Timer的基本单位基于服务端的指标而定,但是实际上我们不需要过于关注Timer的基本单位,因为Micrometer在存储生成的时间序列的时候会自动选择适当的基本单位。Timer接口提供的常用方法如下:
1、使用meterRegistry创建指标

		Timer print1000 = meterRegistry.timer("print1000");
		print1000.record(()->{ 
			// 传入任务,并自行执行
		     for (int i = 0; i < 1000; i++) {
		         System.out.println(i);
		     }
		 });
        Timer print1000 = meterRegistry.timer("print1000");
		// 只定义了指标以及任务,不自行执行
        Runnable wrap = print1000.wrap(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println(i);
            }
        });
        // 执行后指标才有值
        wrap.run();

2、建造器流式创建:

 Timer print1000 = Timer.builder("print1000")
                .description("desc") //描述
                .tag("tagKey", "tagValue")  //标签
                .register(meterRegistry);

        Runnable wrap = print1000.wrap(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println(i);
            }
        });
        wrap.run();

3、Timer的使用还可以基于它的内部类Timer.Sample,通过startstop两个方法记录两者之间的逻辑的执行耗时。

        Timer.Sample sample = Timer.start(meterRegistry);
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
        sample.stop(meterRegistry.timer("print1000"));

4、FunctionTimerTimer的特化类型,它主要提供两个单调递增的函数(其实并不是单调递增,只是在使用中一般需要随着时间最少保持不变或者说不减少),一个用于计数的函数和一个用于记录总调用耗时的函数。

官方文档中的例子如下:

IMap<?, ?> cache = ...; // 假设使用了Hazelcast缓存
registry.more().timer("cache.gets.latency", Tags.of("name", cache.getName()), cache,
    c -> c.getLocalMapStats().getGetOperationCount(),  //实际上就是cache的一个方法,记录缓存生命周期初始化的增量(个数)
    c -> c.getLocalMapStats().getTotalGetLatency(),  // Get操作的延迟时间总量,可以理解为耗时
    TimeUnit.NANOSECONDS
);

countFunction用于统计事件个数,totalTimeFunction用于记录执行总时间,实际上两个函数都只是Function函数的变体,还有一个比较重要的是总时间的单位totalTimeFunctionUnit。简单的使用方式如下:

 		//这个是为了满足参数,暂时不需要理会
        Object holder = new Object();
        AtomicLong totalTimeNanos = new AtomicLong(0);
        AtomicLong totalCount = new AtomicLong(0);
        FunctionTimer.builder("functionTimer",
                        holder,
                        p -> totalCount.get(), // 统计事件个数
                        p -> totalTimeNanos.get(), // 记录执行总时间
                        TimeUnit.NANOSECONDS) // 总时间的单位
                .description("desc") //描述
                .tag("tagKey", "tagValue")  //标签
                .register(meterRegistry);
        totalTimeNanos.addAndGet(10000000);
        totalCount.incrementAndGet();
使用场景:

1、记录指定方法的执行时间用于展示。
2、记录一些任务的执行时间,从而确定某些数据来源的速率,例如消息队列消息的消费速率等。

long task timer(长任务定时器)

LongTaskTimer也是一种Timer的特化类型,主要用于记录长时间执行的任务的持续时间,在任务完成之前,被监测的事件或者任务仍然处于运行状态,任务完成的时候,任务执行的总耗时才会被记录下来,而无返回的Timer记录的是任务启动间隔时间。在Spring应用中,可以简单地使用@Scheduled@Timed注解,基于spring-aop完成定时调度任务的总耗时记录:
1、@Timed注解使用

@Timed(value = "aws.scrape", longTask = true)
@Scheduled(fixedDelay = 360000)
void scrapeResources() {
    //这里做相对耗时的业务逻辑
}

2、使用meterRegistry创建指标

 LongTaskTimer print1000 = meterRegistry.more().longTaskTimer("print1000");
        print1000.record(()->{
            // 传入任务,并自行执行
            for (int i = 0; i < 1000; i++) {
                System.out.println(i);
            }
        });

3、建造器流式创建:

        LongTaskTimer print1000 = LongTaskTimer.builder("print1000")
                .description("desc") //描述
                .tag("tagKey", "tagValue")  //标签
                .register(meterRegistry);
        print1000.record(()->{
            // 传入任务,并自行执行
            for (int i = 0; i < 1000; i++) {
                System.out.println(i);
            }
        });
使用场景:

LongTaskTimer适合用于长时间持续运行的事件耗时的记录,例如相对耗时的定时任务。

distribution summary(分布式摘要)

Summary主要用于跟踪事件的分布,在Micrometer中,对应的类是Distribution Summary(分发摘要)。它的使用方式和Timer十分相似,但是它的记录值并不依赖于时间单位。常见的使用场景:使用Distribution Summary测量命中服务器的请求的有效负载大小。
1、使用meterRegistry创建指标

DistributionSummary summer = meterRegistry.summary("summer");
summer.record(0.25);

2、建造器流式创建:

DistributionSummary register = DistributionSummary.builder("summer")
           .description("desc") //描述
           .tag("tagKey", "tagValue")  //标签
           .register(meterRegistry);
   register.record(0.25);
使用场景

不依赖于时间单位的记录值的测量,例如服务器有效负载值,缓存的命中率等。

常用标签

常用标签可以对所有指标进行添加通用标签

management.metrics.tags.application=${spring.application.name}
management.metrics.tags.tagKey=tagValue

禁用指标

下面以http.server.requests示例禁用

management.metrics.enable.http.server.requests=false
  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于创建独立的、基于生产级别的Java应用程序的框架。而Prometheus是一个开源的监控和警报系统,用于记录和查询应用程序的时间序列数据。在Spring Boot中集成Prometheus可以方便地监控和度量应用程序的性能指标。 要在Spring Boot中集成Prometheus自定义Prometheus指标,可以按照以下步骤进行操作: 1. 添加依赖:在Spring Boot项目的pom.xml文件中添加Prometheus相关的依赖。例如: ```xml <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> ``` 2. 配置Prometheus:在Spring Boot项目的配置文件(如application.properties或application.yml)中添加Prometheus相关的配置。例如: ```yaml management: endpoints: web: exposure: include: prometheus ``` 这样配置后,Spring Boot会自动将Prometheus的监控端点暴露出来。 3. 自定义指标:在代码中使用Micrometer库来定义和记录自定义指标。Micrometer是一个度量库,可以与Prometheus集成。例如,可以使用`Counter`来记录计数器指标,使用`Gauge`来记录度量指标等。以下是一个示例: ```java import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CustomMetrics { private final Counter customCounter; @Autowired public CustomMetrics(MeterRegistry meterRegistry) { customCounter = meterRegistry.counter("custom_counter"); } public void incrementCustomCounter() { customCounter.increment(); } } ``` 在上述示例中,我们定义了一个名为`custom_counter`的计数器指标,并通过`MeterRegistry`将其注册到Micrometer中。 4. 访问指标:启动Spring Boot应用程序后,可以通过访问`/actuator/prometheus`端点来获取Prometheus格式的指标数据。例如,可以使用浏览器或curl命令访问`http://localhost:8080/actuator/prometheus`来获取指标数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值