Spring Boot 包含许多额外功能,帮助您在将应用推送到生产环境时进行监控和管理。您可以选择使用 HTTP 端点或 JMX 来管理和监控应用程序。审计、健康状况和指标收集也可以自动应用于您的应用程序。

1. 启用生产就绪功能

spring-boot-actuator 模块提供了 Spring Boot 的所有生产就绪功能。启用这些功能的推荐方法是在 spring-boot-starter-actuator “Starter” 上添加依赖。

Actuator 的定义

Actuator 是一个制造业术语,指的是用于移动或控制某物的机械装置。Actuator 可以通过微小的变化产生大量运动。

要将 Actuator 添加到基于 Maven 的项目中,请添加以下“Starter”依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

对于 Gradle,请使用以下声明:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

2. 端点

执行器端点允许您监视和与应用程序交互。Spring Boot包含许多内置端点,并允许您添加自己的端点。例如,health端点提供基本的应用程序健康信息。

您可以启用或禁用每个单独的端点,并且可以公开它们(使它们可以通过HTTP或JMX远程访问)。只有在端点启用和公开时,端点才被视为可用。内置端点仅在可用时自动配置。大多数应用程序选择通过HTTP公开,其中端点的ID和/actuator前缀映射到URL。例如,默认情况下,health端点映射到/actuator/health

要了解有关执行器端点及其请求和响应格式的更多信息,请参阅单独的API文档(HTMLPDF)。

以下与技术无关的端点可用:

ID 描述

auditevents

公开当前应用程序的审计事件信息。需要一个AuditEventRepository bean。

beans

显示应用程序中所有Spring bean的完整列表。

caches

公开可用的缓存。

conditions

显示在配置和自动配置类上评估的条件以及它们匹配或不匹配的原因。

configprops

显示所有@ConfigurationProperties的汇总列表。受到消毒的影响。

env

公开Spring的ConfigurableEnvironment中的属性。受到消毒的影响。

flyway

显示已应用的任何Flyway数据库迁移。需要一个或多个Flyway bean。

health

显示应用程序健康信息。

httpexchanges

显示HTTP交换信息(默认情况下,显示最后100个HTTP请求-响应交换)。需要一个HttpExchangeRepository bean。

info

显示任意应用程序信息。

integrationgraph

显示Spring集成图。需要依赖于spring-integration-core

loggers

显示并修改应用程序中日志记录器的配置。

liquibase

显示已应用的任何Liquibase数据库迁移。需要一个或多个Liquibase bean。

metrics

显示当前应用程序的“度量”信息。

mappings

显示所有@RequestMapping路径的汇总列表。

quartz

显示有关Quartz Scheduler作业的信息。受到消毒的影响。

scheduledtasks

显示应用程序中的定时任务。

sessions

允许从基于Spring Session的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序。

shutdown

允许应用程序优雅关闭。仅在使用jar打包时有效。默认情况下禁用。

startup

显示由ApplicationStartup收集的启动步骤数据。需要将SpringApplication配置为使用BufferingApplicationStartup

threaddump

执行线程转储。

如果您的应用程序是Web应用程序(Spring MVC、Spring WebFlux或Jersey),您可以使用以下附加端点:

ID 描述

heapdump

返回堆转储文件。在HotSpot JVM上,返回一个HPROF格式文件。在OpenJ9 JVM上,返回一个PHD格式文件。

logfile

返回日志文件的内容(如果已设置logging.file.namelogging.file.path属性)。支持使用HTTP Range头检索日志文件内容的一部分。

prometheus

以可被Prometheus服务器抓取的格式公开指标。需要依赖于micrometer-registry-prometheus

2.1. 启用端点

默认情况下,除了shutdown端点外,所有端点都是启用的。要配置端点的启用情况,请使用其management.endpoint.<id>.enabled属性。以下示例启用了shutdown端点:

属性
management.endpoint.shutdown.enabled=true
Yaml
management:
  endpoint:
    shutdown:
      enabled: true

如果您更喜欢端点的启用是选择加入而不是选择退出,请将management.endpoints.enabled-by-default属性设置为false,并使用单独的端点enabled属性选择重新加入。以下示例启用了info端点并禁用了所有其他端点:

属性
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true
Yaml
management:
  endpoints:
    enabled-by-default: false
  endpoint:
    info:
      enabled: true
禁用的端点将完全从应用程序上下文中删除。如果您只想更改端点公开的技术,请改用includeexclude属性

2.2. 公开端点

默认情况下,只有健康端点通过HTTP和JMX公开。由于端点可能包含敏感信息,您应仔细考虑何时公开它们。

要更改公开哪些端点,请使用以下特定于技术的includeexclude属性:

属性 默认值

management.endpoints.jmx.exposure.exclude

management.endpoints.jmx.exposure.include

health

management.endpoints.web.exposure.exclude

management.endpoints.web.exposure.include

health

include属性列出了要公开的端点的ID。 exclude属性列出了不应公开的端点的ID。 exclude属性优先于include属性。您可以使用端点ID列表配置includeexclude属性。

例如,要仅通过JMX公开healthinfo端点,请使用以下属性:

属性
management.endpoints.jmx.exposure.include=health,info
Yaml
management:
  endpoints:
    jmx:
      exposure:
        include: "health,info"

*可用于选择所有端点。例如,要通过HTTP公开所有内容,除了envbeans端点,请使用以下属性:

属性
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans
Yaml
management:
  endpoints:
    web:
      exposure:
        include: "*"
        exclude: "env,beans"
*在YAML中具有特殊含义,因此如果要包含(或排除)所有端点,请确保添加引号。
如果您的应用程序是公开的,强烈建议您也保护您的端点
如果您想要实现自己的端点公开策略,可以注册一个EndpointFilter bean。

2.3. 安全性

出于安全目的,默认情况下只有 /health 端点通过HTTP公开。您可以使用 management.endpoints.web.exposure.include 属性配置要公开的端点。

在设置 management.endpoints.web.exposure.include 之前,请确保公开的执行器不包含敏感信息,通过将它们放在防火墙后面进行保护,或者通过类似于Spring Security的方式进行保护。

如果类路径上存在Spring Security并且没有其他 SecurityFilterChain bean,除了 /health 之外的所有执行器都将由Spring Boot自动配置进行安全保护。如果定义了自定义的 SecurityFilterChain bean,则Spring Boot自动配置会退出,并允许您完全控制执行器访问规则。

如果您希望为HTTP端点配置自定义安全性(例如,只允许具有特定角色的用户访问它们),Spring Boot提供了一些方便的 RequestMatcher 对象,您可以与Spring Security结合使用。

典型的Spring Security配置可能如下所示:

Java
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.web.SecurityFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.securityMatcher(EndpointRequest.toAnyEndpoint());
        http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
        http.httpBasic(withDefaults());
        return http.build();
    }

}
Kotlin
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.Customizer.withDefaults
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain

@Configuration(proxyBeanMethods = false)
class MySecurityConfiguration {

    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests { requests ->
            requests.anyRequest().hasRole("ENDPOINT_ADMIN")
        }
        http.httpBasic(withDefaults())
        return http.build()
    }

}

上述示例使用 EndpointRequest.toAnyEndpoint() 来匹配任何端点的请求,然后确保所有端点都具有 ENDPOINT_ADMIN 角色。 EndpointRequest 还提供了其他几种匹配方法。有关详细信息,请参阅API文档(HTMLPDF)。

如果将应用程序部署在防火墙后面,您可能希望所有执行器端点都可以在不需要身份验证的情况下访问。您可以通过更改 management.endpoints.web.exposure.include 属性来实现:

属性
management.endpoints.web.exposure.include=*
Yaml
management:
  endpoints:
    web:
      exposure:
        include: "*"

此外,如果存在Spring Security,您需要添加自定义安全配置,以允许未经身份验证访问端点,如下例所示:

Java
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.web.SecurityFilterChain;

@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();
    }

}
Kotlin
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.web.SecurityFilterChain

@Configuration(proxyBeanMethods = false)
class MySecurityConfiguration {

    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests { requests ->
            requests.anyRequest().permitAll()
        }
        return http.build()
    }

}
在上述两个示例中,配置仅适用于执行器端点。由于Spring Boot的安全配置在存在任何 SecurityFilterChain bean 时完全退出,您需要配置一个额外的 SecurityFilterChain bean,其中包含适用于应用程序其余部分的规则。

2.3.1. 跨站请求伪造保护

由于Spring Boot依赖于Spring Security的默认设置,默认情况下启用了CSRF保护。这意味着在使用默认安全配置时,需要 POST(关闭和日志记录器端点)、PUTDELETE 的执行器端点会收到403(禁止)错误。

我们建议仅在创建供非浏览器客户端使用的服务时完全禁用CSRF保护。

您可以在 Spring Security参考指南 中找到有关CSRF保护的其他信息。

2.4. 配置端点

端点会自动缓存不带任何参数的读操作的响应。要配置端点缓存响应的时间,请使用其 cache.time-to-live 属性。以下示例将 beans 端点的缓存存活时间设置为10秒:

属性
management.endpoint.beans.cache.time-to-live=10s
Yaml
management:
  endpoint:
    beans:
      cache:
        time-to-live: "10s"
management.endpoint.<name> 前缀唯一标识正在配置的端点。

2.5. 敏感值的清理

默认情况下,/env/configprops/quartz端点返回的信息可能是敏感的,因此值始终会被完全清理(替换为******)。

只有在以下情况下才能以未经清理的形式查看值:

  • 已将show-values属性设置为除NEVER之外的其他值

  • 没有自定义的SanitizingFunction bean应用

可以将show-values属性配置为以下值之一,以用于可清理的端点:

  • NEVER - 值始终被完全清理(替换为******

  • ALWAYS - 值向所有用户显示(只要没有SanitizingFunction bean应用)

  • WHEN_AUTHORIZED - 值仅向授权用户显示(只要没有SanitizingFunction bean应用)

对于HTTP端点,如果用户已经进行了身份验证并具有端点角色属性配置的角色,则认为用户已被授权。默认情况下,任何经过身份验证的用户都被授权。

对于JMX端点,所有用户始终被授权。

以下示例允许所有具有admin角色的用户以原始形式查看/env端点的值。未经授权的用户或没有admin角色的用户将只能看到清理后的值。

属性
management.endpoint.env.show-values=WHEN_AUTHORIZED
management.endpoint.env.roles=admin
Yaml
management:
  endpoint:
    env:
      show-values: WHEN_AUTHORIZED
      roles: "admin"
此示例假定未定义任何SanitizingFunction bean。

2.6. Actuator Web端点的超媒体

添加了一个“发现页面”,其中包含到所有端点的链接。默认情况下,“发现页面”位于/actuator上。

要禁用“发现页面”,请将以下属性添加到应用程序属性中:

属性
management.endpoints.web.discovery.enabled=false
Yaml
management:
  endpoints:
    web:
      discovery:
        enabled: false

当配置了自定义管理上下文路径时,“发现页面”会自动从/actuator移动到管理上下文的根路径。例如,如果管理上下文路径为/management,则发现页面可从/management访问。当管理上下文路径设置为/时,将禁用发现页面,以防止与其他映射发生冲突。

2.7. 跨源资源共享(CORS)支持

跨源资源共享(CORS)是一项W3C规范,允许您以灵活的方式指定授权哪种跨域请求。如果您使用Spring MVC或Spring WebFlux,可以配置Actuator的Web端点以支持这种情况。

CORS支持默认情况下是禁用的,只有在设置了management.endpoints.web.cors.allowed-origins属性后才会启用。以下配置允许example.com域中的GETPOST调用:

属性
management.endpoints.web.cors.allowed-origins=https://example.com
management.endpoints.web.cors.allowed-methods=GET,POST
Yaml
management:
  endpoints:
    web:
      cors:
        allowed-origins: "https://example.com"
        allowed-methods: "GET,POST"
请参阅完整选项列表:CorsEndpointProperties

2.8. 实现自定义端点

如果您添加一个使用@Endpoint注释的@Bean,任何使用@ReadOperation@WriteOperation@DeleteOperation注释的方法将自动在JMX上公开,并在Web应用程序中也通过HTTP公开。端点可以通过Jersey、Spring MVC或Spring WebFlux在HTTP上公开。如果Jersey和Spring MVC都可用,则使用Spring MVC。

以下示例公开了一个返回自定义对象的读取操作:

Java
@ReadOperation
public CustomData getData() {
    return new CustomData("test", 5);
}
Kotlin
@ReadOperation
fun getData(): CustomData {
    return CustomData("test", 5)
}

您还可以通过使用@JmxEndpoint@WebEndpoint编写特定于技术的端点。这些端点受限于各自的技术。例如,@WebEndpoint仅通过HTTP公开,而不通过JMX公开。

您可以通过使用@EndpointWebExtension@EndpointJmxExtension编写特定于技术的扩展。这些注释允许您提供特定于技术的操作,以增强现有端点。

最后,如果您需要访问特定于Web框架的功能,您可以实现Servlet或Spring的@Controller@RestController端点,但这会导致它们无法通过JMX访问,或者在使用不同的Web框架时无法使用。

2.8.1. 接收输入

端点上的操作通过其参数接收输入。在Web上公开时,这些参数的值来自URL的查询参数和JSON请求体。在JMX上公开时,参数被映射到MBean的操作的参数。参数默认是必需的。可以通过使用@javax.annotation.Nullable@org.springframework.lang.Nullable对其进行标注,使其变为可选参数。

您可以将JSON请求体中的每个根属性映射到端点的参数。考虑以下JSON请求体:

{
    "name": "test",
    "counter": 42
}

您可以使用此来调用一个接受String nameint counter参数的写入操作,如以下示例所示:

Java
@WriteOperation
public void updateData(String name, int counter) {
    // injects "test" and 42
}
Kotlin
@WriteOperation
fun updateData(name: String?, counter: Int) {
    // injects "test" and 42
}
由于端点是技术无关的,方法签名中只能指定简单类型。特别是,声明一个具有namecounter属性的CustomData类型的单个参数是不受支持的。
为了让输入映射到操作方法的参数,实现端点的Java代码应该使用-parameters进行编译,实现端点的Kotlin代码应该使用-java-parameters进行编译。如果您使用Spring Boot的Gradle插件或者使用Maven和spring-boot-starter-parent,这将自动发生。
输入类型转换

传递给端点操作方法的参数,如果必要,会自动转换为所需类型。在调用操作方法之前,通过使用ApplicationConversionService的实例以及任何使用@EndpointConverter标注的ConverterGenericConverter bean,将在JMX或HTTP上接收的输入转换为所需类型。

2.8.2. 自定义Web端点

@Endpoint@WebEndpoint@EndpointWebExtension上的操作会自动通过Jersey、Spring MVC或Spring WebFlux在HTTP上公开。如果Jersey和Spring MVC都可用,则使用Spring MVC。

Web端点请求谓词

为每个在Web端点上操作生成一个请求谓词。

路径

谓词的路径由端点的ID和Web端点的基本路径确定。默认的基本路径是/actuator。例如,具有ID为sessions的端点在谓词中使用/actuator/sessions作为其路径。

您可以通过使用@Selector注释操作方法的一个或多个参数来进一步自定义路径。这样的参数将作为路径变量添加到路径谓词中。当调用端点操作时,变量的值将传递到操作方法中。如果要捕获所有剩余的路径元素,可以将@Selector(Match=ALL_REMAINING)添加到最后一个参数,并将其设置为与String[]兼容的类型。

HTTP方法

谓词的HTTP方法由操作类型确定,如下表所示:

操作 HTTP方法

@ReadOperation

GET

@WriteOperation

POST

@DeleteOperation

DELETE

消费

对于使用请求体的@WriteOperation(HTTP POST),谓词的consumes子句为application/vnd.spring-boot.actuator.v2+json, application/json。对于所有其他操作,consumes子句为空。

生成

谓词的produces子句可以由@DeleteOperation@ReadOperation@WriteOperation注释的produces属性确定。该属性是可选的。如果未使用,produces子句将自动确定。

如果操作方法返回voidVoid,则produces子句为空。如果操作方法返回org.springframework.core.io.Resource,则produces子句为application/octet-stream。对于所有其他操作,produces子句为application/vnd.spring-boot.actuator.v2+json, application/json

Web端点响应状态

端点操作的默认响应状态取决于操作类型(读取、写入或删除)以及操作返回的内容(如果有)。

如果@ReadOperation返回一个值,则响应状态将为200(OK)。如果不返回值,则响应状态将为404(未找到)。

如果@WriteOperation@DeleteOperation返回一个值,则响应状态将为200(OK)。如果不返回值,则响应状态将为204(无内容)。

如果调用操作时缺少必需参数或参数无法转换为所需类型,则不会调用操作方法,响应状态将为400(错误请求)。

Web端点范围请求

您可以使用HTTP范围请求来请求HTTP资源的一部分。在使用Spring MVC或Spring Web Flux时,返回org.springframework.core.io.Resource的操作会自动支持范围请求。

在使用Jersey时不支持范围请求。
Web端点安全性

Web端点或特定于Web的端点扩展上的操作可以接收当前的java.security.Principalorg.springframework.boot.actuate.endpoint.SecurityContext作为方法参数。前者通常与@Nullable一起使用,以为经过身份验证和未经身份验证的用户提供不同的行为。后者通常用于通过使用其isUserInRole(String)方法执行授权检查。

2.8.3. Servlet端点

通过实现一个使用@ServletEndpoint注释的类并实现Supplier<EndpointServlet>,可以将Servlet公开为端点。Servlet端点提供与Servlet容器的更深度集成,但牺牲了可移植性。它们旨在用于将现有Servlet公开为端点。对于新端点,应尽可能首选@Endpoint@WebEndpoint注释。

2.8.4. 控制器端点

您可以使用@ControllerEndpoint@RestControllerEndpoint来实现仅由Spring MVC或Spring WebFlux公开的端点。方法通过使用Spring MVC和Spring WebFlux的标准注释(如@RequestMapping@GetMapping)进行映射,端点的ID被用作路径的前缀。控制器端点提供与Spring的Web框架更深度的集成,但牺牲了可移植性。应尽可能首选@Endpoint@WebEndpoint注释。

2.9. 健康信息

您可以使用健康信息来检查正在运行的应用程序的状态。监控软件通常会使用它来在生产系统宕机时提醒某人。由health端点公开的信息取决于management.endpoint.health.show-detailsmanagement.endpoint.health.show-components属性,这些属性可以配置为以下值之一:

名称 描述

never

从不显示详细信息。

when-authorized

仅向授权用户显示详细信息。可以使用management.endpoint.health.roles配置授权角色。

always

向所有用户显示详细信息。

默认值为never。当用户在端点的一个或多个角色中时,被视为已授权。如果端点没有配置角色(默认情况下),则认为所有经过身份验证的用户都被授权。您可以使用management.endpoint.health.roles属性配置角色。

如果您已经保护了应用程序并希望使用always,则您的安全配置必须允许经过身份验证和未经身份验证的用户访问健康端点。

健康信息是从HealthContributorRegistry的内容中收集的(默认情况下,从您的ApplicationContext中定义的所有HealthContributor实例)。Spring Boot包括许多自动配置的HealthContributors,您也可以编写自己的。

HealthContributor可以是HealthIndicatorCompositeHealthContributorHealthIndicator提供实际的健康信息,包括StatusCompositeHealthContributor提供其他HealthContributors的组合。总体而言,贡献者形成树结构,以表示整个系统的健康状况。

默认情况下,最终系统健康状态由StatusAggregator推导出来,它根据有序状态列表对每个HealthIndicator的状态进行排序。排序列表中的第一个状态被用作整体健康状态。如果没有HealthIndicator返回StatusAggregator已知的状态,则使用UNKNOWN状态。

您可以使用HealthContributorRegistry在运行时注册和注销健康指标。

2.9.1. 自动配置的HealthIndicators

在适当的情况下,Spring Boot会自动配置以下表中列出的HealthIndicators。您还可以通过配置management.health.key.enabled来启用或禁用选定的指标,其中key列在以下表中:

名称 描述

cassandra

CassandraDriverHealthIndicator

检查Cassandra数据库是否正常。

couchbase

CouchbaseHealthIndicator

检查Couchbase集群是否正常。

db

DataSourceHealthIndicator

检查是否可以连接到DataSource

diskspace

DiskSpaceHealthIndicator

检查磁盘空间是否充足。

elasticsearch

ElasticsearchRestClientHealthIndicator

检查Elasticsearch集群是否正常。

hazelcast

HazelcastHealthIndicator

检查Hazelcast服务器是否正常。

influxdb

InfluxDbHealthIndicator

检查InfluxDB服务器是否正常。

jms

JmsHealthIndicator

检查JMS代理是否正常。

ldap

LdapHealthIndicator

检查LDAP服务器是否正常。

mail

MailHealthIndicator

检查邮件服务器是否正常。

mongo

MongoHealthIndicator

检查Mongo数据库是否正常。

neo4j

Neo4jHealthIndicator

检查Neo4j数据库是否正常。

ping

PingHealthIndicator

始终响应UP

rabbit

RabbitHealthIndicator

检查Rabbit服务器是否正常。

redis

RedisHealthIndicator

检查Redis服务器是否正常。

您可以通过设置management.health.defaults.enabled属性来禁用所有这些指标。

还有其他可用的HealthIndicators,但默认情况下未启用:

名称 描述

livenessstate

LivenessStateHealthIndicator

公开“Liveness”应用程序可用性状态。

readinessstate

ReadinessStateHealthIndicator

公开“Readiness”应用程序可用性状态。

2.9.2. 编写自定义健康指标

要提供自定义健康信息,您可以注册实现 HealthIndicator 接口的 Spring bean。您需要提供 health() 方法的实现并返回一个 Health 响应。 Health 响应应包含一个状态,并可以选择性地包含要显示的附加详细信息。以下代码显示了一个示例 HealthIndicator 实现:

Java
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class MyHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        int errorCode = check();
        if (errorCode != 0) {
            return Health.down().withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }

    private int check() {
        // 执行一些特定的健康检查
        return ...
    }

}
Kotlin
import org.springframework.boot.actuate.health.Health
import org.springframework.boot.actuate.health.HealthIndicator
import org.springframework.stereotype.Component

@Component
class MyHealthIndicator : HealthIndicator {

    override fun health(): Health {
        val errorCode = check()
        if (errorCode != 0) {
            return Health.down().withDetail("Error Code", errorCode).build()
        }
        return Health.up().build()
    }

    private fun check(): Int {
        // 执行一些特定的健康检查
        return  ...
    }

}
给定 HealthIndicator 的标识符是没有 HealthIndicator 后缀的 bean 名称。在上面的示例中,健康信息可在名为 my 的条目中找到。
健康指标通常通过 HTTP 调用,并需要在任何连接超时之前做出响应。如果健康指标的响应时间超过 10 秒,Spring Boot 将记录警告消息。如果要配置此阈值,可以使用 management.endpoint.health.logging.slow-indicator-threshold 属性。

除了 Spring Boot 预定义的 Status 类型外,Health 还可以返回表示新系统状态的自定义 Status。在这种情况下,您还需要提供 StatusAggregator 接口的自定义实现,或者必须使用 management.endpoint.health.status.order 配置属性配置默认实现。

例如,假设您的一个 HealthIndicator 实现中使用了一个代码为 FATAL 的新 Status。要配置严重性顺序,请将以下属性添加到应用程序属性中:

Properties
management.endpoint.health.status.order=fatal,down,out-of-service,unknown,up
Yaml
management:
  endpoint:
    health:
      status:
        order: "fatal,down,out-of-service,unknown,up"

响应中的 HTTP 状态代码反映了整体健康状态。默认情况下,OUT_OF_SERVICEDOWN 映射到 503。包括 UP 在内的任何未映射的健康状态都映射到 200。如果通过 HTTP 访问健康端点,您可能还希望注册自定义状态映射。配置自定义映射会禁用 DOWNOUT_OF_SERVICE 的默认映射。如果要保留默认映射,必须显式配置它们,以及任何自定义映射。例如,以下属性将 FATAL 映射到 503(服务不可用),并保留 DOWNOUT_OF_SERVICE 的默认映射:

Properties
management.endpoint.health.status.http-mapping.down=503
management.endpoint.health.status.http-mapping.fatal=503
management.endpoint.health.status.http-mapping.out-of-service=503
Yaml
management:
  endpoint:
    health:
      status:
        http-mapping:
          down: 503
          fatal: 503
          out-of-service: 503
如果需要更多控制,可以定义自己的 HttpCodeStatusMapper bean。

以下表格显示了内置状态的默认状态映射:

状态 映射

DOWN

SERVICE_UNAVAILABLE503

OUT_OF_SERVICE

SERVICE_UNAVAILABLE503

UP

默认情况下没有映射,因此 HTTP 状态为 200

UNKNOWN

默认情况下没有映射,因此 HTTP 状态为 200

2.9.3. 响应式健康指标

对于使用Spring WebFlux等响应式应用程序,ReactiveHealthContributor提供了一个非阻塞的合同来获取应用程序健康状态。类似于传统的HealthContributor,健康信息是从ReactiveHealthContributorRegistry的内容中收集的(默认情况下,从您的ApplicationContext中定义的所有HealthContributorReactiveHealthContributor实例)。不检查反应式API的常规HealthContributors在弹性调度程序上执行。

在响应式应用程序中,您应该使用ReactiveHealthContributorRegistry在运行时注册和注销健康指标。如果需要注册常规的HealthContributor,应该使用ReactiveHealthContributor#adapt进行包装。

要从响应式API提供自定义健康信息,您可以注册实现ReactiveHealthIndicator接口的Spring bean。以下代码显示了一个示例ReactiveHealthIndicator实现:

Java
import reactor.core.publisher.Mono;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {

    @Override
    public Mono<Health> health() {
        return doHealthCheck().onErrorResume((exception) ->
            Mono.just(new Health.Builder().down(exception).build()));
    }

    private Mono<Health> doHealthCheck() {
        // 执行一些特定的健康检查
        return ...
    }

}
Kotlin
import org.springframework.boot.actuate.health.Health
import org.springframework.boot.actuate.health.ReactiveHealthIndicator
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono

@Component
class MyReactiveHealthIndicator : ReactiveHealthIndicator {

    override fun health(): Mono<Health> {
        return doHealthCheck()!!.onErrorResume { exception: Throwable? ->
            Mono.just(Health.Builder().down(exception).build())
        }
    }

    private fun doHealthCheck(): Mono<Health>? {
        // 执行一些特定的健康检查
        return  ...
    }

}
要自动处理错误,请考虑扩展自AbstractReactiveHealthIndicator

2.9.4. 自动配置的响应式健康指标

在适当的情况下,Spring Boot会自动配置以下ReactiveHealthIndicators

名称 描述

cassandra

CassandraDriverReactiveHealthIndicator

检查Cassandra数据库是否正常。

couchbase

CouchbaseReactiveHealthIndicator

检查Couchbase集群是否正常。

elasticsearch

ElasticsearchReactiveHealthIndicator

检查Elasticsearch集群是否正常。

mongo

MongoReactiveHealthIndicator

检查Mongo数据库是否正常。

neo4j

Neo4jReactiveHealthIndicator

检查Neo4j数据库是否正常。

redis

RedisReactiveHealthIndicator

检查Redis服务器是否正常。

如有必要,响应式指标会替换常规指标。此外,任何未明确处理的HealthIndicator会自动包装。

2.9.5. 健康分组

有时将健康指标组织成您可以用于不同目的的组是很有用的。

要创建健康指标组,您可以使用management.endpoint.health.group.<name>属性,并指定要包含排除的健康指标ID列表。例如,要创建仅包含数据库指标的组,您可以定义如下内容:

属性
management.endpoint.health.group.custom.include=db
Yaml
management:
  endpoint:
    health:
      group:
        custom:
          include: "db"

然后,您可以通过访问localhost:8080/actuator/health/custom来检查结果。

类似地,要创建一个组,从该组中排除数据库指标并包含所有其他指标,您可以定义如下内容:

属性
management.endpoint.health.group.custom.exclude=db
Yaml
management:
  endpoint:
    health:
      group:
        custom:
          exclude: "db"

默认情况下,如果健康组包含或排除不存在的健康指标,则启动将失败。要禁用此行为,请将management.endpoint.health.validate-group-membership设置为false

默认情况下,组会继承与系统健康相同的StatusAggregatorHttpCodeStatusMapper设置。但是,您也可以在每个组上定义这些设置。如果需要,还可以覆盖show-detailsroles属性:

属性
management.endpoint.health.group.custom.show-details=when-authorized
management.endpoint.health.group.custom.roles=admin
management.endpoint.health.group.custom.status.order=fatal,up
management.endpoint.health.group.custom.status.http-mapping.fatal=500
management.endpoint.health.group.custom.status.http-mapping.out-of-service=500
Yaml
management:
  endpoint:
    health:
      group:
        custom:
          show-details: "when-authorized"
          roles: "admin"
          status:
            order: "fatal,up"
            http-mapping:
              fatal: 500
              out-of-service: 500
如果需要为组注册自定义StatusAggregatorHttpCodeStatusMapper bean,则可以使用@Qualifier("groupname")

健康组还可以包含/排除CompositeHealthContributor。您还可以仅包含/排除CompositeHealthContributor的某个组件。可以通过组件的完全限定名称来执行此操作,如下所示:

management.endpoint.health.group.custom.include="test/primary"
management.endpoint.health.group.custom.exclude="test/primary/b"

在上面的示例中,custom组将包含名称为primaryHealthContributor,该组件是test的一个组件。在这里,primary本身是一个组合,名称为bHealthContributor将从custom组中排除。

健康组可以在主端口或管理端口的附加路径上提供。这在云环境(如Kubernetes)中很有用,因为通常会为执行器端点使用单独的管理端口以提高安全性。使用单独的端口可能导致健康检查不可靠,因为即使健康检查成功,主应用程序可能也无法正常工作。可以如下配置健康组的附加路径:

management.endpoint.health.group.live.additional-path="server:/healthz"

这将使live健康组在主服务器端口上的/healthz路径上可用。前缀是必需的,必须是server:(表示主服务器端口)或management:(表示管理端口,如果已配置)。路径必须是单个路径段。

2.9.6. 数据源健康

DataSource健康指标显示标准数据源和路由数据源bean的健康状况。路由数据源的健康状况包括其每个目标数据源的健康状况。在健康端点的响应中,路由数据源的每个目标都使用其路由键命名。如果不希望在指标输出中包含路由数据源,请将management.health.db.ignore-routing-data-sources设置为true

2.10. Kubernetes探针

部署在Kubernetes上的应用程序可以使用容器探针提供关于其内部状态的信息。根据您的Kubernetes配置,kubelet调用这些探针并根据结果做出反应。

默认情况下,Spring Boot管理您的应用程序可用状态。如果部署在Kubernetes环境中,执行器会从ApplicationAvailability接口收集“存活性”和“就绪性”信息,并在专用的健康指标中使用这些信息: LivenessStateHealthIndicatorReadinessStateHealthIndicator。这些指标显示在全局健康端点("/actuator/health")上。它们也通过使用健康组作为单独的HTTP探针公开: "/actuator/health/liveness""/actuator/health/readiness"

然后,您可以使用以下端点信息配置您的Kubernetes基础设施:

livenessProbe:
  httpGet:
    path: "/actuator/health/liveness"
    port: <actuator-port>
  failureThreshold: ...
  periodSeconds: ...

readinessProbe:
  httpGet:
    path: "/actuator/health/readiness"
    port: <actuator-port>
  failureThreshold: ...
  periodSeconds: ...
<actuator-port> 应设置为执行器端点可用的端口。它可以是主Web服务器端口,也可以是单独的管理端口,如果已设置"management.server.port"属性。

这些健康组仅在应用程序运行在Kubernetes环境中时自动启用。您可以通过使用management.endpoint.health.probes.enabled配置属性在任何环境中启用它们。

如果应用程序启动时间超过配置的存活性周期,Kubernetes会提到"startupProbe"作为可能的解决方案。一般来说,在这里不一定需要"startupProbe",因为"readinessProbe"会在所有启动任务完成之前失败。这意味着您的应用程序在准备就绪之前不会接收流量。但是,如果您的应用程序启动时间很长,请考虑使用"startupProbe",以确保Kubernetes在应用程序启动过程中不会终止您的应用程序。请参阅描述应用程序生命周期中探针行为的部分。

如果您的执行器端点部署在单独的管理上下文中,则端点不会使用与主应用程序相同的Web基础设施(端口、连接池、框架组件)。在这种情况下,即使主应用程序无法正常工作(例如,无法接受新连接),探针检查也可能成功。因此,将livenessreadiness健康组提供在主服务器端口上是一个好主意。这可以通过设置以下属性来实现:

management.endpoint.health.probes.add-additional-paths=true

这将使liveness组在主服务器端口上的/livez可用,将readiness组在主服务器端口上的/readyz可用。可以使用每个组上的additional-path属性自定义路径,有关详细信息,请参阅健康组

2.10.1. 使用Kubernetes探针检查外部状态

执行器将“存活性”和“就绪性”探针配置为健康组。这意味着所有健康组功能对它们都是可用的。例如,您可以配置额外的健康指标:

属性
management.endpoint.health.group.readiness.include=readinessState,customCheck
Yaml
management:
  endpoint:
    health:
      group:
        readiness:
          include: "readinessState,customCheck"

默认情况下,Spring Boot不向这些组添加其他健康指标。

“存活性”探针不应依赖于外部系统的健康检查。如果应用程序的存活状态出现问题,Kubernetes会尝试通过重新启动应用程序实例来解决该问题。这意味着如果外部系统(如数据库、Web API或外部缓存)出现故障,Kubernetes可能会重新启动所有应用程序实例并导致级联故障。

至于“就绪性”探针,应用程序开发人员必须谨慎选择检查外部系统。因此,Spring Boot不在就绪性探针中包含任何额外的健康检查。如果应用程序实例的就绪状态不可用,Kubernetes不会将流量路由到该实例。某些外部系统可能不会被应用程序实例共享,在这种情况下,它们可以包含在就绪性探针中。其他外部系统可能对应用程序不是必需的(应用程序可能具有熔断器和回退机制),在这种情况下,它们绝对不应该包含在内。不幸的是,所有应用程序实例共享的外部系统很常见,您必须做出判断:将其包含在就绪性探针中,并期望应用程序在外部服务不可用时被停止,或者将其排除,并处理堆栈更高处的故障,可能通过在调用方使用熔断器来实现。

如果应用程序的所有实例都不可用,具有type=ClusterIPNodePort的Kubernetes服务不会接受任何传入连接。没有HTTP错误响应(例如503等),因为没有连接。具有type=LoadBalancer的服务可能会或可能不会接受连接,这取决于提供程序。具有显式入口的服务也会以取决于实现的方式做出响应 - 入口服务本身必须决定如何处理下游的“连接被拒绝”。在负载均衡器和入口的情况下,HTTP 503是很可能的。

此外,如果应用程序使用Kubernetes自动缩放,它可能会根据其自动缩放器配置对被从负载均衡器中移除的应用程序做出不同的反应。

2.10.2. 应用生命周期和探针状态

与应用生命周期保持一致是Kubernetes探针支持的一个重要方面。AvailabilityState(这是应用程序的内存中的内部状态)与实际探针之间存在显著差异(它公开该状态)。根据应用程序生命周期的阶段,探针可能不可用。

Spring Boot在启动和关闭过程中发布应用程序事件,探针可以监听这些事件并公开AvailabilityState信息。

以下表格显示了AvailabilityState和不同阶段的HTTP连接器状态。

当Spring Boot应用程序启动时:

启动阶段 存活状态 就绪状态 HTTP服务器 备注

启动中

故障

拒绝流量

未启动

Kubernetes检查“存活性”探针,如果时间过长,则重新启动应用程序。

已启动

正确

拒绝流量

拒绝请求

应用程序上下文已刷新。应用程序执行启动任务,但尚未接收流量。

就绪

正确

接受流量

接受请求

启动任务已完成。应用程序正在接收流量。

当Spring Boot应用程序关闭时:

关闭阶段 存活状态 就绪状态 HTTP服务器 备注

运行中

正确

接受流量

接受请求

已请求关闭。

优雅关闭

正确

拒绝流量

拒绝新请求

如果启用,优雅关闭会处理正在处理的请求

关闭完成

N/A

N/A

服务器已关闭

应用程序上下文已关闭,应用程序已关闭。

有关Kubernetes部署的更多信息,请参阅Kubernetes容器生命周期部分

2.11. 应用信息

应用信息公开了从您的ApplicationContext中定义的所有InfoContributor bean收集的各种信息。Spring Boot包含许多自动配置的InfoContributor bean,您也可以编写自己的。

2.11.1. 自动配置的InfoContributors

在适当的情况下,Spring会自动配置以下InfoContributor bean:

ID 名称 描述 先决条件

build

BuildInfoContributor

公开构建信息。

一个META-INF/build-info.properties资源。

env

EnvironmentInfoContributor

公开以info.开头的Environment属性。

无。

git

GitInfoContributor

公开git信息。

一个git.properties资源。

java

JavaInfoContributor

公开Java运行时信息。

无。

os

OsInfoContributor

公开操作系统信息。

无。

个体贡献者是否启用由其management.info.<id>.enabled属性控制。不同的贡献者对于此属性有不同的默认值,取决于它们的先决条件和所公开信息的性质。

没有指示它们应该启用的先决条件,envjavaos贡献者默认情况下是禁用的。可以通过将其management.info.<id>.enabled属性设置为true来启用每个贡献者。

buildgit信息贡献者默认情况下是启用的。可以通过将其management.info.<id>.enabled属性设置为false来禁用每个贡献者。或者,要禁用默认情况下通常启用的每个贡献者,请将management.info.defaults.enabled属性设置为false

2.11.2. 自定义应用信息

当启用env贡献者时,您可以通过设置info.* Spring属性来自定义info端点公开的数据。所有Environment属性在info键下都会自动公开。例如,您可以将以下设置添加到您的application.properties文件中:

属性
info.app.encoding=UTF-8
info.app.java.source=17
info.app.java.target=17
Yaml
info:
  app:
    encoding: "UTF-8"
    java:
      source: "17"
      target: "17"

您可以在构建时扩展信息属性,而不是硬编码这些值。

假设您使用Maven,您可以将前面的示例重写如下:

Yaml
info:
  app:
    encoding: "@project.build.sourceEncoding@"
    java:
      source: "@java.version@"
      target: "@java.version@"

2.11.3. Git提交信息

info端点的另一个有用功能是在构建项目时发布有关您的git源代码库状态的信息的能力。如果有一个GitProperties bean可用,您可以使用info端点来公开这些属性。

如果在类路径的根目录下有一个git.properties文件,则会自动配置一个GitProperties bean。有关更多详细信息,请参阅"如何生成git信息"。

默认情况下,如果存在,端点会公开git.branchgit.commit.idgit.commit.time属性。如果您不希望在端点响应中包含这些属性中的任何一个,它们需要从git.properties文件中排除。如果要显示完整的git信息(即git.properties的完整内容),请使用management.info.git.mode属性,如下所示:

属性
management.info.git.mode=full
Yaml
management:
  info:
    git:
      mode: "full"

要完全禁用info端点中的git提交信息,请将management.info.git.enabled属性设置为false,如下所示:

属性
management.info.git.enabled=false
Yaml
management:
  info:
    git:
      enabled: false

2.11.4. 构建信息

如果存在一个BuildProperties bean,则info端点还可以发布有关构建的信息。如果类路径中存在META-INF/build-info.properties文件,则会发生这种情况。

Maven和Gradle插件都可以生成该文件。有关更多详细信息,请参见"如何生成构建信息"。

2.11.5. Java 信息

info端点发布有关您的Java运行时环境的信息,请参见JavaInfo以获取更多详细信息。

2.11.6. 操作系统信息

info端点发布有关您的操作系统的信息,请参见OsInfo以获取更多详细信息。

2.11.7. 编写自定义 InfoContributors

要提供自定义应用程序信息,您可以注册实现InfoContributor接口的Spring bean。

以下示例提供了一个带有单个值的example条目:

Java
import java.util.Collections;

import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;

@Component
public class MyInfoContributor implements InfoContributor {

    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("example", Collections.singletonMap("key", "value"));
    }

}
Kotlin
import org.springframework.boot.actuate.info.Info
import org.springframework.boot.actuate.info.InfoContributor
import org.springframework.stereotype.Component
import java.util.Collections

@Component
class MyInfoContributor : InfoContributor {

    override fun contribute(builder: Info.Builder) {
        builder.withDetail("example", Collections.singletonMap("key", "value"))
    }

}

如果访问info端点,您应该看到包含以下附加条目的响应:

{
    "example": {
        "key" : "value"
    }
}

3. 监控和管理通过HTTP

如果您正在开发一个Web应用程序,Spring Boot Actuator会自动配置所有已启用的端点以通过HTTP公开。默认约定是使用端点的id作为URL路径的前缀/actuator。例如,health被公开为/actuator/health

Actuator在Spring MVC、Spring WebFlux和Jersey中得到原生支持。如果Jersey和Spring MVC都可用,则使用Spring MVC。
为了获得正确的JSON响应,Jackson是一个必需的依赖,如API文档中所述(HTMLPDF)。

3.1. 自定义管理端点路径

有时,自定义管理端点的前缀很有用。例如,您的应用程序可能已经使用/actuator用于其他目的。您可以使用management.endpoints.web.base-path属性来更改管理端点的前缀,如下例所示:

属性
management.endpoints.web.base-path=/manage
Yaml
management:
  endpoints:
    web:
      base-path: "/manage"

上述的application.properties示例将端点从/actuator/{id}更改为/manage/{id}(例如,/manage/info)。

除非已配置管理端口通过不同的HTTP端口公开端点,否则management.endpoints.web.base-path是相对于server.servlet.context-path(对于Servlet Web应用程序)或spring.webflux.base-path(对于响应式Web应用程序)。如果配置了management.server.portmanagement.endpoints.web.base-path是相对于management.server.base-path

如果要将端点映射到不同的路径,可以使用management.endpoints.web.path-mapping属性。

以下示例将/actuator/health重新映射为/healthcheck

属性
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=healthcheck
Yaml
management:
  endpoints:
    web:
      base-path: "/"
      path-mapping:
        health: "healthcheck"

3.2. 自定义管理服务器端口

通过默认的HTTP端口公开管理端点是云部署的明智选择。但是,如果您的应用程序在自己的数据中心内运行,您可能更喜欢通过不同的HTTP端口公开端点。

您可以设置management.server.port属性来更改HTTP端口,如下例所示:

属性
management.server.port=8081
Yaml
management:
  server:
    port: 8081
在Cloud Foundry上,默认情况下,应用程序仅接收HTTP和TCP路由的8080端口的请求。如果要在Cloud Foundry上使用自定义管理端口,需要显式设置应用程序的路由以将流量转发到自定义端口。

3.3. 配置管理特定的SSL

当配置为使用自定义端口时,您还可以使用各种management.server.ssl.*属性来配置管理服务器的SSL。例如,通过以下属性设置,可以让管理服务器通过HTTP可用,而主应用程序使用HTTPS:

属性
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:store.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=false
Yaml
server:
  port: 8443
  ssl:
    enabled: true
    key-store: "classpath:store.jks"
    key-password: "secret"
management:
  server:
    port: 8080
    ssl:
      enabled: false

或者,主服务器和管理服务器都可以使用SSL,但使用不同的密钥存储库,如下所示:

属性
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:main.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=true
management.server.ssl.key-store=classpath:management.jks
management.server.ssl.key-password=secret
Yaml
server:
  port: 8443
  ssl:
    enabled: true
    key-store: "classpath:main.jks"
    key-password: "secret"
management:
  server:
    port: 8080
    ssl:
      enabled: true
      key-store: "classpath:management.jks"
      key-password: "secret"

3.4. 自定义管理服务器地址

您可以通过设置management.server.address属性来自定义管理端点可用的地址。这样做可以很有用,如果您只想监听内部或面向运维的网络,或者只想监听来自localhost的连接。

只有当端口与主服务器端口不同时,才能监听不同的地址。

以下示例的application.properties不允许远程管理连接:

属性
management.server.port=8081
management.server.address=127.0.0.1
Yaml
management:
  server:
    port: 8081
    address: "127.0.0.1"

3.5. 禁用HTTP端点

如果不想通过HTTP公开端点,可以将管理端口设置为-1,如下例所示:

属性
management.server.port=-1
Yaml
management:
  server:
    port: -1

您也可以通过使用management.endpoints.web.exposure.exclude属性来实现这一点,如下例所示:

属性
management.endpoints.web.exposure.exclude=*
Yaml
management:
  endpoints:
    web:
      exposure:
        exclude: "*"

4. 监控和管理JMX

Java管理扩展(JMX)提供了一种标准机制来监控和管理应用程序。默认情况下,此功能未启用。您可以通过将spring.jmx.enabled配置属性设置为true来启用它。Spring Boot将最适合的MBeanServer公开为一个ID为mbeanServer的bean。任何使用Spring JMX注解(@ManagedResource@ManagedAttribute@ManagedOperation)注释的bean都会被公开到其中。

如果您的平台提供了标准的MBeanServer,Spring Boot将使用该平台,并在必要时默认为VM MBeanServer。如果所有尝试都失败,将创建一个新的MBeanServer

查看JmxAutoConfiguration类以获取更多详细信息。

默认情况下,Spring Boot还将管理端点作为JMX MBeans公开在org.springframework.boot域下。要完全控制在JMX域中的端点注册,请考虑注册自己的EndpointObjectNameFactory实现。

4.1. 自定义MBean名称

MBean的名称通常是从端点的id生成的。例如,health端点公开为org.springframework.boot:type=Endpoint,name=Health

如果您的应用程序包含多个Spring ApplicationContext,可能会发现名称冲突。为解决此问题,您可以将spring.jmx.unique-names属性设置为true,以确保MBean名称始终是唯一的。

您还可以自定义端点公开的JMX域。以下设置显示了在application.properties中执行此操作的示例:

属性
spring.jmx.unique-names=true
management.endpoints.jmx.domain=com.example.myapp
Yaml
spring:
  jmx:
    unique-names: true
management:
  endpoints:
    jmx:
      domain: "com.example.myapp"

4.2. 禁用JMX端点

如果您不希望通过JMX公开端点,可以将management.endpoints.jmx.exposure.exclude属性设置为*,如以下示例所示:

属性
management.endpoints.jmx.exposure.exclude=*
Yaml
management:
  endpoints:
    jmx:
      exposure:
        exclude: "*"

5. 可观测性

可观测性是指从外部观察运行中系统的内部状态的能力。它由日志、度量和跟踪三个支柱组成。

对于度量和跟踪,Spring Boot使用 Micrometer Observation。要创建自己的观测(将导致度量和跟踪),您可以注入一个 ObservationRegistry

import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;

import org.springframework.stereotype.Component;

@Component
public class MyCustomObservation {

    private final ObservationRegistry observationRegistry;

    public MyCustomObservation(ObservationRegistry observationRegistry) {
        this.observationRegistry = observationRegistry;
    }

    public void doSomething() {
        Observation.createNotStarted("doSomething", this.observationRegistry)
            .lowCardinalityKeyValue("locale", "en-US")
            .highCardinalityKeyValue("userId", "42")
            .observe(() -> {
                // 在这里执行业务逻辑
            });
    }

}
低基数标签将添加到度量和跟踪中,而高基数标签仅添加到跟踪中。

类型为 ObservationPredicateGlobalObservationConventionObservationFilterObservationHandler 的 Bean 将自动注册到 ObservationRegistry 上。您还可以注册任意数量的 ObservationRegistryCustomizer Bean 来进一步配置注册表。

可观测性支持依赖于 Context Propagation 库,用于在线程和响应式管道之间转发当前观测。默认情况下,ThreadLocal 值不会自动在响应式操作符中恢复。此行为由 spring.reactor.context-propagation 属性控制,可以将其设置为 auto 以启用自动传播。

有关观测的更多详细信息,请参阅 Micrometer Observation 文档

JDBC 的可观测性可以使用单独的项目进行配置。 Datasource Micrometer 项目 提供了一个 Spring Boot starter,在调用 JDBC 操作时自动创建观测。在 参考文档 中了解更多信息。
R2DBC 的可观测性已内置在 Spring Boot 中。要启用它,请将 io.r2dbc:r2dbc-proxy 依赖项添加到您的项目中。

5.1. 公共标签

公共标签通常用于对操作环境进行维度下钻,例如主机、实例、区域、堆栈等。公共标签作为低基数标签应用于所有观测中,并且可以进行配置,如下例所示:

属性
management.observations.key-values.region=us-east-1
management.observations.key-values.stack=prod
Yaml
management:
  observations:
    key-values:
      region: "us-east-1"
      stack: "prod"

上述示例将向所有观测添加 regionstack 标签,其值分别为 us-east-1prod

5.2. 阻止观测

如果您希望阻止某些观测被报告,可以使用 management.observations.enable 属性:

属性
management.observations.enable.denied.prefix=false
management.observations.enable.another.denied.prefix=false
Yaml
management:
  observations:
    enable:
      denied:
        prefix: false
      another:
        denied:
          prefix: false

上述示例将阻止所有名称以 denied.prefixanother.denied.prefix 开头的观测。

如果要阻止 Spring Security 报告观测,请将属性 management.observations.enable.spring.security 设置为 false

如果需要更多对观测阻止的控制,可以注册类型为 ObservationPredicate 的 Bean。只有当所有 ObservationPredicate Bean 对该观测返回 true 时,才会报告观测。

import io.micrometer.observation.Observation.Context;
import io.micrometer.observation.ObservationPredicate;

import org.springframework.stereotype.Component;

@Component
class MyObservationPredicate implements ObservationPredicate {

    @Override
    public boolean test(String name, Context context) {
        return !name.contains("denied");
    }

}

上述示例将阻止所有名称包含 "denied" 的观测。

5.3. OpenTelemetry 支持

Spring Boot 的执行器模块包含对 OpenTelemetry 的基本支持。

它提供了一个类型为 OpenTelemetry 的 Bean,如果应用程序上下文中存在类型为 SdkTracerProviderContextPropagatorsSdkLoggerProviderSdkMeterProvider 的 Bean,则它们将自动注册。此外,它提供了一个 Resource Bean。自动配置的 Resource 的属性可以通过 management.opentelemetry.resource-attributes 配置属性进行配置。如果您定义了自己的 Resource Bean,则不再适用此配置。

Spring Boot 不提供 OpenTelemetry 指标或日志的自动配置。仅当与 Micrometer Tracing 一起使用时,才会自动配置 OpenTelemetry 跟踪。

接下来的章节将提供有关日志、度量和跟踪的更多详细信息。

5.4. Micrometer 观测注解支持

要启用对 @Timed@Counted@MeterTag@NewSpan 等注解的度量和跟踪扫描,您需要将 management.observations.annotations.enabled 属性设置为 true。此功能由 Micrometer 直接支持,请参阅 MicrometerMicrometer Tracing 参考文档。

6. 日志记录器

Spring Boot Actuator包括在运行时查看和配置应用程序的日志级别的功能。您可以查看整个列表或单个记录器的配置,其中包括显式配置的日志级别以及日志框架赋予其的有效日志级别。这些级别可以是以下之一:

  • TRACE

  • DEBUG

  • INFO

  • WARN

  • ERROR

  • FATAL

  • OFF

  • null

null表示没有显式配置。

6.1. 配置记录器

要配置给定的记录器,请向资源的URI发送部分实体,如下例所示:

{
    "configuredLevel": "DEBUG"
}
要“重置”记录器的特定级别(并使用默认配置),可以将configuredLevel的值传递为null

7. 指标

Spring Boot Actuator提供了依赖管理和自动配置,支持Micrometer,这是一个应用程序度量门面,支持多种监控系统,包括:

要了解更多关于Micrometer功能的信息,请参阅其参考文档,特别是概念部分

7.1. 入门

Spring Boot自动配置了一个复合MeterRegistry,并为在类路径上找到的每个受支持的实现添加一个注册表到该复合注册表中。在运行时类路径中具有micrometer-registry-{system}的依赖足以让Spring Boot配置注册表。

大多数注册表共享通用功能。例如,即使Micrometer注册表实现在类路径上,您也可以禁用特定注册表。以下示例禁用了Datadog:

属性
management.datadog.metrics.export.enabled=false
Yaml
management:
  datadog:
    metrics:
      export:
        enabled: false

您还可以通过注册表特定属性禁用所有注册表,除非另有说明,如以下示例所示:

属性
management.defaults.metrics.export.enabled=false
Yaml
management:
  defaults:
    metrics:
      export:
        enabled: false

Spring Boot还会将任何自动配置的注册表添加到Metrics类上的全局静态复合注册表中,除非您明确告诉它不要这样做:

属性
management.metrics.use-global-registry=false
Yaml
management:
  metrics:
    use-global-registry: false

您可以注册任意数量的MeterRegistryCustomizer bean来进一步配置注册表,例如在注册表注册任何计量器之前应用通用标记:

Java
import io.micrometer.core.instrument.MeterRegistry;

import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return (registry) -> registry.config().commonTags("region", "us-east-1");
    }

}
Kotlin
import io.micrometer.core.instrument.MeterRegistry
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyMeterRegistryConfiguration {

    @Bean
    fun metricsCommonTags(): MeterRegistryCustomizer<MeterRegistry> {
        return MeterRegistryCustomizer { registry ->
            registry.config().commonTags("region", "us-east-1")
        }
    }

}

您可以通过更具体地指定通用类型来对特定注册表实现应用自定义设置:

Java
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.graphite.GraphiteMeterRegistry;

import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

    @Bean
    public MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
        return (registry) -> registry.config().namingConvention(this::name);
    }

    private String name(String name, Meter.Type type, String baseUnit) {
        return ...
    }

}
Kotlin
import io.micrometer.core.instrument.Meter
import io.micrometer.core.instrument.config.NamingConvention
import io.micrometer.graphite.GraphiteMeterRegistry
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyMeterRegistryConfiguration {

    @Bean
    fun graphiteMetricsNamingConvention(): MeterRegistryCustomizer<GraphiteMeterRegistry> {
        return MeterRegistryCustomizer { registry: GraphiteMeterRegistry ->
            registry.config().namingConvention(this::name)
        }
    }

    private fun name(name: String, type: Meter.Type, baseUnit: String?): String {
        return  ...
    }

}

Spring Boot还会配置内置的仪表,您可以通过配置或专用注解标记来控制。

7.2. 支持的监控系统

本节简要描述了每个受支持的监控系统。

7.2.1. AppOptics

默认情况下,AppOptics注册表会定期将指标推送到 api.appoptics.com/v1/measurements。要将指标导出到SaaS AppOptics,必须提供您的API令牌:

属性
management.appoptics.metrics.export.api-token=YOUR_TOKEN
Yaml
management:
  appoptics:
    metrics:
      export:
        api-token: "YOUR_TOKEN"

7.2.2. Atlas

默认情况下,指标会导出到运行在本地机器上的 Atlas。您可以提供 Atlas 服务器的位置:

属性
management.atlas.metrics.export.uri=https://atlas.example.com:7101/api/v1/publish
Yaml
management:
  atlas:
    metrics:
      export:
        uri: "https://atlas.example.com:7101/api/v1/publish"

7.2.3. Datadog

Datadog注册表会定期将指标推送到 datadoghq。要将指标导出到 Datadog,必须提供您的API密钥:

属性
management.datadog.metrics.export.api-key=YOUR_KEY
Yaml
management:
  datadog:
    metrics:
      export:
        api-key: "YOUR_KEY"

如果您另外提供应用程序密钥(可选),则还将导出元数据,如计量器描述、类型和基本单位:

属性
management.datadog.metrics.export.api-key=YOUR_API_KEY
management.datadog.metrics.export.application-key=YOUR_APPLICATION_KEY
Yaml
management:
  datadog:
    metrics:
      export:
        api-key: "YOUR_API_KEY"
        application-key: "YOUR_APPLICATION_KEY"

默认情况下,指标会发送到 Datadog 美国 站点api.datadoghq.com)。如果您的 Datadog 项目托管在其他站点之一,或者需要通过代理发送指标,请相应配置 URI:

属性
management.datadog.metrics.export.uri=https://api.datadoghq.eu
Yaml
management:
  datadog:
    metrics:
      export:
        uri: "https://api.datadoghq.eu"

您还可以更改发送到 Datadog 的指标间隔时间:

属性
management.datadog.metrics.export.step=30s
Yaml
management:
  datadog:
    metrics:
      export:
        step: "30s"

7.2.4. Dynatrace

Dynatrace提供了两种指标摄取API,这两种API都已为 实现。您可以在 指标摄取的Dynatrace文档中找到Dynatrace文档 在这里。在 v1命名空间中的配置属性仅在导出到 Timeseries v1 API时应用。在 v2命名空间中的配置属性仅在导出到 Metrics v2 API时应用。请注意,此集成一次只能导出到 v1v2 API版本之一, v2为首选。如果在 v1命名空间中设置了 device-id(v1必需但在v2中未使用),则将指标导出到 v1端点。否则,将假定为 v2

v2 API

您可以以两种方式使用v2 API。

自动配置

Dynatrace自动配置适用于由OneAgent或Kubernetes的Dynatrace Operator监控的主机。

本地OneAgent:如果主机上运行着OneAgent,则指标将自动导出到本地OneAgent摄取端点。摄取端点将指标转发到Dynatrace后端。

Dynatrace Kubernetes Operator:在Kubernetes中安装了Dynatrace Operator时,注册表将自动从操作员中获取您的端点URI和API令牌。

这是默认行为,除了依赖于io.micrometer:micrometer-registry-dynatrace之外,不需要任何特殊设置。

手动配置

如果没有自动配置可用,则需要Metrics v2 API的端点和API令牌。API令牌必须具有“Ingest metrics”(metrics.ingest)权限设置。我们建议将令牌的范围限制为此权限。您必须确保端点URI包含路径(例如,/api/v2/metrics/ingest):

Metrics API v2摄取端点的URL根据您的部署选项而异:

  • SaaS:https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest

  • 托管部署:https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest

下面的示例配置了使用example环境ID导出指标:

属性
management.dynatrace.metrics.export.uri=https://example.live.dynatrace.com/api/v2/metrics/ingest
management.dynatrace.metrics.export.api-token=YOUR_TOKEN
Yaml
management:
  dynatrace:
    metrics:
      export:
        uri: "https://example.live.dynatrace.com/api/v2/metrics/ingest"
        api-token: "YOUR_TOKEN"

使用Dynatrace v2 API时,以下可选功能可用(更多详细信息请参阅Dynatrace文档):

  • 指标键前缀:设置添加到所有导出指标键之前的前缀。

  • 使用Dynatrace元数据进行丰富:如果OneAgent或Dynatrace操作员正在运行,则使用附加元数据(例如,关于主机、进程或Pod的信息)丰富指标。

  • 默认维度:指定添加到所有导出指标的键值对。如果使用Micrometer指定了具有相同键的标签,则它们将覆盖默认维度。

  • 使用Dynatrace摘要工具:在某些情况下,Micrometer Dynatrace注册表创建的指标会被拒绝。在Micrometer 1.9.x中,通过引入Dynatrace特定的摘要工具来修复了这个问题。将此切换设置为false会强制Micrometer回退到1.9.x之前的默认行为。仅在从Micrometer 1.8.x迁移到1.9.x时遇到问题时才应使用它。

  • 导出计量器元数据:从Micrometer 1.12.0开始,Dynatrace导出器还将默认导出计量器元数据,例如单位和描述。使用export-meter-metadata切换将此功能关闭。

可以不指定URI和API令牌,如下例所示。在这种情况下,将使用自动配置的端点:

属性
management.dynatrace.metrics.export.v2.metric-key-prefix=your.key.prefix
management.dynatrace.metrics.export.v2.enrich-with-dynatrace-metadata=true
management.dynatrace.metrics.export.v2.default-dimensions.key1=value1
management.dynatrace.metrics.export.v2.default-dimensions.key2=value2
management.dynatrace.metrics.export.v2.use-dynatrace-summary-instruments=true
management.dynatrace.metrics.export.v2.export-meter-metadata=true
Yaml
management:
  dynatrace:
    metrics:
      export:
        # 如果不使用本地OneAgent端点,请在此处指定uri和api-token。
        v2:
          metric-key-prefix: "your.key.prefix"
          enrich-with-dynatrace-metadata: true
          default-dimensions:
            key1: "value1"
            key2: "value2"
          use-dynatrace-summary-instruments: true #(默认值:true)
          export-meter-metadata: true             #(默认值:true)
v1 API(传统)

Dynatrace v1 API指标注册表定期通过使用Timeseries v1 API将指标推送到配置的URI。为了与现有设置向后兼容,当设置了device-id(v1必需但在v2中未使用)时,将指标导出到Timeseries v1端点。要将指标导出到 ,必须提供API令牌、设备ID和URI:

属性
management.dynatrace.metrics.export.uri=https://{your-environment-id}.live.dynatrace.com
management.dynatrace.metrics.export.api-token=YOUR_TOKEN
management.dynatrace.metrics.export.v1.device-id=YOUR_DEVICE_ID
Yaml
management:
  dynatrace:
    metrics:
      export:
        uri: "https://{your-environment-id}.live.dynatrace.com"
        api-token: "YOUR_TOKEN"
        v1:
          device-id: "YOUR_DEVICE_ID"

对于v1 API,必须指定不带路径的基本环境URI,因为v1端点路径会自动添加。

与版本无关的设置

除了API端点和令牌,您还可以更改发送指标到Dynatrace的间隔。默认的导出间隔为60s。以下示例将导出间隔设置为30秒:

属性
management.dynatrace.metrics.export.step=30s
Yaml
management:
  dynatrace:
    metrics:
      export:
        step: "30s"

您可以在Micrometer文档Dynatrace文档中找到有关如何为Micrometer设置Dynatrace导出器的更多信息。

7.2.5. Elastic

默认情况下,指标会导出到在本地计算机上运行的 Elastic。您可以通过以下属性提供要使用的Elastic服务器的位置:

属性
management.elastic.metrics.export.host=https://elastic.example.com:8086
Yaml
management:
  elastic:
    metrics:
      export:
        host: "https://elastic.example.com:8086"

7.2.6. Ganglia

默认情况下,指标会导出到在本地计算机上运行的 Ganglia。您可以提供 Ganglia服务器 的主机和端口,如下例所示:

属性
management.ganglia.metrics.export.host=ganglia.example.com
management.ganglia.metrics.export.port=9649
Yaml
management:
  ganglia:
    metrics:
      export:
        host: "ganglia.example.com"
        port: 9649

7.2.7. Graphite

默认情况下,指标会导出到在本地计算机上运行的 Graphite。您可以提供 Graphite服务器 的主机和端口,如下例所示:

属性
management.graphite.metrics.export.host=graphite.example.com
management.graphite.metrics.export.port=9004
Yaml
management:
  graphite:
    metrics:
      export:
         host: "graphite.example.com"
         port: 9004

Micrometer提供了一个默认的 HierarchicalNameMapper,用于管理维度计量标识如何 映射到平面分层名称

要控制此行为,定义您自己的 GraphiteMeterRegistry 并提供您自己的 HierarchicalNameMapper。除非您定义自己的,否则会提供自动配置的 GraphiteConfigClock bean:

Java
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.HierarchicalNameMapper;
import io.micrometer.graphite.GraphiteConfig;
import io.micrometer.graphite.GraphiteMeterRegistry;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyGraphiteConfiguration {

    @Bean
    public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig config, Clock clock) {
        return new GraphiteMeterRegistry(config, clock, this::toHierarchicalName);
    }

    private String toHierarchicalName(Meter.Id id, NamingConvention convention) {
        return ...
    }

}
Kotlin
import io.micrometer.core.instrument.Clock
import io.micrometer.core.instrument.Meter
import io.micrometer.core.instrument.config.NamingConvention
import io.micrometer.core.instrument.util.HierarchicalNameMapper
import io.micrometer.graphite.GraphiteConfig
import io.micrometer.graphite.GraphiteMeterRegistry
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyGraphiteConfiguration {

    @Bean
    fun graphiteMeterRegistry(config: GraphiteConfig, clock: Clock): GraphiteMeterRegistry {
        return GraphiteMeterRegistry(config, clock, this::toHierarchicalName)
    }
    private fun toHierarchicalName(id: Meter.Id, convention: NamingConvention): String {
        return  ...
    }

}

7.2.8. Humio

默认情况下,Humio注册表会定期将指标推送到 cloud.humio.com。要将指标导出到SaaS Humio,您必须提供您的API令牌:

属性
management.humio.metrics.export.api-token=YOUR_TOKEN
Yaml
management:
  humio:
    metrics:
      export:
        api-token: "YOUR_TOKEN"

您还应配置一个或多个标签,以标识将指标推送到的数据源:

属性
management.humio.metrics.export.tags.alpha=a
management.humio.metrics.export.tags.bravo=b
Yaml
management:
  humio:
    metrics:
      export:
        tags:
          alpha: "a"
          bravo: "b"

7.2.9. Influx

默认情况下,指标会导出到在本地计算机上运行的 Influx v1 实例,使用默认配置。要将指标导出到InfluxDB v2,请配置用于写入指标的 orgbucket 和认证 token。您可以通过以下方式提供要使用的 Influx服务器 的位置:

属性
management.influx.metrics.export.uri=https://influx.example.com:8086
Yaml
management:
  influx:
    metrics:
      export:
        uri: "https://influx.example.com:8086"

7.2.10. JMX

Micrometer提供了一个层次映射到JMX,主要作为一种便宜且便携的方式在本地查看指标。默认情况下,指标会导出到metrics JMX域。您可以通过以下方式提供要使用的域:

属性
management.jmx.metrics.export.domain=com.example.app.metrics
Yaml
management:
  jmx:
    metrics:
      export:
        domain: "com.example.app.metrics"

Micrometer提供了一个默认的HierarchicalNameMapper,用于管理维度计量ID如何映射到平面层次结构名称

要控制此行为,定义您自己的JmxMeterRegistry并提供您自己的HierarchicalNameMapper。除非您定义自己的JmxConfigClock bean,否则会提供自动配置的bean:

Java
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.HierarchicalNameMapper;
import io.micrometer.jmx.JmxConfig;
import io.micrometer.jmx.JmxMeterRegistry;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyJmxConfiguration {

    @Bean
    public JmxMeterRegistry jmxMeterRegistry(JmxConfig config, Clock clock) {
        return new JmxMeterRegistry(config, clock, this::toHierarchicalName);
    }

    private String toHierarchicalName(Meter.Id id, NamingConvention convention) {
        return ...
    }

}
Kotlin
import io.micrometer.core.instrument.Clock
import io.micrometer.core.instrument.Meter
import io.micrometer.core.instrument.config.NamingConvention
import io.micrometer.core.instrument.util.HierarchicalNameMapper
import io.micrometer.jmx.JmxConfig
import io.micrometer.jmx.JmxMeterRegistry
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyJmxConfiguration {

    @Bean
    fun jmxMeterRegistry(config: JmxConfig, clock: Clock): JmxMeterRegistry {
        return JmxMeterRegistry(config, clock, this::toHierarchicalName)
    }

    private fun toHierarchicalName(id: Meter.Id, convention: NamingConvention): String {
        return  ...
    }

}

7.2.11. KairosDB

默认情况下,指标会导出到在您本地机器上运行的KairosDB。您可以通过以下方式提供要使用的KairosDB服务器的位置:

属性
management.kairos.metrics.export.uri=https://kairosdb.example.com:8080/api/v1/datapoints
Yaml
management:
  kairos:
    metrics:
      export:
        uri: "https://kairosdb.example.com:8080/api/v1/datapoints"

7.2.12. New Relic

New Relic注册表定期将指标推送到New Relic。要将指标导出到New Relic,您必须提供您的API密钥和帐户ID:

属性
management.newrelic.metrics.export.api-key=YOUR_KEY
management.newrelic.metrics.export.account-id=YOUR_ACCOUNT_ID
Yaml
management:
  newrelic:
    metrics:
      export:
        api-key: "YOUR_KEY"
        account-id: "YOUR_ACCOUNT_ID"

您还可以更改发送指标到New Relic的间隔:

属性
management.newrelic.metrics.export.step=30s
Yaml
management:
  newrelic:
    metrics:
      export:
        step: "30s"

默认情况下,指标通过REST调用发布,但如果类路径上有Java代理API,则也可以使用它:

属性
management.newrelic.metrics.export.client-provider-type=insights-agent
Yaml
management:
  newrelic:
    metrics:
      export:
        client-provider-type: "insights-agent"

最后,您可以通过定义自己的NewRelicClientProvider bean来完全控制。

7.2.13. OpenTelemetry

默认情况下,指标会导出到在您本地机器上运行的OpenTelemetry。您可以通过以下方式提供要使用的OpenTelemetry指标端点的位置:

属性
management.otlp.metrics.export.url=https://otlp.example.com:4318/v1/metrics
Yaml
management:
  otlp:
    metrics:
      export:
        url: "https://otlp.example.com:4318/v1/metrics"

7.2.14. Prometheus

Prometheus期望对指标进行抓取或轮询单个应用实例。Spring Boot提供了一个位于/actuator/prometheus的执行器端点,以展示适当格式的Prometheus抓取

默认情况下,该端点不可用,必须暴露。有关更多详细信息,请参阅暴露端点

以下示例scrape_config添加到prometheus.yml中:

scrape_configs:
  - job_name: "spring"
    metrics_path: "/actuator/prometheus"
    static_configs:
      - targets: ["HOST:PORT"]

Prometheus示例也受支持。要启用此功能,应存在一个SpanContextSupplier bean。如果您使用Micrometer跟踪,则会为您自动配置,但如果您愿意,您也可以自行创建。请查看Prometheus文档,因为此功能需要在Prometheus端显式启用,并且仅支持使用OpenMetrics格式。

对于可能不会存在足够长时间以进行抓取的临时或批处理作业,您可以使用Prometheus Pushgateway支持将指标暴露给Prometheus。要启用Prometheus Pushgateway支持,请将以下依赖项添加到您的项目中:

<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_pushgateway</artifactId>
</dependency>

当Prometheus Pushgateway依赖项存在于类路径上并且management.prometheus.metrics.export.pushgateway.enabled属性设置为true时,将自动配置一个PrometheusPushGatewayManager bean。这将管理将指标推送到Prometheus Pushgateway。

您可以通过使用management.prometheus.metrics.export.pushgateway下的属性来调整PrometheusPushGatewayManager。对于高级配置,您还可以提供自己的PrometheusPushGatewayManager bean。

7.2.15. SignalFx

SignalFx注册表定期将指标推送到SignalFx。要将指标导出到SignalFx,您必须提供您的访问令牌:

属性
management.signalfx.metrics.export.access-token=YOUR_ACCESS_TOKEN
Yaml
management:
  signalfx:
    metrics:
      export:
        access-token: "YOUR_ACCESS_TOKEN"

您还可以更改发送指标到SignalFx的间隔:

属性
management.signalfx.metrics.export.step=30s
Yaml
management:
  signalfx:
    metrics:
      export:
        step: "30s"

7.2.16. Simple

Micrometer提供了一个简单的内存后端,如果没有配置其他注册表,则会自动用作后备。这使您可以在指标端点中查看收集的指标。

一旦使用任何其他可用后端,内存后端将自动禁用自身。您还可以显式禁用它:

属性
management.simple.metrics.export.enabled=false
Yaml
management:
  simple:
    metrics:
      export:
        enabled: false

7.2.17. Stackdriver

Stackdriver注册表定期将指标推送到Stackdriver。要将指标导出到SaaS Stackdriver,您必须提供您的Google Cloud项目ID:

属性
management.stackdriver.metrics.export.project-id=my-project
Yaml
management:
  stackdriver:
    metrics:
      export:
        project-id: "my-project"

您还可以更改发送指标到Stackdriver的间隔:

属性
management.stackdriver.metrics.export.step=30s
Yaml
management:
  stackdriver:
    metrics:
      export:
        step: "30s"

7.2.18. StatsD

StatsD注册表会急切地通过UDP将指标推送到StatsD代理。默认情况下,指标会导出到在本地计算机上运行的StatsD代理。您可以通过以下方式提供StatsD代理主机、端口和要使用的协议:

属性
management.statsd.metrics.export.host=statsd.example.com
management.statsd.metrics.export.port=9125
management.statsd.metrics.export.protocol=udp
Yaml
management:
  statsd:
    metrics:
      export:
        host: "statsd.example.com"
        port: 9125
        protocol: "udp"

您还可以更改要使用的StatsD线协议(默认为Datadog):

属性
management.statsd.metrics.export.flavor=etsy
Yaml
management:
  statsd:
    metrics:
      export:
        flavor: "etsy"

7.2.19. Wavefront

Wavefront注册表定期将指标推送到Wavefront。如果您直接将指标导出到Wavefront,您必须提供您的API令牌:

属性
management.wavefront.api-token=YOUR_API_TOKEN
Yaml
management:
  wavefront:
    api-token: "YOUR_API_TOKEN"

或者,您可以在您的环境中使用Wavefront sidecar或内部代理将指标数据转发到Wavefront API主机:

属性
management.wavefront.uri=proxy://localhost:2878
Yaml
management:
  wavefront:
    uri: "proxy://localhost:2878"
如果您将指标发布到Wavefront代理(如Wavefront文档中所述),主机必须采用proxy://HOST:PORT格式。

您还可以更改发送到Wavefront的指标的间隔:

属性
management.wavefront.metrics.export.step=30s
Yaml
management:
  wavefront:
    metrics:
      export:
        step: "30s"

7.3. 支持的指标和计量器

Spring Boot为各种技术提供了自动计量器注册。在大多数情况下,默认值提供了合理的指标,可以发布到任何受支持的监控系统中。

7.3.1. JVM指标

通过使用核心Micrometer类,自动配置启用了JVM指标。JVM指标发布在jvm.计量器名称下。

提供了以下JVM指标:

  • 各种内存和缓冲池详细信息

  • 与垃圾回收相关的统计信息

  • 线程利用率

  • 加载和卸载的类数量

  • JVM版本信息

  • JIT编译时间

7.3.2. 系统指标

通过使用核心Micrometer类,自动配置启用了系统指标。系统指标发布在system.process.disk.计量器名称下。

提供了以下系统指标:

  • CPU指标

  • 文件描述符指标

  • 运行时间指标(应用程序运行时间和绝对启动时间的固定计量)

  • 可用磁盘空间

7.3.3. 应用程序启动指标

自动配置暴露了应用程序启动时间指标:

  • application.started.time:启动应用程序所需的时间。

  • application.ready.time:应用程序准备好服务请求所需的时间。

指标由应用程序类的完全限定名称标记。

7.3.4. 日志记录器指标

自动配置启用了Logback和Log4J2的事件指标。详细信息发布在log4j2.events.logback.events.计量器名称下。

7.3.5. 任务执行和调度指标

自动配置启用了所有可用的ThreadPoolTaskExecutorThreadPoolTaskScheduler bean的仪表化,只要底层的ThreadPoolExecutor可用。指标由执行器的名称标记,该名称是从bean名称派生的。

7.3.6. JMS指标

自动配置启用了所有可用的JmsTemplate bean和@JmsListener注解方法的仪表化。这将分别产生"jms.message.publish""jms.message.process"指标。有关生成的观察的更多信息,请参阅Spring Framework参考文档

7.3.7. Spring MVC指标

自动配置启用了由Spring MVC控制器和功能处理程序处理的所有请求的仪表化。默认情况下,指标生成的名称为http.server.requests。您可以通过设置management.observations.http.server.requests.name属性来自定义名称。

有关生成的观察的更多信息,请参阅Spring Framework参考文档

要添加默认标签,请提供一个扩展自org.springframework.http.server.observation包中的DefaultServerRequestObservationConvention@Bean。要替换默认标签,请提供一个实现ServerRequestObservationConvention@Bean

在某些情况下,Web控制器中处理的异常不会记录为请求指标标签。应用程序可以选择记录异常,方法是将处理的异常设置为请求属性

默认情况下,所有请求都会被处理。要自定义过滤器,请提供一个实现FilterRegistrationBean<ServerHttpObservationFilter>@Bean

7.3.8. Spring WebFlux指标

自动配置启用了由Spring WebFlux控制器和功能处理程序处理的所有请求的仪表化。默认情况下,指标生成的名称为http.server.requests。您可以通过设置management.observations.http.server.requests.name属性来自定义名称。

有关生成的观察的更多信息,请参阅Spring Framework参考文档

要添加默认标签,请提供一个扩展自org.springframework.http.server.reactive.observation包中的DefaultServerRequestObservationConvention@Bean。要替换默认标签,请提供一个实现ServerRequestObservationConvention@Bean

在某些情况下,控制器和处理程序中处理的异常不会记录为请求指标标签。应用程序可以选择记录异常,方法是将处理的异常设置为请求属性

7.3.9. Jersey服务器指标

自动配置启用了Jersey JAX-RS实现处理的所有请求的仪表化。默认情况下,指标生成的名称为http.server.requests。您可以通过设置management.observations.http.server.requests.name属性来自定义名称。

默认情况下,Jersey服务器指标附带以下信息:

标签 描述

exception

处理请求时抛出的任何异常的简单类名。

method

请求的方法(例如,GETPOST

outcome

基于响应状态码的请求结果。1xx是INFORMATIONAL,2xx是SUCCESS,3xx是REDIRECTION,4xx是CLIENT_ERROR,5xx是SERVER_ERROR

status

响应的HTTP状态码(例如,200500

uri

请求的URI模板在变量替换之前(如果可能)(例如,/api/person/{id}

要自定义标签,请提供一个实现JerseyTagsProvider@Bean

7.3.10. HTTP客户端指标

Spring Boot Actuator管理RestTemplateWebClientRestClient的仪表化。为此,您必须注入自动配置的构建器并使用它来创建实例:

  • RestTemplateBuilder用于RestTemplate

  • WebClient.Builder用于WebClient

  • RestClient.Builder用于RestClient

您还可以手动应用负责此仪表化的自定义器,即ObservationRestTemplateCustomizerObservationWebClientCustomizerObservationRestClientCustomizer

默认情况下,指标生成的名称为http.client.requests。您可以通过设置management.observations.http.client.requests.name属性来自定义名称。

当使用RestTemplateRestClient时,要自定义标签,请提供一个实现org.springframework.http.client.observation包中的ClientRequestObservationConvention@Bean。当使用WebClient时要自定义标签,请提供一个实现org.springframework.web.reactive.function.client包中的ClientRequestObservationConvention@Bean

7.3.11. Tomcat指标

仅当启用MBeanRegistry时,自动配置才会启用Tomcat的仪表化。默认情况下,MBeanRegistry是禁用的,但您可以通过将server.tomcat.mbeanregistry.enabled设置为true来启用它。

Tomcat指标发布在tomcat.计量器名称下。

7.3.12. 缓存指标

自动配置在启动时启用所有可用的Cache实例的仪表化,指标前缀为cache。缓存仪表化针对基本一组指标进行了标准化。还提供了其他特定于缓存的指标。

支持以下缓存库:

  • Cache2k

  • Caffeine

  • Hazelcast

  • 任何符合JCache(JSR-107)规范的实现

  • Redis

指标按缓存的名称和CacheManager的名称进行标记,后者是从bean名称派生的。

仅在启动时配置的缓存才绑定到注册表。对于未在缓存配置中定义的缓存(例如在启动阶段之后动态创建或以编程方式创建的缓存),需要显式注册。提供了一个CacheMetricsRegistrar bean来简化该过程。

7.3.13. Spring Batch指标

7.3.14. Spring GraphQL指标

7.3.15. 数据源指标

自动配置启用所有可用的DataSource对象的仪表化,指标前缀为jdbc.connections。数据源仪表化会生成代表池中当前活动、空闲、最大允许和最小允许连接的计量器。

指标还按基于bean名称计算的DataSource的名称进行标记。

默认情况下,Spring Boot为所有支持的数据源提供元数据。如果您的喜爱数据源不受支持,可以添加额外的DataSourcePoolMetadataProvider bean。请参阅示例DataSourcePoolMetadataProvidersConfiguration

此外,Hikari特定的指标以hikaricp前缀公开。每个指标都按池的名称进行标记(您可以使用spring.datasource.name控制它)。

7.3.16. Hibernate指标

如果类路径上存在org.hibernate.orm:hibernate-micrometer,则所有可用的启用了统计信息的Hibernate EntityManagerFactory实例都会被仪表化,指标名为hibernate

指标还按EntityManagerFactory的名称进行标记,该名称是从bean名称派生的。

要启用统计信息,必须将标准JPA属性hibernate.generate_statistics设置为true。您可以在自动配置的EntityManagerFactory上启用它:

属性
spring.jpa.properties[hibernate.generate_statistics]=true
Yaml
spring:
  jpa:
    properties:
      "[hibernate.generate_statistics]": true

7.3.17. Spring Data Repository指标

自动配置启用所有Spring Data Repository方法调用的仪表化。默认情况下,指标生成的名称为spring.data.repository.invocations。您可以通过设置management.metrics.data.repository.metric-name属性来自定义名称。

支持io.micrometer.core.annotation包中的@Timed注解用于Repository接口和方法。如果不想记录所有Repository调用的指标,可以将management.metrics.data.repository.autotime.enabled设置为false,并仅使用@Timed注解。

带有longTask = true@Timed注解会为该方法启用长任务计时器。长任务计时器需要单独的指标名称,并且可以与短任务计时器叠加。

默认情况下,与存储库调用相关的指标附带以下信息的标签:

标签 描述

repository

Repository的简单类名。

method

调用的Repository方法的名称。

state

结果状态(SUCCESSERRORCANCELEDRUNNING)。

exception

从调用中抛出的任何异常的简单类名。

要替换默认标签,请提供一个实现RepositoryTagsProvider@Bean

7.3.18. RabbitMQ指标

自动配置启用所有可用的RabbitMQ连接工厂的仪表化,指标名为rabbitmq

7.3.19. Spring Integration指标

每当存在MeterRegistry bean时,Spring Integration会自动提供Micrometer支持。指标发布在spring.integration.计量器名称下。

7.3.20. Kafka指标

自动配置为自动配置的消费者工厂和生产者工厂分别注册了一个MicrometerConsumerListenerMicrometerProducerListener。它还为StreamsBuilderFactoryBean注册了一个KafkaStreamsMicrometerListener。有关更多详细信息,请参阅Spring Kafka文档的Micrometer原生指标部分。

7.3.21. MongoDB指标

本节简要描述了MongoDB的可用指标。

MongoDB命令指标

自动配置为自动配置的MongoClient注册了一个MongoMetricsCommandListener

为底层MongoDB驱动程序发出的每个命令创建了一个名为mongodb.driver.commands的计时器指标。每个指标默认使用以下信息进行标记:

标记 描述

command

发出的命令的名称。

cluster.id

发送命令的集群标识符。

server.address

发送命令的服务器地址。

status

命令的结果(SUCCESSFAILED)。

要替换默认的指标标记,请定义一个MongoCommandTagsProvider bean,如下例所示:

Java
import io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCommandTagsProviderConfiguration {

    @Bean
    public MongoCommandTagsProvider customCommandTagsProvider() {
        return new CustomCommandTagsProvider();
    }

}
Kotlin
import io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyCommandTagsProviderConfiguration {

    @Bean
    fun customCommandTagsProvider(): MongoCommandTagsProvider? {
        return CustomCommandTagsProvider()
    }

}

要禁用自动配置的命令指标,请设置以下属性:

属性
management.metrics.mongo.command.enabled=false
Yaml
management:
  metrics:
    mongo:
      command:
        enabled: false
MongoDB连接池指标

自动配置为自动配置的MongoClient注册了一个MongoMetricsConnectionPoolListener

为连接池创建了以下计量指标:

  • mongodb.driver.pool.size报告连接池的当前大小,包括空闲和正在使用的成员。

  • mongodb.driver.pool.checkedout报告当前正在使用的连接数。

  • mongodb.driver.pool.waitqueuesize报告连接池等待队列的当前大小。

每个指标默认使用以下信息进行标记:

标记 描述

cluster.id

连接池对应的集群标识符。

server.address

连接池对应的服务器地址。

要替换默认的指标标记,请定义一个MongoConnectionPoolTagsProvider bean:

Java
import io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyConnectionPoolTagsProviderConfiguration {

    @Bean
    public MongoConnectionPoolTagsProvider customConnectionPoolTagsProvider() {
        return new CustomConnectionPoolTagsProvider();
    }

}
Kotlin
import io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyConnectionPoolTagsProviderConfiguration {

    @Bean
    fun customConnectionPoolTagsProvider(): MongoConnectionPoolTagsProvider {
        return CustomConnectionPoolTagsProvider()
    }

}

要禁用自动配置的连接池指标,请设置以下属性:

属性
management.metrics.mongo.connectionpool.enabled=false
Yaml
management:
  metrics:
    mongo:
      connectionpool:
        enabled: false

7.3.22. Jetty指标

自动配置通过使用Micrometer的JettyServerThreadPoolMetrics为Jetty的ThreadPool绑定指标。通过使用Micrometer的JettyConnectionMetrics绑定Jetty的Connector实例的指标,并且当server.ssl.enabled设置为true时,使用Micrometer的JettySslHandshakeMetrics

7.3.23. @Timed注解支持

要启用@Timed注解的扫描,需要将management.observations.annotations.enabled属性设置为true。请参阅Micrometer文档

7.3.24. Redis指标

自动配置为自动配置的LettuceConnectionFactory注册了一个MicrometerCommandLatencyRecorder。有关更多详细信息,请参阅Lettuce文档的Micrometer指标部分

7.4. 注册自定义指标

要注册自定义指标,请将 MeterRegistry 注入到您的组件中:

Java
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;

import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final Dictionary dictionary;

    public MyBean(MeterRegistry registry) {
        this.dictionary = Dictionary.load();
        registry.gauge("dictionary.size", Tags.empty(), this.dictionary.getWords().size());
    }

}
Kotlin
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Tags
import org.springframework.stereotype.Component

@Component
class MyBean(registry: MeterRegistry) {

    private val dictionary: Dictionary

    init {
        dictionary = Dictionary.load()
        registry.gauge("dictionary.size", Tags.empty(), dictionary.words.size)
    }

}

如果您的指标依赖于其他 bean,我们建议您使用 MeterBinder 来注册它们:

Java
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.binder.MeterBinder;

import org.springframework.context.annotation.Bean;

public class MyMeterBinderConfiguration {

    @Bean
    public MeterBinder queueSize(Queue queue) {
        return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
    }

}
Kotlin
import io.micrometer.core.instrument.Gauge
import io.micrometer.core.instrument.binder.MeterBinder
import org.springframework.context.annotation.Bean

class MyMeterBinderConfiguration {

    @Bean
    fun queueSize(queue: Queue): MeterBinder {
        return MeterBinder { registry ->
            Gauge.builder("queueSize", queue::size).register(registry)
        }
    }

}

使用 MeterBinder 可确保正确设置依赖关系,并在检索指标值时使 bean 可用。如果您发现自己反复在组件或应用程序中为一组指标进行仪器化,MeterBinder 实现也可能很有用。

默认情况下,所有 MeterBinder bean 的指标会自动绑定到 Spring 管理的 MeterRegistry 中。

7.5. 自定义单个指标

如果您需要对特定的Meter实例应用自定义设置,可以使用io.micrometer.core.instrument.config.MeterFilter接口。

例如,如果您想要将所有以com.example开头的计量器ID中的mytag.region标签重命名为mytag.area,可以执行以下操作:

Java
import io.micrometer.core.instrument.config.MeterFilter;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyMetricsFilterConfiguration {

    @Bean
    public MeterFilter renameRegionTagMeterFilter() {
        return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
    }

}
Kotlin
import io.micrometer.core.instrument.config.MeterFilter
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyMetricsFilterConfiguration {

    @Bean
    fun renameRegionTagMeterFilter(): MeterFilter {
        return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area")
    }

}
默认情况下,所有MeterFilter bean都会自动绑定到Spring管理的MeterRegistry。请确保通过使用Spring管理的MeterRegistry注册您的指标,而不是使用Metrics上的任何静态方法。这些使用的是全局注册表,而不是Spring管理的注册表。

7.5.1. 通用标签

通用标签通常用于在操作环境上进行维度分析,例如主机、实例、区域、堆栈等。通用标签应用于所有计量器,并可以进行配置,如下例所示:

属性
management.metrics.tags.region=us-east-1
management.metrics.tags.stack=prod
Yaml
management:
  metrics:
    tags:
      region: "us-east-1"
      stack: "prod"

上述示例将regionstack标签添加到所有计量器中,值分别为us-east-1prod

如果使用Graphite,通用标签的顺序很重要。由于使用此方法无法保证通用标签的顺序,建议Graphite用户定义自定义的MeterFilter

7.5.2. 每个计量器属性

除了MeterFilter bean外,您还可以使用属性在每个计量器基础上应用一组有限的自定义设置。使用Spring Boot的PropertiesMeterFilter,将应用每个以给定名称开头的计量器ID。以下示例过滤掉任何ID以example.remote开头的计量器。

属性
management.metrics.enable.example.remote=false
Yaml
management:
  metrics:
    enable:
      example:
        remote: false

以下属性允许每个计量器的自定义设置:

表1. 每个计量器的自定义设置
属性 描述

management.metrics.enable

是否接受具有特定ID的计量器。未被接受的计量器将从MeterRegistry中过滤掉。

management.metrics.distribution.percentiles-histogram

是否发布适用于计算可聚合(跨维度)百分位数近似值的直方图。

management.metrics.distribution.minimum-expected-value, management.metrics.distribution.maximum-expected-value

通过夹紧预期值的范围来发布更少的直方图桶。

management.metrics.distribution.percentiles

发布应用程序中计算的百分位数值

management.metrics.distribution.expiry, management.metrics.distribution.buffer-length

通过在可配置的到期后旋转的环形缓冲区中累积最近的样本,为最近的样本赋予更大的权重,具有可配置的缓冲区长度。

management.metrics.distribution.slo

发布具有由您的服务级别目标定义的桶的累积直方图。

有关percentiles-histogrampercentilesslo背后概念的更多详细信息,请参阅Micrometer文档的“直方图和百分位数”部分

7.6. 指标端点

Spring Boot提供了一个metrics端点,您可以用于诊断性地检查应用程序收集的指标。该端点默认情况下不可用,必须暴露。有关更多详细信息,请参见暴露端点

导航到/actuator/metrics会显示可用计量器名称的列表。您可以通过提供其名称作为选择器来深入查看有关特定计量器的信息,例如/actuator/metrics/jvm.memory.max

此处使用的名称应与代码中使用的名称匹配,而不是在将其规范化为监控系统所需的命名约定后的名称。换句话说,如果由于其蛇形命名约定在Prometheus中jvm.memory.max显示为jvm_memory_max,您仍应在metrics端点中检查计量器时使用jvm.memory.max作为选择器。

您还可以在URL末尾添加任意数量的tag=KEY:VALUE查询参数,以在计量器上进行维度分析,例如/actuator/metrics/jvm.memory.max?tag=area:nonheap

报告的测量值是与匹配计量器名称和已应用的任何标签的所有计量器的统计数据之和。在上述示例中,返回的Value统计数据是堆的“Code Cache”、“Compressed Class Space”和“Metaspace”区域的最大内存占用的总和。如果您只想查看“Metaspace”的最大大小,可以添加额外的tag=id:Metaspace,即/actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace

7.7. 与Micrometer观察集成

一个DefaultMeterObservationHandler会自动注册到ObservationRegistry上,为每个完成的观察创建指标。

8. 追踪

Spring Boot Actuator为Micrometer Tracing提供了依赖管理和自动配置,Micrometer Tracing是流行跟踪器库的外观。

要了解有关Micrometer Tracing功能的更多信息,请参阅其参考文档

8.1. 支持的跟踪器

Spring Boot自带以下跟踪器的自动配置:

8.2. 入门指南

我们需要一个示例应用程序,以便开始跟踪。对于我们的目的,覆盖在“getting-started.html”部分中的简单“Hello World!” Web应用程序就足够了。我们将使用OpenTelemetry跟踪器与Zipkin作为跟踪后端。

简而言之,我们的主应用程序代码如下:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class MyApplication {

    private static final Log logger = LogFactory.getLog(MyApplication.class);

    @RequestMapping("/")
    String home() {
        logger.info("home() has been called");
        return "Hello World!";
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}
home()方法中添加了一个额外的日志记录语句,稍后会变得重要。

现在我们需要添加以下依赖项:

  • org.springframework.boot:spring-boot-starter-actuator

  • io.micrometer:micrometer-tracing-bridge-otel - 将Micrometer观察API桥接到OpenTelemetry。

  • io.opentelemetry:opentelemetry-exporter-zipkin - 将跟踪报告给Zipkin。

添加以下应用程序属性:

属性
management.tracing.sampling.probability=1.0
Yaml
management:
  tracing:
    sampling:
      probability: 1.0

默认情况下,Spring Boot仅对10%的请求进行采样,以防止超载跟踪后端。此属性将其切换为100%,以便将每个请求发送到跟踪后端。

要收集和可视化跟踪,我们需要一个正在运行的跟踪后端。在这里,我们使用Zipkin作为我们的跟踪后端。Zipkin快速入门指南提供了如何在本地启动Zipkin的说明。

启动Zipkin后,您可以启动应用程序。

如果您在Web浏览器中打开localhost:8080,您应该看到以下输出:

Hello World!

在幕后,已为HTTP请求创建了一个观察,然后将其桥接到OpenTelemetry,后者向Zipkin报告了一个新的跟踪。

现在打开Zipkin UI,网址为localhost:9411,然后点击“Run Query”按钮以列出所有收集的跟踪。您应该看到一个跟踪。点击“Show”按钮以查看该跟踪的详细信息。

8.3. 记录相关ID

相关ID提供了一种有助于将日志文件中的行与跨度/跟踪相关联的方法。如果您正在使用Micrometer Tracing,Spring Boot将默认在您的日志中包含相关ID。

默认的相关ID是从traceIdspanIdMDC值构建的。例如,如果Micrometer Tracing添加了一个MDC traceId803B448A0489F84084905D3093480352和一个MDC spanId3425F23BB2432450,日志输出将包含相关ID[803B448A0489F84084905D3093480352-3425F23BB2432450]

如果您希望为相关ID使用不同的格式,可以使用logging.pattern.correlation属性来定义一个。例如,以下内容将为Logback提供一个与之前Spring Cloud Sleuth使用的格式相同的相关ID:

属性
logging.pattern.correlation=[${spring.application.name:},%X{traceId:-},%X{spanId:-}] 
logging.include-application-name=false
Yaml
logging:
  pattern:
    correlation: "[${spring.application.name:},%X{traceId:-},%X{spanId:-}] "
  include-application-name: false
在上面的示例中,logging.include-application-name设置为false,以避免应用程序名称在日志消息中重复(logging.pattern.correlation已经包含了它)。还值得一提的是,logging.pattern.correlation包含一个尾随空格,以便默认情况下与紧随其后的记录器名称分隔开来。

8.4. 传播跟踪

要自动在网络上传播跟踪,请使用自动配置的RestTemplateBuilderWebClient.Builder来构建客户端。

如果您创建WebClientRestTemplate而不使用自动配置的构建器,则自动跟踪传播将无法工作!

8.5. 追踪器实现

由于Micrometer Tracer支持多个追踪器实现,因此在Spring Boot中可能存在多种依赖组合。

所有追踪器实现都需要org.springframework.boot:spring-boot-starter-actuator依赖。

8.5.1. 使用OpenTelemetry与Zipkin

使用OpenTelemetry进行追踪并向Zipkin报告需要以下依赖:

  • io.micrometer:micrometer-tracing-bridge-otel - 将Micrometer观察API桥接到OpenTelemetry。

  • io.opentelemetry:opentelemetry-exporter-zipkin - 将追踪报告到Zipkin。

使用management.zipkin.tracing.*配置属性来配置向Zipkin报告。

8.5.2. 使用OpenTelemetry与Wavefront

使用OpenTelemetry进行追踪并向Wavefront报告需要以下依赖:

  • io.micrometer:micrometer-tracing-bridge-otel - 将Micrometer观察API桥接到OpenTelemetry。

  • io.micrometer:micrometer-tracing-reporter-wavefront - 将追踪报告到Wavefront。

使用management.wavefront.*配置属性来配置向Wavefront报告。

8.5.3. 使用OpenTelemetry与OTLP

使用OpenTelemetry进行追踪并使用OTLP报告需要以下依赖:

  • io.micrometer:micrometer-tracing-bridge-otel - 将Micrometer观察API桥接到OpenTelemetry。

  • io.opentelemetry:opentelemetry-exporter-otlp - 将追踪报告到可以接受OTLP的收集器。

使用management.otlp.tracing.*配置属性来配置使用OTLP报告。

8.5.4. 使用OpenZipkin Brave与Zipkin

使用OpenZipkin Brave进行追踪并向Zipkin报告需要以下依赖:

  • io.micrometer:micrometer-tracing-bridge-brave - 将Micrometer观察API桥接到Brave。

  • io.zipkin.reporter2:zipkin-reporter-brave - 将追踪报告到Zipkin。

如果您的项目不使用Spring MVC或Spring WebFlux,则还需要io.zipkin.reporter2:zipkin-sender-urlconnection依赖。

使用management.zipkin.tracing.*配置属性来配置向Zipkin报告。

8.5.5. 使用OpenZipkin Brave与Wavefront

使用OpenZipkin Brave进行追踪并向Wavefront报告需要以下依赖:

  • io.micrometer:micrometer-tracing-bridge-brave - 将Micrometer观察API桥接到Brave。

  • io.micrometer:micrometer-tracing-reporter-wavefront - 将追踪报告到Wavefront。

使用management.wavefront.*配置属性来配置向Wavefront报告。

8.6. 与Micrometer观察集成

TracingAwareMeterObservationHandler会自动注册到ObservationRegistry上,为每个完成的观察创建跨度。

8.7. 创建自定义跨度

您可以通过启动观察来创建自己的跨度。为此,请将ObservationRegistry注入到您的组件中:

import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;

import org.springframework.stereotype.Component;

@Component
class CustomObservation {

    private final ObservationRegistry observationRegistry;

    CustomObservation(ObservationRegistry observationRegistry) {
        this.observationRegistry = observationRegistry;
    }

    void someOperation() {
        Observation observation = Observation.createNotStarted("some-operation", this.observationRegistry);
        observation.lowCardinalityKeyValue("some-tag", "some-value");
        observation.observe(() -> {
            // 业务逻辑...
        });
    }

}

这将创建一个名为"some-operation"的观察,带有标签"some-tag=some-value"。

如果要创建一个跨度而不创建度量标准,您需要使用Micrometer的较低级别的Tracer API

8.8. Baggage

您可以使用Tracer API创建行李:

import io.micrometer.tracing.BaggageInScope;
import io.micrometer.tracing.Tracer;

import org.springframework.stereotype.Component;

@Component
class CreatingBaggage {

    private final Tracer tracer;

    CreatingBaggage(Tracer tracer) {
        this.tracer = tracer;
    }

    void doSomething() {
        try (BaggageInScope scope = this.tracer.createBaggageInScope("baggage1", "value1")) {
            // 业务逻辑
        }
    }

}

此示例创建了名为baggage1的行李,值为value1。如果您使用W3C传播,行李将自动传播到网络。如果您使用B3传播,行李不会自动传播。要手动将行李传播到网络,请使用management.tracing.baggage.remote-fields配置属性(这也适用于W3C)。对于上述示例,将此属性设置为baggage1将导致HTTP头baggage1: value1

如果要将行李传播到MDC,请使用management.tracing.baggage.correlation.fields配置属性。对于上述示例,将此属性设置为baggage1将导致名为baggage1的MDC条目。

8.9. 测试

当使用@SpringBootTest时,报告数据的追踪组件不会自动配置。有关更多详细信息,请参阅测试部分

9. 审计

一旦Spring Security开始运行,Spring Boot Actuator具有灵活的审计框架,会发布事件(默认情况下为“身份验证成功”,“失败”和“访问被拒绝”异常)。此功能对于报告和基于身份验证失败实施锁定策略非常有用。

您可以通过在应用程序配置中提供AuditEventRepository类型的bean来启用审计。为方便起见,Spring Boot提供了一个InMemoryAuditEventRepositoryInMemoryAuditEventRepository的功能有限,我们建议仅在开发环境中使用它。对于生产环境,请考虑创建自己的替代AuditEventRepository实现。

9.1. 自定义审计

要自定义发布的安全事件,可以提供自己的AbstractAuthenticationAuditListenerAbstractAuthorizationAuditListener实现。

您还可以将审计服务用于自己的业务事件。为此,可以将AuditEventRepository bean注入到自己的组件中并直接使用,或者使用Spring的ApplicationEventPublisher发布AuditApplicationEvent(通过实现ApplicationEventPublisherAware)。

10. 记录HTTP交换

您可以通过在应用程序配置中提供HttpExchangeRepository类型的bean来启用HTTP交换记录。为方便起见,Spring Boot提供了InMemoryHttpExchangeRepository,默认情况下存储最后100个请求-响应交换。 InMemoryHttpExchangeRepository与跟踪解决方案相比功能有限,我们建议仅在开发环境中使用它。对于生产环境,建议使用生产就绪的跟踪或可观察性解决方案,如Zipkin或OpenTelemetry。或者,您可以创建自己的HttpExchangeRepository

您可以使用httpexchanges端点获取存储在HttpExchangeRepository中的请求-响应交换的信息。

10.1. 自定义HTTP交换记录

要自定义每个记录的交换中包含的项目,请使用management.httpexchanges.recording.include配置属性。

要完全禁用记录,请将management.httpexchanges.recording.enabled设置为false

11. 进程监控

spring-boot模块中,您可以找到两个类来创建通常用于进程监控的文件:

  • ApplicationPidFileWriter创建一个包含应用程序PID的文件(默认情况下,在应用程序目录中,文件名为application.pid)。

  • WebServerPortFileWriter创建一个包含运行Web服务器端口的文件(默认情况下,在应用程序目录中,文件名为application.port)。

默认情况下,这些写入器未激活,但您可以启用它们:

11.1. 扩展配置

META-INF/spring.factories文件中,您可以激活写入PID文件的监听器(或监听器):

org.springframework.context.ApplicationListener=\
org.springframework.boot.context.ApplicationPidFileWriter,\
org.springframework.boot.web.context.WebServerPortFileWriter

11.2. 通过编程方式启用进程监控

您还可以通过调用SpringApplication.addListeners(…​)方法并传递适当的Writer对象来激活监听器。此方法还允许您在Writer构造函数中自定义文件名和路径。

12. 云原生支持

Spring Boot的执行器模块包含了额外的支持,当您部署到兼容的Cloud Foundry实例时会激活该支持。/cloudfoundryapplication路径提供了一个替代的安全路由到所有@Endpoint beans。

扩展支持使得Cloud Foundry管理UI(例如您可以用来查看已部署应用程序的Web应用程序)可以增加Spring Boot执行器信息。例如,应用程序状态页面可以包含完整的健康信息,而不是典型的“运行”或“停止”状态。

/cloudfoundryapplication路径对普通用户不可直接访问。要使用该端点,您必须在请求中传递有效的UAA令牌。

12.1. 禁用扩展的Cloud Foundry执行器支持

如果您想完全禁用/cloudfoundryapplication端点,您可以将以下设置添加到您的application.properties文件中:

属性
management.cloudfoundry.enabled=false
Yaml
management:
  cloudfoundry:
    enabled: false

12.2. Cloud Foundry自签名证书

默认情况下,对/cloudfoundryapplication端点的安全验证会对各种Cloud Foundry服务进行SSL调用。如果您的Cloud Foundry UAA或Cloud Controller服务使用自签名证书,您需要设置以下属性:

属性
management.cloudfoundry.skip-ssl-validation=true
Yaml
management:
  cloudfoundry:
    skip-ssl-validation: true

12.3. 自定义上下文路径

如果服务器的上下文路径已配置为除/之外的任何内容,则 Cloud Foundry 端点不会在应用程序的根目录下可用。例如,如果server.servlet.context-path=/app,则 Cloud Foundry 端点可在/app/cloudfoundryapplication/*处访问。

如果您希望 Cloud Foundry 端点始终在/cloudfoundryapplication/*处可用,而不考虑服务器的上下文路径,您需要在应用程序中显式配置。配置因所使用的 Web 服务器而异。对于 Tomcat,您可以添加以下配置:

Java
import java.io.IOException;
import java.util.Collections;

import jakarta.servlet.GenericServlet;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.apache.catalina.Host;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCloudFoundryConfiguration {

    @Bean
    public TomcatServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory() {

            @Override
            protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
                super.prepareContext(host, initializers);
                StandardContext child = new StandardContext();
                child.addLifecycleListener(new Tomcat.FixContextListener());
                child.setPath("/cloudfoundryapplication");
                ServletContainerInitializer initializer = getServletContextInitializer(getContextPath());
                child.addServletContainerInitializer(initializer, Collections.emptySet());
                child.setCrossContext(true);
                host.addChild(child);
            }

        };
    }

    private ServletContainerInitializer getServletContextInitializer(String contextPath) {
        return (classes, context) -> {
            Servlet servlet = new GenericServlet() {

                @Override
                public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
                    ServletContext context = req.getServletContext().getContext(contextPath);
                    context.getRequestDispatcher("/cloudfoundryapplication").forward(req, res);
                }

            };
            context.addServlet("cloudfoundry", servlet).addMapping("/*");
        };
    }

}
Kotlin
import jakarta.servlet.GenericServlet
import jakarta.servlet.Servlet
import jakarta.servlet.ServletContainerInitializer
import jakarta.servlet.ServletContext
import jakarta.servlet.ServletException
import jakarta.servlet.ServletRequest
import jakarta.servlet.ServletResponse
import org.apache.catalina.Host
import org.apache.catalina.core.StandardContext
import org.apache.catalina.startup.Tomcat.FixContextListener
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
import org.springframework.boot.web.servlet.ServletContextInitializer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.io.IOException
import java.util.Collections.emptySet

@Configuration(proxyBeanMethods = false)
class MyCloudFoundryConfiguration {

    @Bean
    fun servletWebServerFactory(): TomcatServletWebServerFactory {
        return object : TomcatServletWebServerFactory() {

            override fun prepareContext(host: Host, initializers: Array<ServletContextInitializer>) {
                super.prepareContext(host, initializers)
                val child = StandardContext()
                child.addLifecycleListener(FixContextListener())
                child.path = "/cloudfoundryapplication"
                val initializer = getServletContextInitializer(contextPath)
                child.addServletContainerInitializer(initializer, emptySet())
                child.crossContext = true
                host.addChild(child)
            }

        }
    }

    private fun getServletContextInitializer(contextPath: String): ServletContainerInitializer {
        return ServletContainerInitializer { classes: Set<Class<*>?>?, context: ServletContext ->
            val servlet: Servlet = object : GenericServlet() {

                @Throws(ServletException::class, IOException::class)
                override fun service(req: ServletRequest, res: ServletResponse) {
                    val servletContext = req.servletContext.getContext(contextPath)
                    servletContext.getRequestDispatcher("/cloudfoundryapplication").forward(req, res)
                }

            }
            context.addServlet("cloudfoundry", servlet).addMapping("/*")
        }
    }
}

如果您正在使用基于 Webflux 的应用程序,您可以使用以下配置:

Java
import java.util.Map;

import reactor.core.publisher.Mono;

import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebFluxProperties.class)
public class MyReactiveCloudFoundryConfiguration {

    @Bean
    public HttpHandler httpHandler(ApplicationContext applicationContext, WebFluxProperties properties) {
        HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();
        return new CloudFoundryHttpHandler(properties.getBasePath(), httpHandler);
    }

    private static final class CloudFoundryHttpHandler implements HttpHandler {

        private final HttpHandler delegate;

        private final ContextPathCompositeHandler contextPathDelegate;

        private CloudFoundryHttpHandler(String basePath, HttpHandler delegate) {
            this.delegate = delegate;
            this.contextPathDelegate = new ContextPathCompositeHandler(Map.of(basePath, delegate));
        }

        @Override
        public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
            // 先移除底层上下文路径(例如 Servlet 容器)
            String path = request.getPath().pathWithinApplication().value();
            if (path.startsWith("/cloudfoundryapplication")) {
                return this.delegate.handle(request, response);
            }
            else {
                return this.contextPathDelegate.handle(request, response);
            }
        }

    }

}
Kotlin
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.server.reactive.ContextPathCompositeHandler
import org.springframework.http.server.reactive.HttpHandler
import org.springframework.http.server.reactive.ServerHttpRequest
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.web.server.adapter.WebHttpHandlerBuilder
import reactor.core.publisher.Mono

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebFluxProperties::class)
class MyReactiveCloudFoundryConfiguration {

    @Bean
    fun httpHandler(applicationContext: ApplicationContext, properties: WebFluxProperties): HttpHandler {
        val httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build()
        return CloudFoundryHttpHandler(properties.basePath, httpHandler)
    }

    private class CloudFoundryHttpHandler(basePath: String, private val delegate: HttpHandler) : HttpHandler {
        private val contextPathDelegate = ContextPathCompositeHandler(mapOf(basePath to delegate))

        override fun handle(request: ServerHttpRequest, response: ServerHttpResponse): Mono<Void> {
            // 先移除底层上下文路径(例如 Servlet 容器)
            val path = request.path.pathWithinApplication().value()
            return if (path.startsWith("/cloudfoundryapplication")) {
                delegate.handle(request, response)
            } else {
                contextPathDelegate.handle(request, response)
            }
        }
    }
}

13. 接下来阅读什么

您可能想阅读有关图形工具如Graphite的信息。

否则,您可以继续阅读有关“部署选项”或者直接了解Spring Boot的构建工具插件的深入信息。