17. Spring Boot Actuator¶
17.1. Actuator介绍¶
在本节中,我们将介绍Spring Boot Actuator。 我们将首先介绍基础知识,然后详细讨论Spring Boot 1.x和2.x中的可用内容。
本质上,Actuator为Spring Boot的应用带来了监控生产应用的功能:监视应用程序,收集指标,了解流量或数据库状态。 Actuator的主要好处是,我们可以获得生产级工具,而不必自己真正实现这些功能。Actuator主要用于公开有关正在运行的应用程序的操作信息-运行状况,指标,信息,dump,环境等。它使用HTTP endpoints或JMX Bean使我们能够与其交互。
一旦Actuator的依赖关系位于类路径classpath上,用户可以立即使用某些endpoints。 与大多数Spring模块一样,我们可以通过多种方式轻松地对其进行配置或扩展。
17.2. 启用Actuator¶
要在您的应用程序中启用Spring Boot Actuator,您必须在包管理器中添加Spring Boot Actuator依赖项。通过添加Starter依赖项spring-boot-starter-actuator,这是在Spring应用程序中启用actuator功能的最简单方法。
- Maven工程中:
1 2 3 4 5 6 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- Gradle工程中:
1 2 3 dependencies { compile("org.springframework.boot: spring-boot-starter-actuator") }
17.3. Spring Boot 1.X 中的Actuator¶
在1.x中,执行器遵循 R/W 模型,这意味着我们可以对其进行读取或写入。例如,我们可以检索指标或应用程序的运行状况。 另外,我们可以优雅地终止我们的应用程序或更改日志记录配置。
为了使其工作,Actuator要求Spring MVC通过HTTP公开其endpoints。 不支持其他技术。
在1.x中,Actuator带来了自己的安全模型。 它利用了Spring Security安全架构,但是需要与应用程序的其余部分独立配置。而且,大多数endpoints都是sensitive状态,即私密的,这意味着它们不是完全公开的,换句话说,大多数信息将被省略。 例如:/metrics。
17.3.1. 分析Actuator的接口¶
In 1.x, Here are some of the most common endpoints Boot provides out of the box:
- /health – Shows application health information (a simple ‘status’ when accessed over an unauthenticated connection or full message details when authenticated); it’s not sensitive by default
- /info – Displays arbitrary application info; not sensitive by default
- /metrics – Shows ‘metrics’ information for the current application; it’s also sensitive by default
- /trace – Displays trace information (by default the last few HTTP requests)
我们可以在官方文档中找到现有endpoints的完整列表。https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-endpoints
17.3.2. 显示配置细节¶
17.3.3. 利用接口显示指标¶
1 2 | endpoints.metrics.sensitive=false
endpoints.metrics.enabled=true
|
17.3.4. 显示应用程序信息¶
1 2 3 | info.app.name=Spring Sample Application
info.app.description=This is my first spring boot application
info.app.version=1.0.0
|
17.3.5. 关闭应用程序¶
17.3.6. 自定义Actuator¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.docedit.fsd;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class HealthCheck implements HealthIndicator {
@Override
public Health health() {
int errorCode = check(); // perform some specific health check
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
public int check() {
// Our logic to check health
System.out.println("Our logic to check health");
return 0;
}
}
|
17.3.6.1. 启用或禁用某个Actuator接口¶
endpoints.beans.enabled=true
17.3.6.2. 更改接口ID¶
endpoints.beans.id=springbeans
17.3.6.3. 更改Actuator接口的灵敏度¶
endpoints.beans.sensitive=false
17.3.6.4. 编写自定义健康指标¶
- 启用metrics
1 2 endpoints.metrics.sensitive=false endpoints.metrics.enabled=true
- 编写CounterService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.docedit.fsd; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.metrics.CounterService; import org.springframework.stereotype.Component; @Component public class HealthCheck implements HealthIndicator { @Autowired private CounterService counterService; @Override public Health health() { int errorCode = check(); // perform some specific health check if (errorCode != 0) { return Health.down().withDetail("Error Code", errorCode).build(); } return Health.up().build(); } public int check() { // Our logic to check health System.out.println("Our logic to check health"); counterService.increment("counter.login.success"); // test gather custom metrics, counterService.increment("counter.login.failure"); // test gather custom metrics return 0; } }
访问 http://localhost:8080/health 目的是触发counterService.increment方法。
接着访问 http://localhost:8080/metrics , 显示下面的指标信息:
"counter.login.failure":1,"counter.login.success":1,"counter.status.200.health":1
17.3.7. 创建一个自定义Endpoint¶
- 创建CustomEndpoint
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Component public class CustomEndpoint implements Endpoint<List<String>> { @Override public String getId() { return "customEndpoint"; } @Override public boolean isEnabled() { return true; } @Override public boolean isSensitive() { return true; } @Override public List<String> invoke() { // Custom logic to build the output List<String> messages = new ArrayList<String>(); messages.add("This is message 1"); messages.add("This is message 2"); return messages; } }
接着访问 http://localhost:8080/customEndpoint,或者用CURL检查:
curl -H 'Content-Type:application/json' http://localhost:8080/customEndpoint
17.3.8. 对Actuator接口进行安全控制¶
在1.x中。 Actuator基于Spring Security配置其自己的安全模型,但与应用程序的其余部分无关。 默认情况下,除 /info 外的所有内置Endpoint都是私密的。 如果应用程序使用的是Spring Security,我们可以通过在application.properties文件中定义默认的安全属性(用户名,密码和角色)来保护这些endpoints:
security.user.name=admin
security.user.password=secret
management.security.role=SUPERUSER
添加security依赖:
1 2 3 4 | <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
|
17.3.9. Further Customization¶
为了安全起见,我们可能选择通过非标准端口公开Actuator endpoints。可以使用management.port属性进行配置。
1 2 3 4 5 6 7 8 | #port used to expose actuator
management.port=8081
#CIDR allowed to hit actuator
management.address=127.0.0.1
#Whether security should be enabled or disabled altogether
management.security.enabled=false
|
17.4. Spring Boot 2.X 中的Actuator¶
在2.x中,默认情况下,现在所有Actuator endpoints都放在 /actuator 路径下,且只有两个默认是公开的 /health 和 /info,其他的默认是私密的。
我们使用新的属性management.endpoints.web.base-path来调整默认的actuator路径。
17.4.1. 分析Actuator的接口¶
- /auditevents – lists security audit-related events such as user login/logout. Also, we can filter by principal or type among others fields
- /beans – returns all available beans in our BeanFactory. Unlike /auditevents, it doesn’t support filtering
- /conditions – formerly known as /autoconfig, builds a report of conditions around auto-configuration
- /configprops – allows us to fetch all @ConfigurationProperties beans
- /env – returns the current environment properties. Additionally, we can retrieve single properties
- /flyway – provides details about our Flyway database migrations
- /health – summarises the health status of our application
- /heapdump – builds and returns a heap dump from the JVM used by our application
- /info – returns general information. It might be custom data, build information or details about the latest commit
- /liquibase – behaves like /flyway but for Liquibase
- /logfile – returns ordinary application logs
- /loggers – enables us to query and modify the logging level of our application
- /metrics – details metrics of our application. This might include generic metrics as well as custom ones
- /prometheus – returns metrics like the previous one, but formatted to work with a Prometheus server
- /scheduledtasks – provides details about every scheduled task within our application
- /sessions – lists HTTP sessions given we are using Spring Session
- /shutdown – performs a graceful shutdown of the application
- /threaddump – dumps the thread information of the underlying JVM
在Spring Boot 2.0中,内部metrics已被Micrometer支持所取代。 因此,如果我们的应用程序使用的是GaugeService或CounterService,则它们将不再可用。
17.4.1.1. 启用或禁用某个Endpoint¶
如果要启用所有这些功能,可以设置:
management.endpoints.web.exposure.include=*
要显式启用特定endpoint(例如 /shutdown),我们使用:
management.endpoint.shutdown.enabled=true
或者我们可以列出应启用的具体endpoints:
management.endpoints.web.exposure.include=beans,metrics
要公开排除一个(例如 /loggers)以外的所有启用的endpoints,我们使用:
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=loggers
17.4.2. 创建一个自定义endpoint¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package com.docedit.fsd;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;
@Endpoint(id="mypoint")
@Component
public class MyPointEndPoint {
@ReadOperation
public String mypoint(){
return "Hello" ;
}
}
|
我们可以使用以下声明定义操作:
- @ReadOperation – 对应 HTTP GET
- @WriteOperation – 对应 HTTP POST
- @DeleteOperation – 对应 HTTP DELETE
17.4.3. 显示git详细信息¶
- 添加git plugin。
1 2 3 4 5 6 7 | <plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<configuration>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
</configuration>
</plugin>
|
执行mvn clean package命令后,将会生成文件:target/classes/git.properties
macbook-pro:fsd2.x murphy$ cat target/classes/git.properties #Generated by Git-Commit-Id-Plugin #Fri Oct 11 15:17:12 CST 2019 git.branch=master git.build.host=macbook-pro.cn.ibm.com git.build.time=2019-10-11T15\:17\:12+0800 git.build.user.email=lanzejun@cn.ibm.com git.build.user.name=lanzejun git.build.version=0.0.1-SNAPSHOT git.closest.tag.commit.count= git.closest.tag.name= git.commit.id=60201666e9ec6088da5072c1b19c27f686cc9a2c git.commit.id.abbrev=6020166 git.commit.id.describe=6020166-dirty git.commit.id.describe-short=6020166-dirty git.commit.message.full=update git.commit.message.short=update git.commit.time=2019-10-09T17\:02\:28+0800 git.commit.user.email=lanzejun@cn.ibm.com git.commit.user.name=lanzejun git.dirty=true git.remote.origin.url=git@github.ibm.com\:lanzejun/fullstack.git git.tags= git.total.commit.count=70
查看info: http://localhost:8080/actuator/info,默认情况下,显示的节点信息仅有3个。
17.4.3.1. 指定git地址¶
1 2 3 | <configuration>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
</configuration>
|
其中${project.basedir}指的是当前项目的根目录。
17.4.3.3. 关闭git.properties文件的创建¶
在configuration中添加:
<generateGitPropertiesFile>false</generateGitPropertiesFile>
17.4.3.5. 过滤敏感信息¶
在configuration中添加:
1 2 3 | <excludeProperties>
<excludeProperty>git.user.*</excludeProperty>
</excludeProperties>
|
17.4.4. 对Actuator接口进行安全控制¶
Actuator与常规Spring Security规则共享安全配置。因此,要调整Actuator安全性规则,我们可以为路径添加一个例外,如:/actuator/** :
添加security依赖:
1 2 3 4 | <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
|
1 2 3 4 5 6 7 8 | @Bean
public SecurityWebFilterChain securityWebFilterChain(
ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated()
.and().build();
}
|