Spring boot之Actuator理解

Environment

  • Spring boot 2.0.4
  • Jdk1.8

Preface

今天生产上的日志文件把磁盘撑爆了,非常悲剧.既然出了问题,就得找到原因以及解决方案.(一劳永逸)

通过梳理,识别出以下几个问题:

  • 代码中的日志没有行至有效的规范.debug和info没有明确的规范.
  • 有些debug日志有助于生产上排查错误,需要动态切换日志级别的能力.

针对日志规范问题,每个人的见解不一样,我自己的梳理在《Java日志规范看法》中.

根据第二个问题,发现spring boot actuator提供了这个能力,这就促使我去研究一番.

Spring Boot Actuator

○ Spring Boot includes a number of additional features to help you monitor and manage your application when you push it to production. You can choose to manage and monitor your application by using HTTP endpoints or with JMX. Auditing, health, and metrics gathering can also be automatically applied to your application.

☆ Spring boot 提供了以HTTP或JMX管理和监控应用程序.适用于应用程序的审计、健康情况、度量收集.

依赖包

maven项目

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

提供的端点

  • 详细用法参考Usage.

下表提供了16个请求端点,HTTP和JMX都可以使用.另外4个端点在使用web时可以用.

  • 请求前缀为/actuators

例如:以http方式,监测应用程序健康情况:/actuators/health

1
2
$ curl http://localhost:[port]/actuator/health
{"status":"UP"}

列表:

ID Description Enabled by default
auditevents Exposes audit events information for the current application. Yes
beans Displays a complete list of all the Spring beans in your application. Yes
conditions Shows the conditions that were evaluated on configuration and auto-configuration classes and the reasons why they did or did not match. Yes
configprops Displays a collated list of all @ConfigurationProperties. Yes
env Exposes properties from Spring’s ConfigurableEnvironment. Yes
flyway Shows any Flyway database migrations that have been applied. Yes
health Shows application health information. Yes
httptrace Displays HTTP trace information (by default, the last 100 HTTP request-response exchanges). Yes
info Displays arbitrary application info. Yes
loggers Shows and modifies the configuration of loggers in the application. Yes
liquibase Shows any Liquibase database migrations that have been applied. Yes
metrics Shows ‘metrics’ information for the current application. Yes
mappings Displays a collated list of all @RequestMapping paths. Yes
scheduledtasks Displays the scheduled tasks in your application. Yes
sessions Allows retrieval and deletion of user sessions from a Spring Session-backed session store. Not available when using Spring Session’s support for reactive web applications. Yes
shutdown Lets the application be gracefully shutdown. No
threaddump Performs a thread dump. Yes

○ If your application is a web application (Spring MVC, Spring WebFlux, or Jersey),you can use the following additional endpoints.

ID Description Enabled by default
heapdump Returns a GZip compressed hprof heap dump file. Yes
jolokia Exposes JMX beans over HTTP (when Jolokia is on the classpath, not available for WebFlux). Yes
logfile Returns the contents of the logfile (if logging.file or logging.path properties have been set). Supports the use of the HTTP Range header to retrieve part of the log file’s content. Yes
prometheus Exposes metrics in a format that can be scraped by a Prometheus server. Yes

开启端点

  • actuator中提供的20个端点,默认级别开关级别如下:
ID JMX Web
auditevents Yes No
beans Yes No
conditions Yes No
configprops Yes No
env Yes No
flyway Yes No
health Yes Yes
heapdump N/A No
httptrace Yes No
info Yes Yes
jolokia N/A No
logfile N/A No
loggers Yes No
liquibase Yes No
metrics Yes No
mappings Yes No
prometheus N/A No
scheduledtasks Yes No
sessions Yes No
shutdown Yes No
threaddump Yes No
  • JMX

    除prometheus、logfile、jolokia、heapdump没有提供外,其余端点默认开启.

  • Web

    默认只开启health、info端点.

正确打开姿势:

  • JMX

    1
    2
    3
    4
    5
    6
    7
    # 打开 management.endpoints.jmx.exposure.include
    # 关闭 management.endpoints.jmx.exposure.exclude
    # 如关闭mappings、shutdown端点.
    management.endpoints.jmx.exposure.exclude=mappings,shutdown
    # 如关闭所有端点.
    management.endpoints.jmx.exposure.exclude=*
    # YAML中*有特殊含义,需要用"*"
  • Web

    1
    2
    3
    4
    5
    6
    7
    # 打开 management.endpoints.web.exposure.include
    # 关闭 management.endpoints.web.exposure.exclude
    # 如打开env、mappings端点
    management.endpoints.web.exposure.include=env,mappings
    # 如打开所有端点
    management.endpoints.web.exposure.include=*
    # YAML中*有特殊含义,需要用"*"

端点详细用法

请求前缀为/actuators.具体用法参考文档Usage.

配置端点缓存

○ Endpoints automatically cache responses to read operations that do not take any parameters.

☆ 官方说是默认缓存读取操作的无参端点返回值.至于具体时间只能看源码了.

对应的源码类为:EndpointAutoConfiguration、EndpointIdTimeToLivePropertyFunction

正确配置姿势如下:

1
2
3
# The prefix management.endpoint.<name> is used to uniquely identify the endpoint that is being configured.
# 如配置bean端点返回值缓存时间为10秒
management.endpoint.beans.cache.time-to-live=10s

自定义端点路径

  • base-path

    默认值是:/actuator

  • path-mapping

    端点映射路径,默认是官方提供的20个端点名称.

完整请求路径为:[base-path]+[path-mapping]

1
2
3
# 原health端点为:/actuator/health,现在改为:/manager/healthcheck
management.endpoints.web.base-path=/manager
management.endpoints.web.path-mapping.health=healthcheck

自定义端点

○ If you add a @Bean annotated with @Endpoint, any methods annotated with @ReadOperation, @WriteOperation, or @DeleteOperation are automatically exposed over JMX and, in a web application, over HTTP as well. Endpoints can be exposed over HTTP using Jersey, Spring MVC, or Spring WebFlux.

○ You can also write technology-specific endpoints by using @JmxEndpoint or @WebEndpoint. These endpoints are restricted to their respective technologies. For example, @WebEndpoint is exposed only over HTTP and not over JMX.

○ You can write technology-specific extensions by using @EndpointWebExtension and @EndpointJmxExtension. These annotations let you provide technology-specific operations to augment an existing endpoint.

○ Finally, if you need access to web-framework-specific functionality, you can implement Servlet or Spring @Controller and @RestController endpoints at the cost of them not being available over JMX or when using a different web framework.

☆ actuator可以提供JMX和HTTP两种方式,所以也提供对应实现的方式.

  • @Endpoint针对JMX和HTTP.
  • @JmxEndpoint@EndpointJmxExtension只针对JMX.
  • @WebEndpoint@EndpointWebExtension只针对HTTP.
  • @ReadOperation, @WriteOperation, @DeleteOperation 这三个用于指定请求方式.
Operation HTTP method
@ReadOperation GET
@WriteOperation POST
@DeleteOperation DELETE
☆ 使用actuator的自定义端点有特别的意义吗?

目前看,针对HTTP的方式,与平常我自己暴露端点也没区别.但针对JMX监控的话,这就是它优势之处了.

另外,个人认为没有特殊要求,使用@Endpoint更好,既提供了JMX监控端点,也同时提供了HTTP监控端点.

如何使用

○ To allow the input to be mapped to the operation method’s parameters, Java code implementing an endpoint should be compiled with -parameters, and Kotlin code implementing an endpoint should be compiled with -java-parameters. This will happen automatically if you are using Spring Boot’s Gradle plugin or if you are using Maven and spring-boot-starter-parent.

☆ 在使用@ReadOperation等时,默认是按照参数名匹配入参,如果需要参数数量自动匹配,需要在spring boot时添加-parameters.

新增端点
  • 使用@Endpoint@ReadOperation, @WriteOperation, @DeleteOperation

例子:

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
@Component
@Endpoint(id = "custom-health")
public class CustomHealthEndpoint {

@ReadOperation
public String health() {
return "health";
}

@ReadOperation
public String health2(@Selector String name) {
return "custom-end-point get parameter: " + name;
}

@ReadOperation
public String health3(@Selector String name, @Selector String name2) {
return "custom-end-point get parameter1: " + name +",parameter2: " + name2;
}

@WriteOperation
public String writeOperation(@Selector String name) {
return "custom-end-point post";
}

@DeleteOperation
public String deleteOperation(@Selector String name) {
return "custom-end-point delete";
}
}

启动时,使用-parameters参数.

1
2
3
4
5
6
7
# 调用health2方法 http://localhost:[port]/actuator/custom-health/{anystring}
$ curl http://localhost:[port]/actuator/custom-health/hello
custom-end-point get parameter: hello

# 调用health3方法,参数名必须相同,{angstring}用任意字符串替换就行.http://localhost:[port]/actuator/custom-health/{anystring}/{anystring}
$ curl http://localhost:[port]/actuator/custom-health/hello/world
custom-end-point get parameter1: hello,parameter2: world

启动时,不使用-parameters参数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 调用health无参方法
$ curl http://localhost:[port]/actuator/custom-health
health

# 调用health2方法
$ curl http://localhost:[port]/actuator/custom-health/name
{"timestamp":"2018-08-27T11:04:06.709+0000","status":400,"error":"Bad Request","message":"Missing parameters: name","path":"/actuator/custom-health/p1"}

只能通过以下方式才能请求到health2方法,参数名必须相同.{angstring}用任意字符串替换就行.
$ curl http://localhost:[port]/actuator/custom-health/{anystring}?name=hello
custom-end-point get parameter: hello

# 调用health3方法,参数名必须相同,{angstring}用任意字符串替换就行.
$ curl http://localhost:[port]/actuator/custom-health/{anystring}/{anystring}?name=hello&name=world
custom-end-point get parameter1: hello,parameter2: world

☆ 总结:actuator中端点的多参数请求方式,不按照参数名匹配.所以需要在启动时添加-parameters参数.

  • 使用WebEndpointExtension@EndpointJmxExtension
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Endpoint(id = "myhealth")
public class MyHealthEndpoint {

@ReadOperation
public String health() {
return "health";
}
}

@EndpointWebExtension(endpoint = MyHealthEndpoint.class)
public class MyHealthWebEndpointExtension {

private final MyHealthEndpoint delegate;

public MyHealthWebEndpointExtension(MyHealthEndpoint delegate) {
this.delegate = delegate;
}

@ReadOperation
public WebEndpointResponse<String> getHealth() {
return new WebEndpointResponse<>("health", 200);
}
}

@Configuration
public class ActuatorConfiguration {

@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public MyHealthEndpoint myHealthEndpoint() {
return new MyHealthEndpoint();
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean({MyHealthEndpoint.class})
public MyHealthWebEndpointExtension myHealthWebEndpointExtension(
MyHealthEndpoint delegate) {
return new MyHealthWebEndpointExtension(delegate);
}
}
# application.yml
management:
endpoints:
myhealth:
enabled: true
覆盖原端点

目前覆盖原端点只能通过重载的方式.我这里测试了health端点的覆盖.

1
2
3
4
5
6
7
8
9
10
@Component
public class MyHealthIndicator implements HealthIndicator {

@Override
public Health health() {
return Health.down().build();
}

}
# 再次请求Health端点,返回值就为{"status":"DOWN"}

遗留问题

端点默认缓存的默认时间是多少?

官网还有更多关于监控文章待学习.

参考

spring-boot-2.0.4-doc

Custom Endpoint in Spring Boot Actuator

How to make the @Endpoint(id = “health”) working in Spring Boot 2.0?

坚持原创技术分享,您的支持将鼓励我继续创作!
Fork me on GitHub