首页 > 其他分享 >Spring Boot如何自定义监控指标

Spring Boot如何自定义监控指标

时间:2023-06-02 11:02:43浏览次数:35  
标签:自定义 Spring Boot request springframework amount import org annotation


1.创建项目

pom.xml引入相关依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.olive</groupId>
 <artifactId>prometheus-meter-demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.7.RELEASE</version>
  <relativePath />
 </parent>
 <properties>
  <java.version>1.8</java.version>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
 </properties>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
  <!-- Micrometer Prometheus registry  -->
  <dependency>
   <groupId>io.micrometer</groupId>
   <artifactId>micrometer-registry-prometheus</artifactId>
  </dependency>
 </dependencies>
 <dependencyManagement>
  <dependencies>
   <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>${spring-boot.version}</version>
    <type>pom</type>
    <scope>import</scope>
   </dependency>
  </dependencies>
 </dependencyManagement>
</project>

2.自定义指标

  • 方式一

直接使用micrometer核心包的类进行指标定义和注册

package com.olive.monitor;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.MeterRegistry;

@Component
public class NativeMetricsMontior {

 /**
  * 支付次数
  */
 private Counter payCount;

 /**
  * 支付金额统计
  */
 private DistributionSummary payAmountSum;

 @Autowired
 private MeterRegistry registry;

 @PostConstruct
 private void init() {
  payCount = registry.counter("pay_request_count", "payCount", "pay-count");
  payAmountSum = registry.summary("pay_amount_sum", "payAmountSum", "pay-amount-sum");
 }

 public Counter getPayCount() {
  return payCount;
 }

 public DistributionSummary getPayAmountSum() {
  return payAmountSum;
 }

}
  • 方式二

通过引入micrometer-registry-prometheus包,该包结合prometheus,对micrometer进行了封装

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

同样定义两个metrics

package com.olive.monitor;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Counter;

@Component
public class PrometheusMetricsMonitor {

 /**
  * 订单发起次数
  */
 private Counter orderCount;

 /**
  * 金额统计
  */
 private Counter orderAmountSum;
 
 @Autowired
 private CollectorRegistry registry;
 
 
 @PostConstruct
 private void init() {
  orderCount = Counter.build().name("order_request_count")
    .help("order request count.")
    .labelNames("orderCount")
    .register();
  orderAmountSum = Counter.build().name("order_amount_sum")
    .help("order amount sum.")
    .labelNames("orderAmountSum")
    .register();
  registry.register(orderCount);
  registry.register(orderAmountSum);
 }

 public Counter getOrderCount() {
  return orderCount;
 }

 public Counter getOrderAmountSum() {
  return orderAmountSum;
 }

}

prometheus 4种常用Metrics

Counter

连续增加不会减少的计数器,可以用于记录只增不减的类型,例如:网站访问人数,系统运行时间等。

对于Counter类型的指标,只包含一个inc()的方法,就是用于计数器+1.

一般而言,Counter类型的metric指标在冥冥中我们使用_total结束,如http_requests_total.

Gauge

可增可减的仪表盘,曲线图

对于这类可增可减的指标,用于反应应用的当前状态。

例如在监控主机时,主机当前空闲的内存大小,可用内存大小等等。

对于Gauge指标的对象则包含两个主要的方法inc()和dec(),用于增加和减少计数。

Histogram

主要用来统计数据的分布情况,这是一种特殊的metrics数据类型,代表的是一种近似的百分比估算数值,统计所有离散的指标数据在各个取值区段内的次数。例如:我们想统计一段时间内http请求响应小于0.005秒、小于0.01秒、小于0.025秒的数据分布情况。那么使用Histogram采集每一次http请求的时间,同时设置bucket。

Summary

Summary和Histogram非常相似,都可以统计事件发生的次数或者大小,以及其分布情况,他们都提供了对时间的计数_count以及值的汇总_sum,也都提供了可以计算统计样本分布情况的功能,不同之处在于Histogram可以通过histogram_quantile函数在服务器计算分位数。而Sumamry的分位数则是直接在客户端进行定义的。因此对于分位数的计算,Summary在通过PromQL进行查询的时候有更好的性能表现,而Histogram则会消耗更多的资源,但是相对于客户端而言Histogram消耗的资源就更少。用哪个都行,根据实际场景自由调整即可。

3. 测试

定义两个controller分别使用NativeMetricsMontiorPrometheusMetricsMonitor

package com.olive.controller;

import java.util.Random;

import javax.annotation.Resource;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.olive.monitor.NativeMetricsMontior;

@RestController
public class PayController {

 @Resource
 private NativeMetricsMontior monitor;

 @RequestMapping("/pay")
 public String pay(@RequestParam("amount") Double amount) throws Exception {
  // 统计支付次数
  monitor.getPayCount().increment();

  Random random = new Random();
  //int amount = random.nextInt(100);
  if(amount==null) {
   amount = 0.0;
  }
  // 统计支付总金额
  monitor.getPayAmountSum().record(amount);
  return "支付成功, 支付金额: " + amount;
 }

}
package com.olive.controller;

import java.util.Random;

import javax.annotation.Resource;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.olive.monitor.PrometheusMetricsMonitor;

@RestController
public class OrderController {

 @Resource
 private PrometheusMetricsMonitor monitor;

 @RequestMapping("/order")
 public String order(@RequestParam("amount") Double amount) throws Exception {
  // 订单总数
  monitor.getOrderCount()
   .labels("orderCount")
   .inc();

  Random random = new Random();
  //int amount = random.nextInt(100);
  if(amount==null) {
   amount = 0.0;
  }
  // 统计订单总金额
  monitor.getOrderAmountSum()
   .labels("orderAmountSum")
   .inc(amount);
  return "下单成功, 订单金额: " + amount;
 }

}

启动服务

访问http://127.0.0.1:9595/actuator/prometheus;正常看到监测数据



Spring Boot如何自定义监控指标_maven

改变amount多次方式http://127.0.0.1:8080/order?amount=100http://127.0.0.1:8080/pay?amount=10后;再访问http://127.0.0.1:9595/actuator/prometheus。查看监控数据



Spring Boot如何自定义监控指标_maven_02

4.项目中的应用

项目中按照上面说的方式进行数据埋点监控不太现实;在spring项目中基本通过AOP进行埋点监测。比如写一个切面Aspect;这样的方式就非常友好。能在入口就做了数据埋点监测,无须在controller里进行代码编写。

package com.olive.aspect;

import java.time.LocalDate;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

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 io.micrometer.core.instrument.Metrics;

@Aspect
@Component
public class PrometheusMetricsAspect {

    // 切入所有controller包下的请求方法
    @Pointcut("execution(* com.olive.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";
        
        // 获取api url
        String api = request.getServletPath();
        // 获取请求方法
        String method = request.getMethod();
        long startTs = 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] = "userId";
        tags[7] = userId;
        
        String amount = StringUtils.hasText(request.getParameter("amount")) ? 
          request.getParameter("amount") : "0.0";
        
        tags[8] = "amount";
        tags[9] = amount;
        // 请求次数加1
        //自定义的指标名称:custom_http_request_all,指标包含数据
        Metrics.counter("custom_http_request_all", tags).increment();
        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Exception e) {
            //请求失败次数加1
            Metrics.counter("custom_http_request_error", tags).increment();
            throw e;
        } finally {
            long endTs = System.currentTimeMillis() - startTs;
            //记录请求响应时间
           Metrics.timer("custom_http_request_time", tags).record(endTs, TimeUnit.MILLISECONDS);
        }
        return object;
    }
}

编写好切面后,重启服务;访问controller的接口,同样可以进行自定义监控指标埋点



Spring Boot如何自定义监控指标_maven_03


标签:自定义,Spring,Boot,request,springframework,amount,import,org,annotation
From: https://blog.51cto.com/u_13538361/6400809

相关文章

  • maven创建web项目(springboot)
    创建一个Java项目和创建一个Web项目在IntelliJIDEA中有一些区别。创建Java项目:选择"Java"选项,并选择适当的JDK版本。创建的是一个普通的Java项目,用于编写Java类、库和应用程序。没有默认的Web相关依赖和配置。创建Web项目:选择"JavaEnterprise"选......
  • spinner自定义[转]
    转自:https://www.jianshu.com/p/7b03ade29091spinner_drop_down_shape的代码<?xmlversion="1.0"encoding="utf-8"?><layer-listxmlns:android="http://schemas.android.com/apk/res/android"><item><shap......
  • Vue-自定义icon实现
    在项目中引入了element-ui之后,发现其内置的icon有限,无法满足项目的需求,因此需自定义icon来实现需求。在vue项目的components下新建SvgIcon目录,在SvgIcon目录下新建index.vue插入代码:<template><svgclass="svg-icon"aria-hidden="true"><use:xlink:href="ic......
  • props自定义属性
    props含义props是组件的自定义属性,在封装通用组件的时候,合理的使用props可以极大地提高组件的复用性。注意:全局组件在main.js里注册;使用者中标签直接调用(注意v-bind);组件里注意props的只读性。method单行代码简写仅单行能这么写<template><div> <button@click="add">+1<......
  • Jasypt加密SpringBoot配置文件和自动加密数据库敏感信息
    Jasypt是开源的加密和解密的组件。和Spring提供了很好的集成。一、加密SpringBoot配置文件 新建SpringBoot项目,添加依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>......
  • springboot 上传文件
    1、html代码:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title></head><body><formaction="/upload"method="post"enctype=&qu......
  • springboot 拦截器配置
      创建目录 interceptor——MyInterceptor.java文件,该文件实现 HandlerInterceptor接口 MyInterceptor.java文件实现 HandlerInterceptor接口代码如下: 代码案例:(已验证cookie为案列)importorg.springframework.beans.factory.annotation.Value;importorg.springframework.......
  • VsCode开发 Java Maven Springboot
    安装java相关的扩展插件在VisualStudioCode中打开扩展(Ctrl+Shift+X),输入关键词java、spring分别下载Java开发插件包和springboot插件包 配置参数点击设置按钮,进入设置选项,配置用户设置(文件->首选项->设置  Ctrl+,)添加如下代码:"java.errors.incompleteClasspath.severity......
  • springboot 中配置Swagger2
     1.引入依赖<!--swagger2依赖--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency......
  • springMVC的controller中获取request,response对象的两个方法
    @GetMapping("outLogin")publicStringoutLogin(){ServletRequestAttributesattributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequestrequest=attributes.getRequest();......