0
点赞
收藏
分享

微信扫一扫

Java自定义metric

单调先生 2022-05-29 阅读 175

1.环境

framework-bom 1.7.5
jdk 1.8
io.micrometer 1.5.4
org.aspectj

pom依赖(最外层pom.xml中内容)

<parent>
<groupId>com.yupaopao.frameworkgroupId>
<artifactId>framework-bomartifactId>
<version>1.7.5version>
parent>



<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-coreartifactId>
<version>1.5.4version>
dependency>

<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-registry-prometheusartifactId>
<version>1.5.4version>
dependency>



<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>

2.项目结构介绍

Java自定义metric_spring


Java自定义metric_ide_02


Java自定义metric_ide_03

3.项目程序介绍

3.1配置文件

没有使用appolo,使用下面的配置

application.properties

spring.application.name需要设置为cmdb中的应用名

server.port=8080
spring.application.name=order-service-prometheus
#对于 Prometheus 来说,Spring Boot Actuator 会自动配置一个 URL 为 /actuator/Prometheus 的 HTTP 服务来供 Prometheus 抓取数据。
#不过该 Actuator 服务默认是关闭的,需要通过 Spring Boot 的配置打开。
management.endpoints.web.exposure.include= info,health,env,mappings,prometheus
management.metrics.tags.application=${spring.application.name}

这里端口为8080,则指标访问地址为​​http://localhost:8080/actuator/prometheus​​

使用appolo,配置如下

Java自定义metric_java_04

由于这里配置端口为54321,则指标访问地址为​​http://localhost:54321/actuator/prometheus​​

3.2各类型指标demo

入口类

/**
* @author tanglonghao
*/
@EnableApolloConfig
@SpringBootApplication(scanBasePackages = "com.yupaopao.ops")
@DubboComponentScan(value = "com.yupaopao.ops")
public class JavaDemoWebApplication {
public static void main(String[] args) {
SpringApplication.run(JavaDemoWebApplication.class, args);
}
//在启动主类中添加Bean ,此配置是监控 jvm 的,可选项
@Bean
MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${spring.application.name}") String applicationName){
// Common tags可以被定义在registry级别,并且会被添加到每个监控系统的报告中
return registry -> registry.config().commonTags("application",applicationName);
}

}

Metrics.java

package com.yupaopao.ops.prometheus.prometheusMetric.metric;

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

@Component
public class Metrics implements MeterBinder {
private Counter counterOne;
private Counter counterTwo;
private AtomicInteger gaugeOne;
private DistributionSummary summaryOne;
private DistributionSummary summaryTwo;
private DistributionSummary histogramOne;


public Counter getCounterOne() {
return counterOne;
}

public Counter getCounterTwo() {
return counterTwo;
}

public AtomicInteger getGaugeOne() {
return gaugeOne;
}

public DistributionSummary getSummaryOne() {
return summaryOne;
}

public DistributionSummary getSummarTwo() {
return summaryTwo;
}

public DistributionSummary getHistogramOne() {
return histogramOne;
}

@Override
public void bindTo(MeterRegistry registry) {
//counter
//Counter接口允许以固定的数值递增,该数值必须为正数。
this.counterOne = Counter.builder("counter.one").tags(new String[]{"method","get","url","/rules"}).description("This is the one counter").register(registry);
this.counterTwo = (Counter) registry.counter("counter.two", "method","get","url","/rules");

// gauge
this.gaugeOne = registry.gauge("gauge.one", Tags.concat(Tags.empty(),"method","get","url","/rules"),new AtomicInteger(0));

//summary
this.summaryOne = registry.summary("summary.one","method","get","url","/rules");

this.summaryTwo = DistributionSummary.builder("summary.two")
.description("simple distribution summary").tags("method","get","url","/rules")
.publishPercentiles(0.5, 0.75, 0.9)
.register(registry);

System.out.println(this.summaryTwo.takeSnapshot());

// timer
// 实际是gauge类型 和summary
// 方法 record() 使用 Timer 对象的 record() 方法来记录一个 Runnable 对象的运行时间
Timer timer = registry.timer("timer.simple.one","method","get","url","/rules");
timer.record(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});

Timer.Sample sample = Timer.start();
new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
sample.stop(registry.timer("timer.sample","method","get","url","/rules"));
}).start();

//histogram
this.histogramOne = DistributionSummary.builder("histogram.one")
.scale(1).tags(Tags.concat(Tags.empty(),"method","get","url","/rules")).serviceLevelObjectives(70,80,90)
.register(registry);

}
}

PrometheusServiceImpl.java

package com.yupaopao.ops.service.impl;

import com.yupaopao.ops.prometheus.prometheusMetric.metric.Metrics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yupaopao.ops.service.PrometheusService;
import java.util.Random;

@Service
public class PrometheusServiceImpl implements PrometheusService {
@Autowired
private Metrics metrics;

@Override
public String prometheusTest1() {
try{
Thread.sleep(2000);
}catch (Exception e){
System.out.println(e);
}

return "prometheusTest1";
}

@Override
public String prometheusTest2() {
return "prometheusTest2";
}

@Override
public String metric() {
metrics.getCounterOne().increment();
metrics.getCounterTwo().increment();

int num = (int) (Math.random() * 3);
System.out.println("gauge value---------"+num);
metrics.getGaugeOne().set(num);

metrics.getSummaryOne().record(300);

metrics.getSummarTwo().record(20);
metrics.getSummarTwo().record(30);
metrics.getSummarTwo().record(40);
metrics.getSummarTwo().record(50);

metrics.getHistogramOne().record(30);
metrics.getHistogramOne().record(40);
metrics.getHistogramOne().record(90);
return "metric";
}
}

PrometheusController.java

package com.yupaopao.ops.web.controller;

import com.yupaopao.ops.service.PrometheusService;
import com.yupaopao.ops.service.PrometheusService2;
import com.yupaopao.ops.web.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = {"/prometheus"})
public class PrometheusController {
@Autowired
private PrometheusService prometheusService;

@GetMapping("/prometheusTest1")
public Result prometheusTest1() {
return Result.success(prometheusService.prometheusTest1());
}
@GetMapping("/prometheusTest2")
public Result prometheusTest2() {
return Result.success(prometheusService.prometheusTest2());
}

@RequestMapping("/metrics")
public Result metrics(){
return Result.success(prometheusService.metric());
}

}

访问一下​​http://localhost:8080/prometheus/metric​​ 或 ​​http://localhost:54321/prometheus/metric​​

然后访问:​​http://localhost:8080/actuator/prometheus​​  或 ​​http://localhost:54321/actuator/prometheus​​ 

就能看到指标数值

...

# HELP counter_one_total This is the one counter
# TYPE counter_one_total counter
counter_one_total{application="app1",method="get",url="/rules",} 1.0
# HELP counter_two_total
# TYPE counter_two_total counter
counter_two_total{application="app1",method="get",url="/rules",} 1.0

# HELP gauge_one
# TYPE gauge_one gauge
gauge_one{application="app1",method="get",url="/rules",} 2000.0

# HELP summary_one_max
# TYPE summary_one_max gauge
summary_one_max{application="app1",method="get",url="/rules",} 300.0
# HELP summary_one
# TYPE summary_one summary
summary_one_count{application="app1",method="get",url="/rules",} 1.0
summary_one_sum{application="app1",method="get",url="/rules",} 300.0

# HELP summary_two_max simple distribution summary
# TYPE summary_two_max gauge
summary_two_max{application="app1",method="get",url="/rules",} 50.0
# HELP summary_two simple distribution summary
# TYPE summary_two summary
summary_two{application="app1",method="get",url="/rules",quantile="0.5",} 30.0
summary_two{application="app1",method="get",url="/rules",quantile="0.75",} 41.0
summary_two{application="app1",method="get",url="/rules",quantile="0.9",} 51.0
summary_two_count{application="app1",method="get",url="/rules",} 4.0
summary_two_sum{application="app1",method="get",url="/rules",} 140.0

# HELP histogram_one_max
# TYPE histogram_one_max gauge
histogram_one_max{application="app1",method="get",url="/rules",} 90.0
# HELP histogram_one
# TYPE histogram_one histogram
histogram_one_bucket{application="app1",method="get",url="/rules",le="70.0",} 2.0
histogram_one_bucket{application="app1",method="get",url="/rules",le="80.0",} 2.0
histogram_one_bucket{application="app1",method="get",url="/rules",le="90.0",} 3.0
histogram_one_bucket{application="app1",method="get",url="/rules",le="+Inf",} 3.0
histogram_one_count{application="app1",method="get",url="/rules",} 3.0
histogram_one_sum{application="app1",method="get",url="/rules",} 160.0

# HELP timer_simple_one_seconds_max
# TYPE timer_simple_one_seconds_max gauge
timer_simple_one_seconds_max{application="app1",method="get",url="/rules",} 2.00453292
# HELP timer_simple_one_seconds
# TYPE timer_simple_one_seconds summary
timer_simple_one_seconds_count{application="app1",method="get",url="/rules",} 1.0
timer_simple_one_seconds_sum{application="app1",method="get",url="/rules",} 2.00453292

3.3监控QPS与请求耗时(统计每个应用的请求次数和每个请求的请求耗时)

这里使用切面编程的方式,监控的是service.impl下的类,这样主要是为了即监控http请求,也监控 dubbo请求

当然也可使用别的方式,大佬们随意发挥!!!

AspectAop.java

package com.yupaopao.ops.prometheus.prometheusMetric.aop;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@Aspect
public class AspectAop {
@Autowired
MeterRegistry registry;

private Counter counter_total;
private AtomicInteger request_time;
private String packageName;

ThreadLocal<Long> startTime = new ThreadLocal<>();

@Pointcut("execution(public * com.yupaopao.ops.service.impl.*.*(..))")
private void pointCut() {
}

@PostConstruct
public void init() {

}

@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String packageName = joinPoint.getSignature().getDeclaringType().getName();
this.packageName = packageName;
// 请求次数使用的是counter类型
counter_total = registry.counter("bixin_app_requests_count");
startTime.set(System.currentTimeMillis());
counter_total.increment();
System.out.println("app_requests_count +1");
}

@AfterReturning(returning = "methodName", pointcut = "pointCut()")
public void doAftereReturning(Object methodName) {
// 这里是毫秒
Long requestTime = System.currentTimeMillis() - startTime.get();
// 请求耗时使用的是gauge类型
this.request_time = registry.gauge("bixin_app_request_time", Tags.concat(Tags.empty(),"packageName",packageName,"methodName", methodName.toString()),new AtomicInteger(requestTime.intValue()));
System.out.println(this.packageName+"---"+methodName+"---------------");
System.out.println("请求执行时间----:" + requestTime.intValue());
}
}


请求​​http://127.0.0.1:8080/prometheus/prometheusTest1​​

查看指标​​http://127.0.0.1:54321/actuator/prometheus​​

# HELP bixin_app_request_time  
# TYPE bixin_app_request_time gauge
bixin_app_request_time{application="java-demo",methodName="prometheusTest1",packageName="com.yupaopao.ops.service.impl.PrometheusServiceImpl",} 2008.0

# HELP bixin_app_requests_count_total
# TYPE bixin_app_requests_count_total counter
bixin_app_requests_count_total{application="java-demo",} 1.0

prometheus中QPS计算公式  sum(rate(bixin_app_requests_count_total{job="java-demo"}[5m]))


4.官网

官网http://micrometer.io/docs/concepts


举报

相关推荐

0 条评论