可观测性支持

Micrometer 定义了一个 观测概念,它支持应用程序中的指标和跟踪。 指标支持提供了一种创建计时器、计量器或计数器的方式,用于收集有关应用程序运行时行为的统计信息。 指标可以帮助您跟踪错误率、使用模式、性能等。 跟踪提供了一个跨越应用程序边界的整个系统的整体视图;您可以放大特定的用户请求并跟踪它们在整个应用程序中的完成情况。 如果配置了 ObservationRegistry,Spring Framework 会检测其自身代码库的各个部分以发布观测。 您可以了解有关 在 Spring Boot 中配置可观测性基础设施的更多信息。

生成的观测列表

Spring Framework 检测各种功能以实现可观测性。 如 本节开头所述,观测可以根据配置生成计时器指标和/或跟踪。

Table 1. Spring Framework 生成的观测
观测名称 描述

"http.client.requests"

HTTP 客户端交换所花费的时间

"http.server.requests"

框架级别的 HTTP 服务器交换处理时间

"jms.message.publish"

消息生产者向目标发送 JMS 消息所花费的时间。

"jms.message.process"

消息消费者之前接收到的 JMS 消息的处理时间。

"tasks.scheduled.execution"

@Scheduled 任务执行的处理时间

观测使用 Micrometer 的官方命名约定,但指标名称将自动转换为 监控系统后端首选的格式 (Prometheus、Atlas、Graphite、InfluxDB…​)。

Micrometer 观测概念

如果您不熟悉 Micrometer 观测,这里是您应该了解的概念的快速摘要。

  • Observation 是应用程序中发生的实际事件记录。ObservationHandler 实现会处理它以生成指标或跟踪。

  • 每个观测都有一个对应的 ObservationContext 实现;此类型保存提取其元数据的所有相关信息。 对于 HTTP 服务器观测,上下文实现可以保存 HTTP 请求、HTTP 响应、处理期间抛出的任何异常等。

  • 每个 Observation 都包含 KeyValues 元数据。对于 HTTP 服务器观测,这可能是 HTTP 请求方法、HTTP 响应状态等。 此元数据由 ObservationConvention 实现提供,这些实现应声明它们支持的 ObservationContext 类型。

  • 如果 KeyValue 元组的可能值数量较少且有界(HTTP 方法是一个很好的例子),则 KeyValues 被认为是“低基数”。 低基数的值仅贡献给指标。 相反,“高基数”值是无界的(例如,HTTP 请求 URI),并且仅贡献给跟踪。

  • ObservationDocumentation 记录特定领域中的所有观测,列出预期的键名及其含义。

配置观测

全局配置选项可在 ObservationRegistry#observationConfig() 级别使用。 每个被检测的组件将提供两个扩展点:

  • 设置 ObservationRegistry;如果未设置,则不会记录观测,并且将是无操作的

  • 提供自定义 ObservationConvention 以更改默认观测名称和提取的 KeyValues

使用自定义观测约定

让我们以 Spring MVC “http.server.requests”指标检测与 ServerHttpObservationFilter 为例。 此观测使用 ServerRequestObservationConventionServerRequestObservationContext;自定义约定可以在 Servlet 过滤器上配置。 如果您想自定义观测生成的元数据,您可以根据您的要求扩展 DefaultServerRequestObservationConvention

如果您想完全控制,您可以实现您感兴趣的观测的整个约定契约:

您还可以使用自定义 ObservationFilter 实现类似的目标——为观测添加或删除键值。 过滤器不会替换默认约定,而是作为后处理组件使用。

您可以在 ObservationRegistry 上配置 ObservationFilter 实例。

@Scheduled 任务检测

每次 @Scheduled 任务执行创建一个观测。 应用程序需要将 ObservationRegistry 配置到 ScheduledTaskRegistrar 上以启用观测记录。 这可以通过声明一个设置观测注册表的 SchedulingConfigurer bean 来完成:

它默认使用 org.springframework.scheduling.support.DefaultScheduledTaskObservationConvention,由 ScheduledTaskObservationContext 提供支持。 您可以直接在 ObservationRegistry 上配置自定义实现。 在预定方法执行期间,当前观测会恢复到 ThreadLocal 上下文或 Reactor 上下文(如果预定方法返回 MonoFlux 类型)。

默认情况下,创建以下 KeyValues

Table 2. 低基数键

名称

描述

code.function (必需)

计划执行的 Java Method 的名称。

code.namespace (必需)

包含计划方法的 bean 实例的类的规范名称,或匿名类的`"ANONYMOUS"`。

error (必需)

执行期间抛出的异常的类名,如果没有发生异常则为`"none"`。

exception (已弃用)

复制 error 键,将来可能会删除。

outcome (必需)

方法执行的结果。可以是`"SUCCESS"`、"ERROR"`或`"UNKNOWN"(例如,如果操作在执行期间被取消)。

JMS 消息传递检测

如果类路径上存在 io.micrometer:micrometer-jakarta9 依赖项,Spring Framework 将使用 Micrometer 提供的 Jakarta JMS 检测。 io.micrometer.jakarta9.instrument.jms.JmsInstrumentation 检测 jakarta.jms.Session 并记录相关观测。

此检测将创建两种类型的观测:

  • 当 JMS 消息发送到代理时,通常使用 JmsTemplate,记录 "jms.message.publish"

  • 当 JMS 消息由应用程序处理时,通常使用 MessageListener@JmsListener 注解方法,记录 "jms.message.process"

目前没有针对 "jms.message.receive" 观测的检测,因为测量等待接收消息所花费的时间价值不大。 这种集成通常会检测 MessageConsumer#receive 方法调用。但是一旦它们返回,处理时间就不会被测量,并且跟踪范围也无法传播到应用程序。

默认情况下,两个观测共享同一组可能的 KeyValues

Table 3. 低基数键

名称

描述

error

消息操作期间抛出的异常的类名(或“none”)。

exception (已弃用)

复制 error 键,将来可能会删除。

messaging.destination.temporary (必需)

目的地是否为 TemporaryQueueTemporaryTopic(值:"true""false")。

messaging.operation (必需)

正在执行的 JMS 操作的名称(值:"publish""process")。

Table 4. 高基数键

名称

描述

messaging.message.conversation_id

JMS 消息的关联 ID。

messaging.destination.name

当前消息发送到的目的地的名称。

messaging.message.id

消息传递系统用作消息标识符的值。

JMS 消息发布检测

当 JMS 消息发送到代理时,记录 "jms.message.publish" 观测。 它们测量发送消息所花费的时间,并使用传出的 JMS 消息头传播跟踪信息。

您需要将 ObservationRegistry 配置到 JmsTemplate 上以启用观测:

它默认使用 io.micrometer.jakarta9.instrument.jms.DefaultJmsPublishObservationConvention,由 io.micrometer.jakarta9.instrument.jms.JmsPublishObservationContext 提供支持。

当响应消息从监听器方法返回时,使用 @JmsListener 注解方法记录类似的观测。

JMS 消息处理检测

当 JMS 消息由应用程序处理时,记录 "jms.message.process" 观测。 它们测量处理消息所花费的时间,并使用传入的 JMS 消息头传播跟踪上下文。

大多数应用程序将使用 @JmsListener 注解方法机制来处理传入消息。 您需要确保 ObservationRegistry 已配置在专用的 JmsListenerContainerFactory 上:

需要默认容器工厂来启用注解支持, 但请注意,@JmsListener 注解可以引用特定的容器工厂 bean 以用于特定目的。 在所有情况下,只有当观测注册表配置在容器工厂上时,才会记录观测。

当消息由 MessageListener 处理时,使用 JmsTemplate 记录类似的观测。 此类监听器在会话回调中设置在 MessageConsumer 上(参见 JmsTemplate.execute(SessionCallback<T>))。

此观测默认使用 io.micrometer.jakarta9.instrument.jms.DefaultJmsProcessObservationConvention,由 io.micrometer.jakarta9.instrument.jms.JmsProcessObservationContext 提供支持。

HTTP 服务器检测

对于 Servlet 和 Reactive 应用程序,HTTP 服务器交换观测以名称 "http.server.requests" 创建。

Servlet 应用程序

应用程序需要在其应用程序中配置 org.springframework.web.filter.ServerHttpObservationFilter Servlet 过滤器。 它默认使用 org.springframework.http.server.observation.DefaultServerRequestObservationConvention,由 ServerRequestObservationContext 提供支持。

这仅在 Exception 未被 Web 框架处理并冒泡到 Servlet 过滤器时才将观测记录为错误。 通常,所有由 Spring MVC 的 @ExceptionHandlerProblemDetail 支持处理的异常都不会记录在观测中。 您可以在请求处理的任何时候自己设置 ObservationContext 上的错误字段:

由于检测是在 Servlet 过滤器级别完成的,因此观测范围仅涵盖在此之后排序的过滤器以及请求的处理。 通常,Servlet 容器错误处理是在较低级别执行的,并且不会有任何活动的观测或 span。 对于此用例,需要容器特定的实现,例如 Tomcat 的 org.apache.catalina.Valve;这超出了本项目的范围。

默认情况下,创建以下 KeyValues

Table 5. 低基数键

名称

描述

error (必需)

交换期间抛出的异常的类名,如果没有发生异常则为`"none"`。

exception (已弃用)

复制 error 键,将来可能会删除。

method (必需)

HTTP 请求方法的名称,如果不是众所周知的方法则为`"none"`。

outcome (必需)

HTTP 服务器交换的结果。

status (必需)

HTTP 响应原始状态码,如果未创建响应则为`"UNKNOWN"`。

uri (必需)

匹配处理程序的 URI 模式(如果可用),否则 3xx 响应回退到 REDIRECTION,404 响应回退到 NOT_FOUND,没有路径信息的请求回退到 root,所有其他请求回退到 UNKNOWN

Table 6. 高基数键

名称

描述

http.url (必需)

HTTP 请求 URI。

Reactive 应用程序

应用程序需要使用 MeterRegistry 配置 WebHttpHandlerBuilder 以启用服务器检测。 这可以在 WebHttpHandlerBuilder 上完成,如下所示:

它默认使用 org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention,由 ServerRequestObservationContext 提供支持。

这仅在 Exception 未被应用程序控制器处理时才将观测记录为错误。 通常,所有由 Spring WebFlux 的 @ExceptionHandlerProblemDetail 支持处理的异常都不会记录在观测中。 您可以在请求处理的任何时候自己设置 ObservationContext 上的错误字段:

默认情况下,创建以下 KeyValues

Table 7. 低基数键

名称

描述

error (必需)

交换期间抛出的异常的类名,如果没有发生异常则为`"none"`。

exception (已弃用)

复制 error 键,将来可能会删除。

method (必需)

HTTP 请求方法的名称,如果不是众所周知的方法则为`"none"`。

outcome (必需)

HTTP 服务器交换的结果。

status (必需)

HTTP 响应原始状态码,如果未创建响应则为`"UNKNOWN"`。

uri (必需)

匹配处理程序的 URI 模式(如果可用),否则 3xx 响应回退到 REDIRECTION,404 响应回退到 NOT_FOUND,没有路径信息的请求回退到 root,所有其他请求回退到 UNKNOWN

Table 8. 高基数键

名称

描述

http.url (必需)

HTTP 请求 URI。

HTTP 客户端检测

HTTP 客户端交换观测以名称 "http.client.requests" 为阻塞和响应式客户端创建。 此观测测量整个 HTTP 请求/响应交换,从连接建立到正文反序列化。 与它们的服务器对应物不同,检测直接在客户端中实现,因此唯一需要的步骤是在客户端上配置 ObservationRegistry

RestTemplate

应用程序必须在 RestTemplate 实例上配置 ObservationRegistry 以启用检测;否则,观测将是“无操作”。 Spring Boot 将自动配置已设置观测注册表的 RestTemplateBuilder bean。

检测默认使用 org.springframework.http.client.observation.ClientRequestObservationConvention,由 ClientRequestObservationContext 提供支持。

Table 9. 低基数键

名称

描述

method (必需)

HTTP 请求方法的名称,如果不是众所周知的方法则为`"none"`。

uri (必需)

用于 HTTP 请求的 URI 模板,如果未提供则为`"none"`。URI 的协议、主机和端口部分不予考虑。

client.name (必需)

从请求 URI 主机派生的客户端名称。

status (必需)

HTTP 响应原始状态码,如果发生 IOException 则为`"IO_ERROR"`,如果未收到响应则为`"CLIENT_ERROR"`。

outcome (必需)

HTTP 客户端交换的结果。

error (必需)

交换期间抛出的异常的类名,如果没有发生异常则为`"none"`。

exception (已弃用)

复制 error 键,将来可能会删除。

Table 10. 高基数键

名称

描述

http.url (必需)

HTTP 请求 URI。

RestClient

应用程序必须在 RestClient.Builder 上配置 ObservationRegistry 以启用检测;否则,观测将是“无操作”。

检测默认使用 org.springframework.http.client.observation.ClientRequestObservationConvention,由 ClientRequestObservationContext 提供支持。

Table 11. 低基数键

名称

描述

method (必需)

HTTP 请求方法的名称,如果无法创建请求则为`"none"`。

uri (必需)

用于 HTTP 请求的 URI 模板,如果未提供则为`"none"`。URI 的协议、主机和端口部分不予考虑。

client.name (必需)

从请求 URI 主机派生的客户端名称。

status (必需)

HTTP 响应原始状态码,如果发生 IOException 则为`"IO_ERROR"`,如果未收到响应则为`"CLIENT_ERROR"`。

outcome (必需)

HTTP 客户端交换的结果。

error (必需)

交换期间抛出的异常的类名,如果没有发生异常则为`"none"`。

exception (已弃用)

复制 error 键,将来可能会删除。

Table 12. 高基数键

名称

描述

http.url (必需)

HTTP 请求 URI。

WebClient

应用程序必须在 WebClient.Builder 上配置 ObservationRegistry 以启用检测;否则,观测将是“无操作”。 Spring Boot 将自动配置已设置观测注册表的 WebClient.Builder bean。

检测默认使用 org.springframework.web.reactive.function.client.ClientRequestObservationConvention,由 ClientRequestObservationContext 提供支持。

Table 13. 低基数键

名称

描述

method (必需)

HTTP 请求方法的名称,如果不是众所周知的方法则为`"none"`。

uri (必需)

用于 HTTP 请求的 URI 模板,如果未提供则为`"none"`。URI 的协议、主机和端口部分不予考虑。

client.name (必需)

从请求 URI 主机派生的客户端名称。

status (必需)

HTTP 响应原始状态码,如果发生 IOException 则为`"IO_ERROR"`,如果未收到响应则为`"CLIENT_ERROR"`。

outcome (必需)

HTTP 客户端交换的结果。

error (必需)

交换期间抛出的异常的类名,如果没有发生异常则为`"none"`。

exception (已弃用)

复制 error 键,将来可能会删除。

Table 14. 高基数键

名称

描述

http.url (必需)

HTTP 请求 URI。

应用程序事件和 @EventListener

Spring Framework 不为 @EventListener 调用提供观测, 因为它们不具备此类检测的正确语义。 默认情况下,事件发布和处理是同步且在同一线程上完成的。 这意味着在任务执行期间,ThreadLocals 和日志上下文将与事件发布者相同。

如果应用程序全局配置了一个自定义 ApplicationEventMulticaster,并采用了一种在不同线程上调度事件处理的策略,则情况不再如此。 所有 @EventListener 方法都将在不同的线程上处理,而不是在主事件发布线程上。 在这些情况下,https://docs.micrometer.io/context-propagation/reference/[Micrometer Context Propagation 库]可以帮助传播此类值并更好地关联事件的处理。 应用程序可以将选择的 TaskExecutor 配置为使用 ContextPropagatingTaskDecorator 来装饰任务并传播上下文。 为此,io.micrometer:context-propagation 库必须存在于类路径中:

类似地,如果针对每个 @EventListener 注解方法本地做出异步选择,通过向其添加 @Async, 您可以选择通过其限定符引用一个传播上下文的 TaskExecutor。 给定以下 TaskExecutor bean 定义,配置了专用的任务装饰器:

使用 @Async 和相关限定符注解事件监听器将实现类似的上下文传播结果: