SpringBoot系列之Prometheus自定义埋点上报

本文涉及的产品
可观测监控 Prometheus 版,每月50GB免费额度
简介: 之前介绍了一篇SpringBoot集成Prometheus实现数据上报的博文,在前面一篇博文中,更多的是一个SpringBoot应用如何最小成本的接入Prometheus,并结合Grafana配置一个完整的应用监控大盘有看过前文的小伙伴可能知晓,SpringBoot接入Prometheus之后,基本上不用做额外的开发,就已经实现了我们关心的JVM情况、GC情况、HTTP调用请求等信息,然而在实际的业务开发过程中,我们总会遇到一些需要手动上报的场景,那么我们可以怎么处理呢?

image.png


之前介绍了一篇SpringBoot集成Prometheus实现数据上报的博文,在前面一篇博文中,更多的是一个SpringBoot应用如何最小成本的接入Prometheus,并结合Grafana配置一个完整的应用监控大盘


有看过前文的小伙伴可能知晓,SpringBoot接入Prometheus之后,基本上不用做额外的开发,就已经实现了我们关心的JVM情况、GC情况、HTTP调用请求等信息,然而在实际的业务开发过程中,我们总会遇到一些需要手动上报的场景,那么我们可以怎么处理呢?


本文的核心知识点:


  • 通过一个实例演示SpringBoot应用,如何实现自定义的数据上报

上篇博文: SpringBoot整合Prometheus实现应用监控


I. 项目环境搭建



本文演示的项目主要为SpringBoot2.2.1版本,更高的版本使用姿势没有太大的区别,至于1.x版本的不确保可行(因为我并没有测试)


1.依赖


pom依赖,主要是下面几个包


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
</dependencies>
复制代码


2. 配置信息


其次是配置文件,注册下Prometheus的相关信息


spring:
  application:
    name: prometheus-example
management:
  endpoints:
    web:
      exposure:
        include: "*"
  metrics:
    tags:
      application: ${spring.application.name}
复制代码


上面配置中,有两个关键信息,前面博文也有介绍,这里简单说明


  • management.endpoints.web.exposure.include 这里指定所有的web接口都会上报
  • metrics.tags.application 这个应用所有上报的metrics 都会带上application这个标签


配置完毕之后,会提供一个 /actuator/prometheus的端点,供prometheus来拉取Metrics信息


II. 自定义上报



假设我们现在想自己上报http请求的相关信息,当前计划采集下面几个信息


  • 总的请求数:采用Counter
  • 当前正在处理的请求数:采用Gauge
  • 请求耗时直方图: Histogram


1. Prometheus Metric封装


基于上面的分析,我们这里实现了三种常见的Metric信息上报,这里提供一个统一的封装类,用于获取对应的Metric类型


package com.git.hui.boot.prometheus.interceptor;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import io.prometheus.client.Histogram;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * @author yihui
 * @date 2021/11/09
 */
@Component
public class PrometheusComponent implements ApplicationContextAware {
    private static PrometheusComponent instance;
    /**
     * 请求总数
     */
    private Counter reqCounter;
    /**
     * 正在请求的http数量
     */
    private Gauge duringReqGauge;
    /**
     * 直方图,请求分布情况
     */
    private Histogram reqLatencyHistogram;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        instance = this;
        CollectorRegistry collectorRegistry = applicationContext.getBean(CollectorRegistry.class);
        // 这里指定SpringBoot容器的CollectorRegistry,如果使用默认的会导致无法收集
        reqCounter = Counter.build().name("demo_rest_req_total").labelNames("path", "method", "code")
                .help("总的请求计数").register(collectorRegistry);
        duringReqGauge = Gauge.build()
                .name("demo_rest_inprogress_req").labelNames("path", "method")
                .help("正在处理的请求数").register(collectorRegistry);
        reqLatencyHistogram = Histogram.build().labelNames("path", "method", "code")
                .name("demo_rest_requests_latency_seconds_histogram").help("请求耗时分布")
                .register(collectorRegistry);
    }
    public static PrometheusComponent getInstance() {
        return instance;
    }
    public Counter counter() {
        return reqCounter;
    }
    public Gauge gauge() {
        return duringReqGauge;
    }
    public Histogram histogram() {
        return reqLatencyHistogram;
    }
}
复制代码


注意上面的setApplicationContext()的方法实现逻辑,其中在创建Counter/Gauge/Histogram时,使用的是simpleclient包中提供的最基础的用法,并不是micrometer的封装方式,后面一篇博文会介绍到两种的差异性


上面实现的特点在于,创建Metric时,就已经定义好了label标签,这里定义了


  • path: 请求url路径
  • method: http方法, get/post
  • code: 状态码,表示请求成功还是异常


2. 拦截器实现自定义信息采集上报


接下来我们实现一个自定义的拦截器,拦截所有的http请求,然后上报关键信息

public class PrometheusInterceptor extends HandlerInterceptorAdapter {
    private ThreadLocal<Histogram.Timer> timerThreadLocal = new ThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 正在处理的请求量
        PrometheusComponent.getInstance().gauge().labels(request.getRequestURI(), request.getMethod()).inc();
        timerThreadLocal.set(PrometheusComponent.getInstance().histogram()
                .labels(request.getRequestURI(), request.getMethod(), String.valueOf(response.getStatus()))
                .startTimer());
        return super.preHandle(request, response, handler);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        int status = response.getStatus();
        // count 请求计数,标签分别为 请求路径,请求方法,response http code
        // 请求应用总量:  sum(demo_rest_req_total)
        // 每秒http请求量: sum(rate(demo_rest_req_total[1m])
        // 请求topk的url:  topk(10, sum(demo_rest_req_total) by (path))
        PrometheusComponent.getInstance().counter().labels(uri, method, String.valueOf(status)).inc();
        // 请求完毕,计数器-1
        PrometheusComponent.getInstance().gauge().labels(uri, method).dec();
        // 直方图统计
        Histogram.Timer timer = timerThreadLocal.get();
        if (timer != null) {
            timer.observeDuration();
            timerThreadLocal.remove();
        }
        super.afterCompletion(request, response, handler, ex);
    }
}
复制代码


对于拦截器的知识点这里不进行展开,有兴趣的小伙伴可以查看 SpringBoot系列Web篇之拦截器Interceptor使用姿势介绍


这里我们主要关心的就两点


  • 执行之前(preHandle): gauge计数+1,开始计时
  • 执行之后 (afterCompletion): guage计数-1,counter计数+1,计时收集


3. 测试


最后我们需要注册上面的拦截器,并写个demo进行测试一下

@RestController
@SpringBootApplication
public class Application implements WebMvcConfigurer {
    private Random random = new Random();
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PrometheusInterceptor()).addPathPatterns("/**");
    }
    @GetMapping(path = "hello")
    public String hello(String name) {
        int sleep = random.nextInt(200);
        try {
            Thread.sleep(sleep);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello sleep: " + sleep + " for " + name;
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
    @Bean
    MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${spring.application.name}") String applicationName) {
        return (registry) -> registry.config().commonTags("application", applicationName);
    }
}
复制代码


应用启动之后,访问几次hello的http接口,然后在查看一下metric信息,看是否有我们刚才上报的数据


image.png


4. 小结


这一篇博文算是上一篇的补全,若我们希望自定义上报一些信息,可以使用上面这种方式来支持


当然,上报并不代表结束,接下来配置大盘等信息也非常的关键,特别是直方图如何配置Grafana?怎么查看请求的耗时分布情况,就由下文来介绍了



相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
相关文章
|
4月前
|
Prometheus 监控 Cloud Native
自定义grafana_table(数据源Prometheus)
综上所述,自定义 Grafana 表格并将 Prometheus 作为数据源的关键是理解 PromQL 的查询机制、熟悉 Grafana 面板的配置选项,并利用 Grafana 强大的转换和自定义功能使数据展示更为直观和有洞见性。随着对这些工具更深入的了解,您将可以创建出更高级的监控仪表盘,以支持复杂的业务监控需求。
340 1
|
4月前
|
Prometheus 监控 Cloud Native
Spring Boot 性能护航!Prometheus、Grafana、ELK 组合拳,点燃数字化时代应用稳定之火
【8月更文挑战第29天】在现代软件开发中,保证应用性能与稳定至关重要。Spring Boot 作为流行的 Java 框架,结合 Prometheus、Grafana 和 ELK 可显著提升监控与分析能力。Prometheus 负责收集时间序列数据,Grafana 将数据可视化,而 ELK (Elasticsearch、Logstash、Kibana)则管理并分析应用日志。通过具体实例演示了如何在 Spring Boot 应用中集成这些工具:配置 Prometheus 获取度量信息、Grafana 显示结果及 ELK 分析日志,从而帮助开发者快速定位问题,确保应用稳定高效运行。
116 1
|
5月前
|
Prometheus 监控 Cloud Native
使用Spring Boot和Prometheus进行监控
使用Spring Boot和Prometheus进行监控
|
6月前
|
Prometheus 监控 Cloud Native
性能监控神器Prometheus、Grafana、ELK 在springboot中的运用
【6月更文挑战第27天】在 Spring Boot 应用中,监控和日志管理是确保系统稳定性和性能的重要手段。
381 4
|
6月前
|
Prometheus Cloud Native Java
springboot集成prometheus异常处理
springboot集成prometheus异常处理
84 2
|
6月前
|
Prometheus 监控 Cloud Native
SpringBoot2.x整合Prometheus+Grafana【附源码】
SpringBoot2.x整合Prometheus+Grafana【附源码】
109 1
|
1月前
|
Prometheus 运维 监控
智能运维实战:Prometheus与Grafana的监控与告警体系
【10月更文挑战第26天】Prometheus与Grafana是智能运维中的强大组合,前者是开源的系统监控和警报工具,后者是数据可视化平台。Prometheus具备时间序列数据库、多维数据模型、PromQL查询语言等特性,而Grafana支持多数据源、丰富的可视化选项和告警功能。两者结合可实现实时监控、灵活告警和高度定制化的仪表板,广泛应用于服务器、应用和数据库的监控。
182 3
|
4月前
|
Prometheus 监控 Cloud Native
【监控】prometheus传统环境监控告警常用配置
【监控】prometheus传统环境监控告警常用配置
【监控】prometheus传统环境监控告警常用配置
|
14天前
|
存储 Prometheus 监控
监控堆外第三方监控工具Prometheus
监控堆外第三方监控工具Prometheus
33 3
|
17天前
|
存储 Prometheus 运维
在云原生环境中,阿里云ARMS与Prometheus的集成提供了强大的应用实时监控解决方案
在云原生环境中,阿里云ARMS与Prometheus的集成提供了强大的应用实时监控解决方案。该集成结合了ARMS的基础设施监控能力和Prometheus的灵活配置及社区支持,实现了全面、精准的系统状态、性能和错误监控,提升了应用的稳定性和管理效率。通过统一的数据视图和高级查询功能,帮助企业有效应对云原生挑战,促进业务的持续发展。
25 3