可观测性支持

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 任务都会创建一个观测。 应用程序需要配置 ScheduledTaskRegistrar 上的 ObservationRegistry 以启用观测记录。 这可以通过声明一个设置观测注册表的 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.JmsInstrumentationjakarta.jms.Session 进行插桩并记录相关观测。

此插桩将创建 2 种类型的观测:

  • 当 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 消息头传播跟踪信息。

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

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

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

JMS 消息处理插桩

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

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

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

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

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

HTTP 服务器插桩

HTTP 服务器交换观测以名称 "http.server.requests" 为 Servlet 和 Reactive 应用程序创建, 如果使用 OpenTelemetry 约定,则为 "http.server.request.duration"

Servlet 应用程序

应用程序需要在其应用程序中配置 org.springframework.web.filter.ServerHttpObservationFilter Servlet 过滤器。

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

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

默认语义约定

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

默认情况下,会创建以下 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。

OpenTelemetry 语义约定

OpenTelemetry 变体可与 org.springframework.http.server.observation.OpenTelemetryServerRequestObservationConvention 一起使用,并由 ServerRequestObservationContext 支持。

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 上下文传播库]可以帮助传播这些值并更好地关联事件的处理。 应用程序可以将选择的 TaskExecutor 配置为使用 ContextPropagatingTaskDecorator,该装饰器装饰任务并传播上下文。 为此,io.micrometer:context-propagation 库必须存在于类路径中:

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

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