Actuator 一般用在 production 環境,使用 http endpoint 或 JMX 方式監控 app,然後抓取指標數值給資料監控平台。
以此順序介紹 Actuator -> Endpoints -> Metrics -> Grafana
要啟用 actuator,只需要加上 library
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Endpoint
endpoint 是用來監控 spring boot app,spring boot 內建很多endpoints,每個 endpoint 都可透過 http/JMX 方式暴露出去,大部分都是用 http。endpoint 會映射為 /actuator/${ID}
ID 就是 endpoint 的 ID,ex: /actuator/health
啟動 app 後,瀏覽網址 http://localhost:8080/actuator/health
結果 UP 代表健康運作中
{
"status": "UP"
}
spring boot 內建的 endpoints
name | desc |
---|---|
auditevents | 當前 app 的 audit event |
beans | 所有 spring beans |
caches | 可使用的 cache |
conditions | 設定類別上評估條件及匹配成功與否的原因 |
configprops | 所有 @ConfigurationProperties list |
env | spring 環境中暴露的所有 properties |
flyway | 所有 flyway 遷移記錄 |
health | 健康資訊 |
httpexchanges | http exchange message(預設顯示最新的 100個) |
info | app basic info |
integrationgraph | spring integration graph |
loggers | 顯示/修改 logger 設定 |
liquibase | 顯示 liquibase db migration |
metrics | metric infos |
mappings | 顯示所有 @RequestMapping |
quartz | 顯示 quartz jobs |
scheduledtasks | 顯示 scheduled tasks |
sessions | 當有 servlet-based web app 使用 Spring Session 時,查詢/刪除 user sessions |
shutdown | 關閉 app |
startup | 顯示啟動的資料 |
threaddump | thread dump |
使用 web app 時,還有以下這些
name | desc |
---|---|
heapdump | 回傳 heap dump。HotSpot VM 是回傳 HPROF-format file。OpenJ9 JVM 是回傳 PHD-format file |
logfile | log file content (需要設定 logging.file.name/logging.file.path) |
prometheus | 可被 prometheus server 提取的 metric |
除了 shotdown 其他所有 endpoint 預設都是開啟的。可透過 management.endpoint.<id>.enabled
啟用/禁用 endpoint。
ex:
management:
endpoint:
shutdown:
enabled: true
禁用所有 endpoint, 只啟用某一個 endpoint
management:
endpoints:
enable-by-default: false
endpoint:
shutdown:
enabled: true
expose endpoint
啟用後,不一定能被存取。spring boot 3 預設只以 JMX, Web 方式暴露了 health
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude |
|
management.endpoints.jmx.exposure.include |
health |
management.endpoints.web.exposure.exclude |
|
management.endpoints.web.exposure.include |
health |
management:
endpoints:
jmx:
exposure:
include: "health,info"
web:
exposure:
include: "*"
exclude: "env,beans"
security
endpoint 提供的資訊需要安全保護
只要有 Spring Security library,就會自動保護所有 endpoints
實作 actuator 的 ManagementWebSecurityAutoConfiguration
註冊在 spring-boot-actuator-autoconfigure
修改 pom.xml 後
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
存取 http://localhost:8080/actuator/info 會自動轉到 Please sign in
如果不想使用 spring boot 預設機制,可改用 SecurityFilterChain
package com.test.actuator;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests((authorize) -> {
authorize.requestMatchers("/").permitAll()
.requestMatchers(EndpointRequest.to("health")).hasRole("ENDPOINT_ADMIN")
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
})
// .csrf(csrf -> csrf.disable())
.csrf(csrf -> csrf.ignoringRequestMatchers(EndpointRequest.toAnyEndpoint()))
.formLogin(withDefaults())
.logout(logout -> logout.logoutUrl("/"))
.build();
}
@Bean
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("test").password("{noop}test")
.roles("ENDPOINT_ADMIN", "ADMIN", "TEST").build());
manager.createUser(User.withUsername("root").password("{noop}root")
.roles("ADMIN").build());
return manager;
}
}
permit all
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());
return http.build();
}
}
customize endpoint mapping
預設 http://localhost:8080/actuator 可取得所有暴露的 endpoints
ex:
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"health-path": {
"href": "http://localhost:8080/actuator/health/{*path}",
"templated": true
},
"health": {
"href": "http://localhost:8080/actuator/health",
"templated": false
}
}
}
可用以下設定禁用
management:
endpoints:
web:
discovery:
enabled: false
也可以修改 mapping,這樣要改用 http://localhost:8080/act/hth 取得 health
management:
endpoints:
web:
base-path: /act
path-mapping:
health: hth
也可以修改 web port,不使用 service 的 web port。
management:
server:
port: 8088
address: 127.0.0.1
把 port 改為 -1 等同 expose.exclude: "*"
management:
server:
port: -1
實作自訂 endpoint
endpoint 啟用時,會自動設定
heath endpoint 是用 HealthEndpointAutoConfiguration。 然後用 @Import
找到不同 web 類型的 endpoint class
health endpoint 是用 HealthEndpoint 類別實作的,該類別有 @Endpoint
註解,且要註冊為 Bean。支援以 @JmxEndpoint
@WebEndpoint
暴露方式
以 @ReadOperation
@WriteOperation
@DeleteOperation
對應不同的 http method: GET/POST/DELETE
POST request Content-Type 只接受 application/vnd.spring-boot.actuator.v2+json, application/json
新增 User.java
package com.test.actuator;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
TestEndpoint.java
package com.test.actuator.endpoint;
import com.test.actuator.User;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
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.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
@Component
@WebEndpoint(id = "test")
public class TestEndpoint {
@ReadOperation
public User getUser(@Selector Integer id) {
return new User(id, "james", 18);
}
@WriteOperation
public User updateUser(int id, @Nullable String name, @Nullable Integer age) {
User user = getUser(id);
user.setName(StringUtils.defaultIfBlank(name, user.getName()));
user.setAge(ObjectUtils.defaultIfNull(age, user.getAge()));
return user;
}
}
注意要 expose endpoint
management:
endpoints:
web:
exposure:
include: "*"
瀏覽網址 http://localhost:8080/actuator/test/1
結果
{"id":1,"name":"james","age":18}
POST/DELETE 預設會回應 403,因為 spring boot 預設會打開 CSRF
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests((authorize) -> {
authorize.requestMatchers("/").permitAll()
.requestMatchers(EndpointRequest.to("health")).hasRole("ENDPOINT_ADMIN")
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
})
.csrf(csrf -> csrf.disable())
// .csrf(csrf -> csrf.ignoringRequestMatchers(EndpointRequest.toAnyEndpoint()))
.formLogin(withDefaults())
.logout(logout -> logout.logoutUrl("/"))
.build();
}
enpoint 也支援 CORS 設定
management:
endpoints:
web:
cors:
allowed-origins: "https://test.com"
allowed-methods: "GET,POST"
Observability
系統外部觀測正在運作的內部狀態的能力,spring boot 3 透過 Micrometer 提高可觀測性,支援 Micrometer 1.10+
引用可觀測 API,並自動設定 micrometer 追蹤,支援 Brave, OpenTelemetry, Zipkin, Wavefront
使用 micrometer API 完成觀測後,可將數據交給 Zipkin
Metrics
/actuator/metrics 指標,包含了 JVM, system, tomcat, Logger, Spring MVC...
預設不會 expose
瀏覽網址 http://localhost:8080/actuator/metrics 可查閱所有 metrics
http://localhost:8080/actuator/metrics/jvm.memory.max 就是取得 jvm.memory.max 的資訊
可自訂 metric
package com.test.actuator.metrics;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class MetricsConfig {
@Bean
public MeterBinder initDate(Environment env) {
return (registry) -> Gauge.builder("init.date", this::date).register(registry);
}
@Bean
public MeterBinder systemDate(Environment env) {
return (registry) -> Gauge.builder("system.date", this::date).register(registry);
}
private Number date() {
return 2024.11;
}
}
網址 http://localhost:8080/actuator/metrics/init.date
結果
{
"name":"init.date",
"measurements":[
{
"statistic":"VALUE",
"value":2024.11
}
],
"availableTags":[
]
}
Tracing
使用 OpenTelemetry 結合 Zipkin 或 Wavefront
使用 OpenZipkin Brave 結合 Zipkin 或 Wavefront
OpenTelemetry 可生成/收集/匯出觀測資料 metrics, logs, traces,他只會收集資料,分析跟展示要用其他軟體
Zipkin 是 Twitter 開源的分佈式追蹤系統,可收集解決服務的延遲問題的時間資料。如果 log 有 Trace ID,可直接展示。
<!-- 將 Micrometer Observation API 橋接到 OpenTelemetry -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<!-- 向 Zipkin 報告跟蹤資訊 -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
採樣設定,預設為 0.1,也就是只採樣 10% 的 request
management:
tracing:
sampling:
probability: 1.0
在 log 顯示 Trace ID, Span ID
logging:
pattern:
level: ${spring.application.name:},%X{traceId:-},%X{spanId:-}
Spring Boot Admin
GitHub - codecentric/spring-boot-admin: Admin UI for administration of spring boot applications
這個是社群開發的
有個 server 提供 Spring Boot Actuators UI
有個 client 註冊到 server,並能存取所有 actuator endpoints.
ref: Spring Boot Admin – Getting started
配置 Admin Server
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在 application 加上 @EnableAdminServer
@SpringBootApplication
@EnableAdminServer
public class SpringBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminApplication.class, args);
}
}
配置 Client
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
加上設定
spring:
boot:
admin:
client:
url: http://localhost:8080
management:
endpoints:
web:
expose:
include: '*'
info:
env:
enabled: true
禁用所有安全機制
@Configuration
public static class SecurityPermitAllConfig {
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) {
return http.authorizeHttpRequests((authorizeRequests) -> authorizeRequests.anyRequest().permitAll())
.csrf().disable().build();
}
}
參考 Spring Boot Admin server notification 可設定通知
Prometheus
要在 pom.xml 加上 library
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>${micrometer-registry-prometheus.version}</version>
</dependency>
spring boot 就會提供 endpoint /actuator/prometheus 可 pull 資料
加上 libary
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
<version>${simpleclient_pushgateway.version}</version>
</dependency>
修改設定
management:
prometheus:
metrics:
export:
pushgateway:
enabled: true
可 push 資料
Prometheus 通常結合 Grafana 使用
沒有留言:
張貼留言