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;正常看到监测数据

改变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。查看监控数据

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如何自定义监控指标的更多相关文章

  1. 微服务监控之三:Prometheus + Grafana Spring Boot 应用可视化监控

    一.Springboot增加Prometheus 1.Spring Boot 应用暴露监控指标,添加如下依赖 <dependency> <groupId>org.springf ...

  2. 拒绝黑盒应用-Spring Boot 应用可视化监控

    图文简介 逻辑关系 效果演示 快速开始 1.Spring Boot 应用暴露监控指标[版本 1.5.7.RELEASE] 首先,添加依赖如下依赖: <dependency> <gro ...

  3. (转)Spring Boot(二十):使用 spring-boot-admin 对 Spring Boot 服务进行监控

    http://www.ityouknow.com/springboot/2018/02/11/spring-boot-admin.html 上一篇文章<Spring Boot(十九):使用 Sp ...

  4. Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置

    用过 Spring Boot 的小伙伴都知道,我们只需要在项目中引入 spring-boot-starter-web 依赖,SpringMVC 的一整套东西就会自动给我们配置好,但是,真实的项目环境比 ...

  5. Spring Boot Admin2.X监控的服务context-path问题

    在使用Spring Boot Admin进行监控时,如果被监控的服务没有加context-path的话是不会有任何问题的,一旦服务加了context-path的配置,监控就会失败. 下图是正常情况的显 ...

  6. prometheus自定义监控指标——实战

    上一节介绍了pushgateway的作用.优劣以及部署使用,本机通过几个实例来重温一下自定义监控指标是如何使用的. 一.监控容器启动时间(shell) 使用prometheus已经两个月了,但从未找到 ...

  7. spring boot/cloud 应用监控

    应用的监控功能,对于分布式系统非常重要.如果把分布式系统比作整个社会系统.那么各个服务对应社会中具体服务机构,比如银行.学校.超市等,那么监控就类似于警察局和医院,所以其重要性显而易见.这里说的,监控 ...

  8. Spring Boot中自定义注解+AOP实现主备库切换

    摘要: 本篇文章的场景是做调度中心和监控中心时的需求,后端使用TDDL实现分表分库,需求:实现关键业务的查询监控,当用Mybatis查询数据时需要从主库切换到备库或者直接连到备库上查询,从而减小主库的 ...

  9. Spring Boot 2.x监控数据可视化(Actuator + Prometheus + Grafana手把手)

    TIPS 本文基于Spring Boot 2.1.4,理论支持Spring Boot 2.x所有版本 众所周知,Spring Boot有个子项目Spring Boot Actuator,它为应用提供了 ...

  10. spring Boot 学习(八、Spring Boot与与监控管理)

    一.监控管理通过引入spring-boot-starter-actuator,可以使用Spring Boot为我们提供的准 生产环境下的应用监控和管理功能.我们可以通过HTTP,JMX,SSH协议来进 ...

随机推荐

  1. Linux 下的输入输出和重定向示例

    Linux 下的输入输出和重定向示例 作者:Grey 原文地址: 博客园:Linux 下的输入输出和重定向示例 CSDN:Linux 下的输入输出和重定向示例 说明 Linux 下的输入输出有如下三种 ...

  2. 精华推荐 | 【深入浅出RocketMQ原理及实战】「性能原理挖掘系列」透彻剖析贯穿RocketMQ的事务性消息的底层原理并在分析其实际开发场景

    什么是事务消息 事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败.RocketMQ的事务消息提供类似 X/Open ...

  3. 跟光磊学Java-macOS版Java8开发环境搭建(基于Intel x86 64-bit)

    Java语言核心技术   日常办公和软件开发除了可以使用Windows系统以外,还可以使用macOS系统,至于具体使用什么系统取决于你入职公司之后公司给你发的什么电脑,如果是MacBookPro那么就 ...

  4. Linux安装&卸载mysql5.7

    Linux系统下卸载mysql 停止mysql服务 systemctl stop mysqld.service 查看安装的mysql服务 rpm -qa|grep -i mysql 删除安装的mysq ...

  5. [python] 基于blind-watermark库添加图片盲水印

    blind-watermark是一个能够给图片添加/解析基于频域的数字盲水印的Python库.图像水印image watermark是指在图片里添加文本或图形,以标记图片的来源.但是图像水印会破坏原图 ...

  6. [随笔所想] CSDN认证博客专家申请通过随笔所想

    本篇博客写于2020年5月13日晚,为了纪念CSDN博客专家申请通过. 2020年5月10日晚,也就是2020年的母亲节当晚提交了博客专家申请.在2020年5月13日上午,就知道博客专家申请通过啦!前 ...

  7. Codeforces Gym 104059B - Breeding Bugs

    简要题意 Virtual Judge 传送门 | Codeforces Gym 传送门 给出一个长度为 \(n\) 的序列 \(a\),你需要从中选出一些数,使其两两相加不为质数.输出最大可以选择多少 ...

  8. React中实现keepalive组件缓存效果

    背景:由于react官方并没有提供缓存组件相关的api(类似vue中的keepalive),在某些场景,会使得页面交互性变的很差,比如在有搜索条件的表格页面,点击某一条数据跳转到详情页面,再返回表格页 ...

  9. Jest如何有序地执行测试

    项目场景: node环境下编写js库,处于规范性考虑,需要做单元测试,我选择了Jest 问题描述 我的js库需要访问数据库,因此操作都是异步的,而且各个测试单元有严格的先后执行顺序(比如,建表 > ...

  10. C#中检查null的语法糖,非常实用

    c#处理null的几个语法糖,非常实用.(尤其是文末Dictionary那个案例,记得收藏) ??如果左边是的null,那么返回右边的操作数,否则就返回左边的操作数,这个在给变量赋予默认值非常好用. ...