Promethues结合Springboot

项目地址:https://gitee.com/sssuperbear/promethues-metricdemo.git

Metrics指标类型以及使用场景:

  • Counter,只增不减的计数器
  • Gauge,可增可减的仪表盘
  • Histogram,自带buckets区间用于统计分布统计图
  • Summary, 客户端定义的数据分布统计图 除了上述方法我们也可以通过拦截器/过滤器:用于统计所有应用请求的情况等

导入依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>


<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

添加application.yaml

添加application.yaml之后,可以查询路径变为:/actuator/prometheus

1
2
3
4
5
6
7
8
9
10
11
spring:
application:
name: prometheus-example
management:
endpoints:
web:
exposure:
include: "*"
metrics:
tags:
application: ${spring.application.name}

添加MetricInterceptor类

该类规定了自定义的一些指标count的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class MetricInterceptor extends HandlerInterceptorAdapter {
@Autowired
private MeterRegistry meterRegistry;
private ThreadLocal<Timer.Sample> threadLocal = new ThreadLocal<>();

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 总计数 + 1
meterRegistry.counter("micro_req_total", Tags.of("url", request.getRequestURI(), "method", request.getMethod())).increment();
// 处理中计数 +1
meterRegistry.gauge("micro_process_req", Tags.of("url", request.getRequestURI(), "method", request.getMethod()), 1);

Timer.Sample sample = Timer.start();
threadLocal.set(sample);
return super.preHandle(request, response, handler);
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
try {
super.postHandle(request, response, handler, modelAndView);
} finally {
meterRegistry.gauge("micro_process_req", Tags.of("url", request.getRequestURI(), "method", request.getMethod()), -1);
Timer timer = Timer.builder("micro_req_histogram").minimumExpectedValue(Duration.ofMillis(1)).maximumExpectedValue(Duration.ofMinutes(3))
.sla(Duration.ofMillis(10), Duration.ofMillis(50), Duration.ofMillis(100), Duration.ofMillis(300), Duration.ofMillis(1000))
.tags(Tags.of("url", request.getRequestURI(), "method", request.getMethod(), "code", String.valueOf(response.getStatus())))
.register(meterRegistry);
threadLocal.get().stop(timer);
threadLocal.remove();
}
}
}

主程序中添加注册代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.example.demo;

import com.example.demo.interceptor.MetricInterceptor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootApplication
public class DemoApplication implements WebMvcConfigurer {

@Bean
public MetricInterceptor metricInterceptor() {
return new MetricInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(metricInterceptor()).addPathPatterns("/**");
}

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

Controller中添加查询注册代码

1
2
3
4
5
// 注意,这个是注册的核心代码块
@Bean
MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${spring.application.name}") String applicationName) {
return (registry) -> registry.config().commonTags("application", applicationName);
}