实现原理很简单,主要是基于micrometer包装提供的MeterRegistry bean 进行扩展
项目结构
- maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dalong</groupId>
<artifactId>prome</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>prome</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 项目结构
基于spring 的starter 官网生成
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── dalong
│ │ └── prome
│ │ ├── Login.java
│ │ ├── MyService.java
│ │ └── PromeApplication.java
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
- 代码说明
application.properties,开启prometheus 配置的
management.endpoints.web.exposure.include=prometheus,health,info
management.endpoints.web.base-path=/
MyService.java 一个模拟延迟处理的bean
package com.dalong.prome;
import io.micrometer.core.annotation.Timed;
import org.springframework.stereotype.Service;
import java.util.HashMap;
/**
@author dalong
*/
@Service
public class MyService {
// 注册timed 可以查看服务请求时间的处理,我们可以查看比较慢的请求情况,尤其是异步,而且是长时间运行的调度任务
@Timed(description = "fetch userservice")
public Object fetchUserinfo() throws InterruptedException {
HashMap<String,String> userinfo =new HashMap<>();
userinfo.put("name","demoapp");
userinfo.put("version","v1");
Thread.sleep((long) (1000*Math.random()));
return userinfo;
}
}
PromeApplication.java:入口,注册了一个time的aop bean
package com.dalong.prome;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class PromeApplication {
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
public static void main(String[] args) {
SpringApplication.run(PromeApplication.class, args);
}
}
Login.java 一个service
package com.dalong.prome;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
/**
@author dalong
*/
@RestController
public class Login {
MeterRegistry meterRegistry;
Counter okCounter;
Counter failCounter;
MyService myService;
public Login(MeterRegistry meterRegistry,MyService myService){
this.meterRegistry=meterRegistry;
this.myService=myService;
okCounter = meterRegistry.counter("platform_userlogin_ok", "type", "ok"); // 1 - create a counter
failCounter = Counter.builder("platform_userlogin_fail") // 2 - create a counter using the fluent API
.tag("type", "fail")
.description("The number of fail logins")
.register(meterRegistry);
}
@RequestMapping(value = {"/demoapp"})
@Timed(description = "deoapp")
public Object info() throws InterruptedException {
if (Math.random()*10>1){
// ok
okCounter.increment();
return myService.fetchUserinfo();
}else{
// fail
failCounter.increment();
return myService.fetchUserinfo();
}
}
}
- 运行效果
接口请求
metrics
说明
不太好的地方是默认对于prometheus 包装的MeterRegistry并不如golang 或者其他语言prometheus metrics 定义的那么方便(尤其是label 的处理上)
但是总的来说还都是比较简单的,基于prometheus 灵活的能力,我们可以比较方便的分析业务指标,如果真的需要自定义扩展的metrics 推荐使用
MeterBinder 接口以及Meter进行扩展,以下包含了一个参考例子
参考资料
https://docs.spring.io/spring-metrics/docs/current/public/prometheus
https://blog.autsoft.hu/defining-custom-metrics-in-a-spring-boot-application-using-micrometer/
https://www.atlantbh.com/custom_metrics_micrometer_prometheus_spring_boot_actuator/