spring-boot-actuator
是 spring-boot 周边组件之一,主要是用来查询或监控 spring-boot 项目各种组件、各种维度的度量指标,比如环境变量信息、日志级别、spring bean 信息、组件(redis、mq、db)健康状态等,可以通过 jmx 技术或者 http 技术来使用 actuator,下面主要是通过 http 技术来讲解其使用方法以及自定义 endpoint 端点信息和 health indicator 健康状况指示信息。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
<version>2.3.2.RELEASEversion>
dependency>
默认会 expose 两个 web endpoint,分别是 health、info
打开 http://localhost:8081/actuator/health,看到的响应如下
说明应用程序是健康的。
在 application.properties 配置文件中添加配置 management.endpoint.health.show-details=always
后再打开该链接,得到的响应如下
可以看到显示的结果变多了,不仅显示了应用的健康状况,也显示了应用中组件的健康状况,比如我的应用中使用了 nacos 注册中心,响应中就多了个 nacosDiscovery 组件。
默认情况下,只暴露了两个端点(info endpoint 和 health endpoint),现在我想暴露全部的端点,只需要在 application.properties 配置文件中加上配置 management.endpoints.web.exposure.include=*
,访问 http://localhost:8081/actuator 结果如下
{
"_links": {
"self": {
"href": "http://localhost:8081/actuator",
"templated": false
},
"archaius": {
"href": "http://localhost:8081/actuator/archaius",
"templated": false
},
"nacosdiscovery": {
"href": "http://localhost:8081/actuator/nacosdiscovery",
"templated": false
},
"beans": {
"href": "http://localhost:8081/actuator/beans",
"templated": false
},
"caches-cache": {
"href": "http://localhost:8081/actuator/caches/{cache}",
"templated": true
},
"caches": {
"href": "http://localhost:8081/actuator/caches",
"templated": false
},
"health": {
"href": "http://localhost:8081/actuator/health",
"templated": false
},
"health-path": {
"href": "http://localhost:8081/actuator/health/{*path}",
"templated": true
},
"info": {
"href": "http://localhost:8081/actuator/info",
"templated": false
},
"conditions": {
"href": "http://localhost:8081/actuator/conditions",
"templated": false
},
"configprops": {
"href": "http://localhost:8081/actuator/configprops",
"templated": false
},
"env-toMatch": {
"href": "http://localhost:8081/actuator/env/{toMatch}",
"templated": true
},
"env": {
"href": "http://localhost:8081/actuator/env",
"templated": false
},
"loggers": {
"href": "http://localhost:8081/actuator/loggers",
"templated": false
},
"loggers-name": {
"href": "http://localhost:8081/actuator/loggers/{name}",
"templated": true
},
"heapdump": {
"href": "http://localhost:8081/actuator/heapdump",
"templated": false
},
"threaddump": {
"href": "http://localhost:8081/actuator/threaddump",
"templated": false
},
"metrics-requiredMetricName": {
"href": "http://localhost:8081/actuator/metrics/{requiredMetricName}",
"templated": true
},
"metrics": {
"href": "http://localhost:8081/actuator/metrics",
"templated": false
},
"scheduledtasks": {
"href": "http://localhost:8081/actuator/scheduledtasks",
"templated": false
},
"mappings": {
"href": "http://localhost:8081/actuator/mappings",
"templated": false
},
"refresh": {
"href": "http://localhost:8081/actuator/refresh",
"templated": false
},
"features": {
"href": "http://localhost:8081/actuator/features",
"templated": false
},
"service-registry": {
"href": "http://localhost:8081/actuator/service-registry",
"templated": false
}
}
}
可以发现,多了很多个端点,我们重点关注下 metrics 端点,打开浏览器访问 http://localhost:8081/actuator/metrics 得到的结果如下
{
"names": [
"http.server.requests",
"jvm.buffer.count",
"jvm.buffer.memory.used",
"jvm.buffer.total.capacity",
"jvm.classes.loaded",
"jvm.classes.unloaded",
"jvm.gc.live.data.size",
"jvm.gc.max.data.size",
"jvm.gc.memory.allocated",
"jvm.gc.memory.promoted",
"jvm.gc.pause",
"jvm.memory.committed",
"jvm.memory.max",
"jvm.memory.used",
"jvm.threads.daemon",
"jvm.threads.live",
"jvm.threads.peak",
"jvm.threads.states",
"logback.events",
"process.cpu.usage",
"process.files.max",
"process.files.open",
"process.start.time",
"process.uptime",
"system.cpu.count",
"system.cpu.usage",
"system.load.average.1m",
"tomcat.sessions.active.current",
"tomcat.sessions.active.max",
"tomcat.sessions.alive.max",
"tomcat.sessions.created",
"tomcat.sessions.expired",
"tomcat.sessions.rejected"
]
}
可以发现,系统中有这么多可以度量的指标,那么该怎么查看这些指标呢?注意到有个 metrics-requiredMetricName 端点,我们访问这个端点,同时加上指标名称,比如访问 http://localhost:8081/actuator/metrics/jvm.memory.max 来查看 JVM 最大内存,响应结果如下
{
"name": "jvm.memory.max",
"description": "The maximum amount of memory in bytes that can be used for memory management",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 5421137919
}
],
"availableTags": [
{
"tag": "area",
"values": [
"heap",
"nonheap"
]
},
{
"tag": "id",
"values": [
"Compressed Class Space",
"PS Old Gen",
"PS Survivor Space",
"Metaspace",
"PS Eden Space",
"Code Cache"
]
}
]
}
暴露全部端点的同时,也可以排除某几个指定的端点,比如要排除 env 和 beans 端点,就可以在配置文件中加上 management.endpoints.web.exposure.exclude=env,beans
。
自定义 endpoint 时,做好三点即可,一是使该类成为 spring bean,二是加上 @Endpoint
注解,三是灵活运用 @ReadOperation
和 @WriteOperation
注解,自定义的 books endpoint 如下
package org.tunnel.sample.cloud.endpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 自定义Endpoint,Endpoint名称为“books”
*
* @author debo
*/
@Component
@Endpoint(id = "books")
public class BookEndpoint {
private List<String> books = Stream.of("java", "c++", "python").collect(Collectors.toList());
/**
* 使用GET方法访问,访问链接http://localhost:8081/actuator/books
* 相当于新增了一个端点,端点名:books
*
* @return
*/
@ReadOperation
public List<String> books() {
return books;
}
/**
* 使用GET方法访问,访问链接http://localhost:8081/actuator/books/${bookName}
* 相当于新增了一个端点,端点名:books-bookName
*
* @param bookName
* @return
*/
@ReadOperation
public String bookDesc(@Selector String bookName) {
if ("java".equals(bookName)) {
return "Java是世界上最好的语言";
}
return "你是谁?";
}
/**
* 使用POST JSON方法访问
* curl -X POST -H "Content-Type: application/json" http://localhost:8081/actuator/books -d '{"bookName":"钢铁是怎样炼成的","version":3}'
*
* @param bookName
* @param version
* @return
*/
@WriteOperation
public String addBook(String bookName, Integer version) {
books.add(bookName + version);
return "成功";
}
}
启动项目后,会发现 actuator 主页新增两个 endpoint:books 和 books-bookName,其中 books 端点同时支持 GET 和 POST 请求,POST 请求是由 @WriteOperation
注解支持,books-bookName 端点支持 GET 请求,参数由 path 路径传入
注意:需要在 maven-complier-plugin 插件配置 -parameters 编译参数,否则端点名称不会是 books-bookName,而是 books-arg0。
自定义健康状况检查时,做好两点即可,一是使该类成为 spring bean,二是继承 AbstractHealthIndicator
类,实现 doHealthCheck
方法
package org.tunnel.sample.cloud.endpoint.health;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.stereotype.Component;
/**
* 自定义健康状态检查,如果beanName是myHealthIndicator,那么在health中出现的标识就是“my”
*
* @author debo
* @date 2022-01-26
*/
@Component
public class MyHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Builder builder) throws Exception {
builder.up();
}
}
打开 http://localhost:8081/actuator/health,发现多了个 my
健康状况检查标识
通过 loggers 端点,可以动态修改项目的日志级别,比如想要修改 ROOT logger 的日志级别,就可以发送 POST 请求 curl -X POST -H "Content-Type: application/json" http://localhost:8081/actuator/loggers/ROOT -d '{"configuredLevel":"DEBUG"}'
shutdown 端点可以用来远程关闭 spring-boot 应用,比如发送 POST 请求 curl -X POST http://localhost:8081/actuator/shutdown
即可关闭应用。
默认情况下,除了 shutdown endpoint ,其它所有的 endpoint 都是开启(enable)的,也就是说,shutdown endpoint 被 expose 后,还需要手动 enable 才能生效,enable 的格式如 management.endpoint.
,比如要开启 shutdown endpoint ,需要在配置文件 application.properties 中添加配置 management.endpoint.shutdown.enabled=true
。