springboot actuator自定义prometheus监控指标
Posted 今夜月色很美
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot actuator自定义prometheus监控指标相关的知识,希望对你有一定的参考价值。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.3.2</version>
</dependency>
工具类HandleUtils
import io.micrometer.core.instrument.ImmutableTag;
import io.micrometer.core.instrument.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
* 操作工具类
*/
public class HandleUtils {
private static final Logger logger = LoggerFactory.getLogger(HandleUtils.class);
/**
* 组装tags
*
* @param tags 扩展tags
* @return tags数组
*/
public static String[] handelTag(List<Tag> tags) {
if(CollectionUtils.isEmpty(tags)){
return new String[0];
}
int size = tags.size() * 2 + 2 ;
String[] tagArray = new String[size];
int i = 0;
for (Tag tag : tags) {
tagArray[++i] = tag.getKey();
tagArray[++i] = tag.getValue();
}
return tagArray;
}
}
counter计数器
import com.iflytek.lingxi.actuator.client.micrometer.constant.MetricsConstants;
import com.iflytek.lingxi.actuator.client.micrometer.utils.HandleUtils;
import com.iflytek.lingxi.actuator.client.micrometer.utils.RegexUtils;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import java.util.List;
/**
* 介绍:
* Counter(计数器) 一个增量为正数的单值计数器
* <p>
* 使用场景:
* Counter的作用是记录XXX的总量或者计数值,适用于一些增长类型的统计,
* 例如下单、支付次数、 Http请求总量记录等等,通过Tag可以区分不同的场景,
* 对于下单,可以使用不同的Tag标记不同的业务来源或者是按日期划分,
* 对于Http请求总量记录,可以使用Tag区分不同的URL
*
*/
public class MetricsCounterService {
/**
* 计数器
*
* @param name 指标名称 (数字字母下划线组合)
*/
public static Counter counter(String name) {
return MetricsCounterService.counter(name, null);
}
/**
* 计数器(可扩展tag)
*
* @param name 指标名称 (数字字母下划线组合)
* @param tags 自定义tag
*/
public static Counter counter(String name, List<Tag> tags) {
// 参数校验
RegexUtils.checkNameAndTag(name);
// 组装tags
String[] tagArray = HandleUtils.handelTag(tags);
return Metrics.counter(MetricsConstants.NAME_PREFIX + name, tagArray);
}
}
gauge仪表盘
import com.iflytek.lingxi.actuator.client.micrometer.constant.MetricsConstants;
import com.iflytek.lingxi.actuator.client.micrometer.utils.RegexUtils;
import io.micrometer.core.instrument.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author lyz
* @Title: CustomMetricsGaugeService
* @Description: 继承MetricsGaugeService添加removeGauge方法
* @date 2021/8/23 9:53
*/
@Slf4j
public class CustomMetricsGaugeService{
private static ConcurrentHashMap<String, Number> cacheMap = new ConcurrentHashMap<String, Number>();
/**
* 仪表
*
* @param name 指标名称 (数字字母下划线组合)
*/
public static <T extends Number> T gauge(String name, T number) {
// 参数校验
return gauge(name, new ArrayList<Tag>(), number);
}
/**
* 非master移除所有监控指标
*/
public static void removeAllMetrics(){
cacheMap.clear();
Metrics.globalRegistry.forEachMeter(item -> {
Metrics.globalRegistry.remove(item);
});
}
/**
* gauge监控指标移除
* @param appid
* @param api
*/
public static void removeGauge(String appid, String api){
Metrics.globalRegistry.forEachMeter(item -> {
String apiTag = item.getId().getTag("api");
String appidTag = item.getId().getTag("appid");
if (StringUtils.isNotBlank(apiTag) && StringUtils.isNotBlank(appidTag) && apiTag.equals(api) && appidTag.equals(appid)){
log.info("删除计量监控指标,api:{},appid:{}", api, appid);
Metrics.globalRegistry.remove(item);
String key = item.getId().getName();
for (Tag tag : item.getId().getTags()) {
key += tag.getKey() + tag.getValue();
}
String baseKey = Base64Utils.encodeToString(key.getBytes());
cacheMap.remove(baseKey);
}
});
}
/**
* 仪表(可扩展tag)
*
* @param name 指标名称 (数字字母下划线组合)
* @param tags 自定义tag
*/
public static <T extends Number> T gauge(String name, List<Tag> tags, T number) {
// 参数校验
RegexUtils.checkNameAndTag(name);
String key = MetricsConstants.NAME_PREFIX + name;
if (!CollectionUtils.isEmpty(tags)) {
for (Tag tag : tags) {
key += tag.getKey() + tag.getValue();
}
}
String baseKey = Base64Utils.encodeToString(key.getBytes());
Number t = cacheMap.get(baseKey);
if (t == null) {
t = (T) Metrics.gauge(MetricsConstants.NAME_PREFIX + name, tags, number);
cacheMap.put(baseKey, t);
} else {
t = ifNaNReSet(name, tags, number, baseKey, t);
}
return (T) t;
}
private static <T extends Number> Number ifNaNReSet(String name, List<Tag> tags, T number, String baseKey, Number t) {
try{
Gauge gauge = Metrics.globalRegistry.get(MetricsConstants.NAME_PREFIX + name).tags(tags).gauge();
boolean isNaN = Double.isNaN(gauge.value());
if (isNaN){
Metrics.globalRegistry.remove(gauge);
t = (T) Metrics.gauge(MetricsConstants.NAME_PREFIX + name, tags, number);
cacheMap.put(baseKey, t);
}
} catch (Exception e){
t = (T) Metrics.gauge(MetricsConstants.NAME_PREFIX + name, tags, number);
}
return t;
}
}
Summary摘要
import com.iflytek.lingxi.actuator.client.micrometer.constant.MetricsConstants;
import com.iflytek.lingxi.actuator.client.micrometer.utils.HandleUtils;
import com.iflytek.lingxi.actuator.client.micrometer.utils.RegexUtils;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import java.util.List;
/**
* 介绍:
* Summary(摘要)用于跟踪事件的分布。
* 它类似于一个计时器,但更一般的情况是,它的大小并不一定是一段时间的测量值。
* 在micrometer中,对应的类是DistributionSummary,它的用法有点像Timer,
* 但是记录的值是需要直接指定,而不是通过测量一个任务的执行时间。
* <p>
* 使用场景:
* 1、记录指定方法的执行时间用于展示。
* 2、记录一些任务的执行时间,从而确定某些数据来源的速率,例如消息队列消息的消费速率等。
*
*/
public class MetricsSummaryService {
/**
* 计时器
*
* @param name 指标名称 (数字字母下划线组合)
* @return Summary对象
*/
public static DistributionSummary summary(String name) {
return MetricsSummaryService.summary(name, null);
}
/**
* 计时器 (可扩展tag)
*
* @param name 指标名称 (数字字母下划线组合)
* @param tags 自定义tag
* @return Summary对象
*/
public static DistributionSummary summary(String name, List<Tag> tags) {
// 参数校验
RegexUtils.checkNameAndTag(name);
// 组装tags
String[] tagArray = HandleUtils.handelTag(tags);
return Metrics.summary(MetricsConstants.NAME_PREFIX + name, tagArray);
}
}
Timer计时器
import com.iflytek.lingxi.actuator.client.micrometer.constant.MetricsConstants;
import com.iflytek.lingxi.actuator.client.micrometer.utils.HandleUtils;
import com.iflytek.lingxi.actuator.client.micrometer.utils.RegexUtils;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import java.util.List;
/**
* 介绍:
* Timer(计时器)同时测量一个特定的代码逻辑块的调用(执行)速度和它的时间分布。
* 简单来说,就是在调用结束的时间点记录整个调用块执行的总时间,适用于测量短时间执行的事件的耗时分布,例如消息队列消息的消费速率。
* <p>
* 使用场景:
* 1、记录指定方法的执行时间用于展示。
* 2、记录一些任务的执行时间,从而确定某些数据来源的速率,例如消息队列消息的消费速率等。
*
*/
public class MetricsTimerService {
/**
* 计时器
*
* @param name 指标名称 (数字字母下划线组合)
* @return Timer对象
*/
public static Timer timer(String name) {
return MetricsTimerService.timer(name, null);
}
/**
* 计时器 (可扩展tag)
*
* @param name 指标名称 (数字字母下划线组合)
* @param tags 自定义tag
* @return Timer对象
*/
public static Timer timer(String name, List<Tag> tags) {
// 参数校验
RegexUtils.checkNameAndTag(name);
// 组装tags
String[] tagArray = HandleUtils.handelTag(tags);
return Metrics.timer(MetricsConstants.NAME_PREFIX + name, tagArray);
}
}
自定义操作
自动注入类PrometheusMetricsExportAutoConfiguration
根据该类源码可以看到,项目启动时已注入CollectorRegistry
@Autowired
private CollectorRegistry collectorRegistry;
public void test(){
Enumeration<Collector.MetricFamilySamples> metricFamilySamplesEnumeration = this.collectorRegistry.metricFamilySamples();
while (metricFamilySamplesEnumeration.hasMoreElements()){
Collector.MetricFamilySamples metricFamilySamples = metricFamilySamplesEnumeration.nextElement();
List<Collector.MetricFamilySamples.Sample> sampleList = metricFamilySamples.samples;
for (Collector.MetricFamilySamples.Sample sample : sampleList) {
if ("xxx".equals(sample.name)){
System.out.println(sample);
}
}
}
}
获取registry
Set<MeterRegistry> registrySet = Metrics.globalRegistry.getRegistries();
for (MeterRegistry meterRegistry : registrySet) {
if (meterRegistry instanceof PrometheusMeterRegistry){
((PrometheusMeterRegistry) meterRegistry).getPrometheusRegistry().unregister(meterRegistry.);
}
}
暴漏监控端点类
PrometheusScrapeEndpoint
以上是关于springboot actuator自定义prometheus监控指标的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot2——指标监控actuator多环境切换Profile和自定义starter
SpringBoot - 构建监控体系02_定义度量指标和 Actuator 端点
SpringBoot2.x系列教程(七十)Spring Boot Actuator集成及自定义Endpoint详解
Spring Boot Actuator Endpoints 安全性不适用于自定义 Spring Security 配置