Springboot应用整合Prometheus+Grafana进行自定义指标监控

Springboot应用整合Prometheus+Grafana进行自定义指标监控

最近需要监控接口的请求数据P90,P99,平均耗时,接口参数包含userId的接口请求数据等等

第一步 创建一个springboot项目

pom文件

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>
    <!--aop -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <!--actuator -->
    <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>
    <!--prometheus -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
        <scope>runtime</scope>
    </dependency>   

springboot的actuator可以很好的配合prometheus实现项目的监控,所以这里使用actuator来进行配合

配置信息

spring.application.name="prometheus-test" //建议写上
management.endpoint.metrics.enabled=true //支持metrics
management.endpoints.web.exposure.include=* //开放端口
management.endpoint.prometheus.enabled=true //支持prometheus
management.metrics.export.prometheus.enabled=true

切面实现prometheus自定义监控指标

监控请求数量 ,请求响应时间,请求特定参数

package com.example.prometheus.demo.aspect;

import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class PrometheusMetricsAspect {

    // 切入所有controller包下的请求方法
    @Pointcut("execution(* com.example.prometheus.demo.controller..*.*(..))")
    public void controllerPointcut() {
    }

    @Around("controllerPointcut()")
    public Object MetricsCollector(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String userId = StringUtils.hasText( request.getParameter("userId"))?request.getParameter("userId"):"no userId";
        String appId = StringUtils.hasText( request.getParameter("appId"))?request.getParameter("appId"):"no appId";

        // 获取api url
        String api = request.getServletPath();
        // 获取请求方法
        String method = request.getMethod();
        long timeMillis = System.currentTimeMillis();
        LocalDate now = LocalDate.now();
        String[] tags = new String[10];
        tags[0]="api";
        tags[1] = api;
        tags[2]="method";
        tags[3]=method;
        tags[4]="day";
        tags[5]=now.toString();
        tags[6]="appId";
        tags[7]=appId;
        tags[8]="userId";
        tags[9]=userId;
        // 请求次数加1
        //自定义的指标名称:http_request_test_all,指标包含数据
        Metrics.counter("http_request_test_all",tags).increment();
        Object object;
        try {
            object = joinPoint.proceed();
        } catch (Exception e) {
            // 请求失败次数加1
            Metrics.counter("http_request_test_error",tags).increment();
            throw e;
        } finally {
            long f = System.currentTimeMillis();
            long l = f - timeMillis;
            //记录请求响应时间
           Metrics.timer("http_request_test_time", tags).record(l, TimeUnit.MILLISECONDS);
        }
        return object;
    }
}

创建测试用的接口

package com.example.prometheus.demo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("test")
public class TestController {

    @GetMapping("/user")
    public String getInfo(@RequestParam String userId ){
        log.info("userId:{}",userId);
        return "123";
    }

    @GetMapping("/app")
    public String getAppInfo(@RequestParam String appId ){
        log.info("appId:{}",appId);
        return "123456";
    }

    @GetMapping("/user/app")
    public String getUserAppInfo(@RequestParam String appId ,@RequestParam String userId ){
        log.info("appId:{}",appId);
        log.info("userId:{}",userId);
        return "abc";
    }
}

启动项目 进行测试查看监控数据是否生效

启动项目 首先访问 ip+port/actuator/prometheus 出现以下数据则表示prometheus正确启动当中

image.png

访问一下测试接口:127.0.0.1:8080/test/user?userId=2143,然后刷新/actuator/prometheus接口看看数据

image.png

可以看到我们自定义的指标:http_request_test_all 和指标里面我们定义的数据信息,同时需要注意的是我们在统计请求次数的时候,这里会自动将我们的指标加上后缀:_total 所以我们后续使用grafana查询的时候也要加上这个后缀。

PS: 可能版本不一样,我在看资料上发现有些后缀是:_count,所以具体是什么需要通过/actuator/prometheus接口查看。

Windows下安装Prometheus

prometheus官网: https://prometheus.io/download/ 有windows版本的,直接下载安装即可,prometheus启动时会自动加载同目录下的Prometheus.yml文件,如果需要监听上面的springboot项目,需要在配置文件当中进行添加

scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus-test"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    metrics_path: /actuator/prometheus
    static_configs:
      - targets: ["localhost:8080"]

其中 prometheus 是默认都有的,下面的prometheus-test是我监听的springboot项目,然后需要配置metrics_path:/actuator/prometheus 这样才能正确获取到springboot应用的信息。

PS: https://www.cnblogs.com/liujiliang/p/10080849.html 这篇文章讲解了prometheus的配置文件。

PS:prometheus默认端口是9090,如需修改需要在启动时添加参数,尝试过在配置文件当中添加,并不成功

PS: windows在双击prometheus.exe后可能出现无法运行的情况,说的是什么windows版本兼容性,防火墙拦截了什么的,网上自行百度下解决方案,我是直接换的电脑。

PS: prometheus有自己的数据查询语法:PromQL 一些复杂的需要自行百度学习

image.png

登录可视化界面在搜索当中输入up 然后点击execute可以看到当前监控的job状态 1表示监控当中,0表示监控信息获取失败

Windows下安装Grafana

grafana官网:https://grafana.com/grafana/download?pg=get&plcmt=selfmanaged-box1-cta1&platform=windows

有windows版本,可以直接下载安装即可,默认端口是3000,默认账号密码是admin

登陆后直接在设置里面的Data Sourecs管理添加Prometheus数据源:输入数据源地址保存即可

image.png

使用grafana展示数据

点击添加,然后创建面板,然后添加panel

image.png

image.png

1 输入PromQL查询语句

2 设置展示数据的名称

3 设置数据展示的图表:直方图,折线图,饼图等

4 设置图表名称

当设置好之后点击run query即可出现数据。

grafana是一个功能非常强大的数据可视化软件,使用教程也是需要仔细学习一下。

Springboot应用开启P90,P99统计

默认是没有开启P90和P99统计的需要在代码当中进行配置

package com.example.prometheus.demo.config;

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
@Slf4j
public class MicrometerConfig {

    @Bean
    MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> {
            registry.config().meterFilter(
                    new MeterFilter() {
                        @Override
                        public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
				//匹配http开头并且是timer类型的监控指标
                            if (id.getType() == Meter.Type.TIMER & id.getName().matches("^(http){1}.*")) {
                                return DistributionStatisticConfig.builder()
                                        .percentilesHistogram(true)
                                        .percentiles(0.5, 0.90, 0.95, 0.99)
                                        .serviceLevelObjectives(Duration.ofMillis(50).toNanos(),
                                                Duration.ofMillis(100).toNanos(),
                                                Duration.ofMillis(200).toNanos(),
                                                Duration.ofSeconds(1).toNanos(),
                                                Duration.ofSeconds(5).toNanos())
                                        .minimumExpectedValue(Duration.ofMillis(1).toNanos())
                                        .maximumExpectedValue(Duration.ofSeconds(5).toNanos())
                                        .build()
                                        .merge(config);
                            } else {
                                return config;
                            }
                        }
                    });
        };
    }
}

然后记录请求响应时间

	 //记录请求响应时间
           Metrics.timer("http_request_test_time", tags).record(l, TimeUnit.MILLISECONDS);

发起请求后会在/actuator/prometheus看到相应的信息

image.png

统计PromQL

每分钟请求总数

60*sum(rate(http_request_test_all_total{}[1m]))

统计自定义标签api=/test/user

60*sum(rate(http_request_test_all_total{api="/test/user"}[1m]))

请求平均耗时

(sum(http_request_test_time_seconds)/sum(http_request_test_all_total))

P90 P99指标统计

avg(http_request_test_time_seconds{job="prometheus-test" ,quantile =~ "0.9|0.99"}) by (job,quantile)

最大耗时

max(http_request_test_time_seconds_max{job="prometheus-test"})


标题:Springboot应用整合Prometheus+Grafana进行自定义指标监控
作者:hjljy
地址:https://www.hjljy.cn/articles/2022/05/09/1652075818581.html

评论

取消