此版本仍在开发中,尚未被视为稳定版。如需最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

可观测性支持

Micrometer 定义了一种Observation(观测)概念,可在应用程序中同时支持指标(Metrics)和追踪(Traces)。 指标支持提供了一种创建计时器、仪表或计数器的方法,用于收集有关应用程序运行时行为的统计信息。 指标可以帮助你跟踪错误率、使用模式、性能等。 追踪则提供了跨越应用边界的整个系统的整体视图;你可以聚焦于特定的用户请求,并跟踪其在整个应用系统中的完整执行过程。spring-doc.cadn.net.cn

Spring Framework 对其自身代码库的多个部分进行了插桩,以便在配置了 ObservationRegistry 时发布观测数据。 您可以进一步了解在 Spring Boot 中配置可观测性基础设施spring-doc.cadn.net.cn

已生成的观测列表

Spring Framework 提供了多种用于可观测性的功能。 如本节开头所述,根据配置的不同,观测(observations)可以生成计时器指标(Metrics)和/或追踪(Traces)。spring-doc.cadn.net.cn

表1. Spring Framework 生成的观测数据
观测名称 描述

"http.client.requests"spring-doc.cadn.net.cn

HTTP 客户端交换所花费的时间spring-doc.cadn.net.cn

"http.server.requests"spring-doc.cadn.net.cn

在框架级别处理 HTTP 服务器交换的时间spring-doc.cadn.net.cn

"jms.message.publish"spring-doc.cadn.net.cn

消息生产者向目标发送 JMS 消息所花费的时间。spring-doc.cadn.net.cn

"jms.message.process"spring-doc.cadn.net.cn

之前由消息消费者接收到的 JMS 消息的处理时间。spring-doc.cadn.net.cn

"tasks.scheduled.execution"spring-doc.cadn.net.cn

@Scheduled 任务执行的处理时间spring-doc.cadn.net.cn

Observations 使用 Micrometer 的官方命名规范,但指标(Metrics)名称将自动转换为 监控系统后端所偏好的格式 (如 Prometheus、Atlas、Graphite、InfluxDB 等)。

Micrometer 观测概念

如果你不熟悉 Micrometer Observation,以下是关于你需要了解的概念的简要概述。spring-doc.cadn.net.cn

  • Observation 是对应用程序中发生的某件事情的实际记录。它由 ObservationHandler 的实现进行处理,以生成指标(metrics)或追踪(traces)。spring-doc.cadn.net.cn

  • 每个观测(observation)都有一个对应的 ObservationContext 实现;该类型保存了用于提取其元数据的所有相关信息。 对于 HTTP 服务器观测而言,其上下文实现可能包含 HTTP 请求、HTTP 响应、处理过程中抛出的任何异常等。spring-doc.cadn.net.cn

  • 每个 Observation 都包含 KeyValues 元数据。以 HTTP 服务器的 observation 为例,这些元数据可以是 HTTP 请求方法、HTTP 响应状态等。 这些元数据由 ObservationConvention 的实现类提供,这些实现类应声明它们所支持的 ObservationContext 类型。spring-doc.cadn.net.cn

  • 如果 KeyValues 元组的可能取值数量较少且有限(例如 HTTP 方法就是一个很好的例子),则称这些 KeyValue 为“低基数”(low cardinality)。 低基数的值仅用于指标(metrics)。 相反,“高基数”(high cardinality)的值是无界的(例如 HTTP 请求 URI),仅用于追踪(traces)。spring-doc.cadn.net.cn

  • ObservationDocumentation 用于记录特定领域中的所有观测数据,列出预期的键名及其含义。spring-doc.cadn.net.cn

配置观测功能

全局配置选项可在 ObservationRegistry#observationConfig() 级别进行设置。 每个被监控的组件将提供两个扩展点:spring-doc.cadn.net.cn

  • 设置 ObservationRegistry;如果未设置,观测数据将不会被记录,相关操作将变为无操作(no-op)spring-doc.cadn.net.cn

  • 提供一个自定义的 ObservationConvention 来更改默认的观测名称和提取的 KeyValuesspring-doc.cadn.net.cn

使用自定义观测约定

以 Spring MVC 的 "http.server.requests" 指标监控为例,它使用了 ServerHttpObservationFilter。 该监控使用了一个带有 ServerRequestObservationConventionServerRequestObservationContext;自定义的约定可以在 Servlet 过滤器上进行配置。 如果您希望自定义监控所产生的元数据,可以根据自身需求继承 DefaultServerRequestObservationConventionspring-doc.cadn.net.cn

import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;

import org.springframework.http.server.observation.DefaultServerRequestObservationConvention;
import org.springframework.http.server.observation.ServerRequestObservationContext;

public class ExtendedServerRequestObservationConvention extends DefaultServerRequestObservationConvention {

	@Override
	public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
		// here, we just want to have an additional KeyValue to the observation, keeping the default values
		return super.getLowCardinalityKeyValues(context).and(custom(context));
	}

	private KeyValue custom(ServerRequestObservationContext context) {
		return KeyValue.of("custom.method", context.getCarrier().getMethod());
	}

}

如果你希望拥有完全的控制权,可以为你所关注的观测实现完整的约定契约:spring-doc.cadn.net.cn

import java.util.Locale;

import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;

import org.springframework.http.server.observation.ServerHttpObservationDocumentation;
import org.springframework.http.server.observation.ServerRequestObservationContext;
import org.springframework.http.server.observation.ServerRequestObservationConvention;

public class CustomServerRequestObservationConvention implements ServerRequestObservationConvention {

	@Override
	public String getName() {
		// will be used as the metric name
		return "http.server.requests";
	}

	@Override
	public String getContextualName(ServerRequestObservationContext context) {
		// will be used for the trace name
		return "http " + context.getCarrier().getMethod().toLowerCase(Locale.ROOT);
	}

	@Override
	public KeyValues getLowCardinalityKeyValues(ServerRequestObservationContext context) {
		return KeyValues.of(method(context), status(context), exception(context));
	}


	@Override
	public KeyValues getHighCardinalityKeyValues(ServerRequestObservationContext context) {
		return KeyValues.of(httpUrl(context));
	}

	private KeyValue method(ServerRequestObservationContext context) {
		// You should reuse as much as possible the corresponding ObservationDocumentation for key names
		return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod());
	}

	// status(), exception(), httpUrl()...

	private KeyValue status(ServerRequestObservationContext context) {
		return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, String.valueOf(context.getResponse().getStatus()));
	}

	private KeyValue exception(ServerRequestObservationContext context) {
		String exception = (context.getError() != null ? context.getError().getClass().getSimpleName() : KeyValue.NONE_VALUE);
		return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, exception);
	}

	private KeyValue httpUrl(ServerRequestObservationContext context) {
		return KeyValue.of(ServerHttpObservationDocumentation.HighCardinalityKeyNames.HTTP_URL, context.getCarrier().getRequestURI());
	}

}

你也可以通过使用自定义的 ObservationFilter 来实现类似的目标——为观测(observation)添加或移除键值。 过滤器不会替换默认的约定,而是作为后处理组件使用。spring-doc.cadn.net.cn

import io.micrometer.common.KeyValue;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationFilter;

import org.springframework.http.server.observation.ServerRequestObservationContext;

public class ServerRequestObservationFilter implements ObservationFilter {

	@Override
	public Observation.Context map(Observation.Context context) {
		if (context instanceof ServerRequestObservationContext serverContext) {
			context.setName("custom.observation.name");
			context.addLowCardinalityKeyValue(KeyValue.of("project", "spring"));
			String customAttribute = (String) serverContext.getCarrier().getAttribute("customAttribute");
			context.addLowCardinalityKeyValue(KeyValue.of("custom.attribute", customAttribute));
		}
		return context;
	}
}

你可以在 ObservationFilter 上配置 ObservationRegistry 实例。spring-doc.cadn.net.cn

@Scheduled 任务的可观测性支持

每次执行 @Scheduled 任务 时,都会创建一个观测记录。 应用程序需要在 ScheduledTaskRegistrar 上配置 ObservationRegistry,以启用观测记录的采集。 这可以通过声明一个设置观测注册表的 SchedulingConfigurer Bean 来实现:spring-doc.cadn.net.cn

import io.micrometer.observation.ObservationRegistry;

import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

public class ObservationSchedulingConfigurer implements SchedulingConfigurer {

	private final ObservationRegistry observationRegistry;

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

	@Override
	public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
		taskRegistrar.setObservationRegistry(this.observationRegistry);
	}

}

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

默认情况下,会创建以下 KeyValuesspring-doc.cadn.net.cn

表2. 低基数键

code.function (必填)spring-doc.cadn.net.cn

被安排执行的 Java Method 的名称。spring-doc.cadn.net.cn

code.namespace (必填)spring-doc.cadn.net.cn

持有调度方法的 Bean 实例所属类的规范名称,对于匿名类则为 "ANONYMOUS"spring-doc.cadn.net.cn

error (必填)spring-doc.cadn.net.cn

执行期间抛出的异常的类名,如果没有发生异常,则为 "none"spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

outcome (必填)spring-doc.cadn.net.cn

方法执行的结果。可以是 "SUCCESS""ERROR""UNKNOWN"(例如,操作在执行过程中被取消)。spring-doc.cadn.net.cn

JMS 消息传递插桩

如果类路径中包含 io.micrometer:micrometer-jakarta9 依赖,Spring Framework 将使用 Micrometer 提供的 Jakarta JMS 指标监控功能。 io.micrometer.jakarta9.instrument.jms.JmsInstrumentation 会对 jakarta.jms.Session 进行监控,并记录相关的观测数据。spring-doc.cadn.net.cn

此插桩将创建两种类型的观测:spring-doc.cadn.net.cn

  • "jms.message.publish" 当 JMS 消息发送到代理(broker)时触发,通常通过 JmsTemplate 发送。spring-doc.cadn.net.cn

  • "jms.message.process" 当应用程序处理 JMS 消息时触发,通常通过 MessageListener 或带有 @JmsListener 注解的方法实现。spring-doc.cadn.net.cn

目前没有针对 "jms.message.receive" 观测的埋点,因为测量等待接收消息所花费的时间几乎没有价值。 此类集成通常会对 MessageConsumer#receive 方法调用进行埋点。但一旦这些方法返回,处理时间就无法被测量,且追踪上下文也无法传播到应用程序中。

默认情况下,这两个观测共享同一组可能的KeyValuesspring-doc.cadn.net.cn

表3. 低基数键

消息传递操作期间抛出的异常的类名(或“none”)。spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

messaging.destination.temporary (必填)spring-doc.cadn.net.cn

目标是否为 TemporaryQueueTemporaryTopic(取值:"true""false")。spring-doc.cadn.net.cn

messaging.operation (必填)spring-doc.cadn.net.cn

正在执行的 JMS 操作的名称(取值:"publish""process")。spring-doc.cadn.net.cn

表4. 高基数键

messaging.message.conversation_idspring-doc.cadn.net.cn

JMS 消息的关联 ID。spring-doc.cadn.net.cn

messaging.destination.namespring-doc.cadn.net.cn

当前消息所发送到的目标名称。spring-doc.cadn.net.cn

messaging.message.idspring-doc.cadn.net.cn

消息系统用作消息标识符的值。spring-doc.cadn.net.cn

JMS 消息发布插桩

"jms.message.publish" 观测记录在 JMS 消息发送到代理(broker)时生成。 它们用于测量发送消息所花费的时间,并通过传出的 JMS 消息头传播追踪信息。spring-doc.cadn.net.cn

您需要在 ObservationRegistry 上配置 JmsTemplate 以启用观测功能:spring-doc.cadn.net.cn

import io.micrometer.observation.ObservationRegistry;
import jakarta.jms.ConnectionFactory;

import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;

public class JmsTemplatePublish {

	private final JmsTemplate jmsTemplate;

	private final JmsMessagingTemplate jmsMessagingTemplate;

	public JmsTemplatePublish(ObservationRegistry observationRegistry, ConnectionFactory connectionFactory) {
		this.jmsTemplate = new JmsTemplate(connectionFactory);
		// configure the observation registry
		this.jmsTemplate.setObservationRegistry(observationRegistry);

		// For JmsMessagingTemplate, instantiate it with a JMS template that has a configured registry
		this.jmsMessagingTemplate = new JmsMessagingTemplate(this.jmsTemplate);
	}

	public void sendMessages() {
		this.jmsTemplate.convertAndSend("spring.observation.test", "test message");
	}

}

默认使用 io.micrometer.jakarta9.instrument.jms.DefaultJmsPublishObservationConvention,其底层由 io.micrometer.jakarta9.instrument.jms.JmsPublishObservationContext 支持。spring-doc.cadn.net.cn

当监听器方法返回响应消息时,使用 @JmsListener 注解的方法也会记录类似的观察结果。spring-doc.cadn.net.cn

JMS 消息处理仪器化

"jms.message.process" 观测记录在应用程序处理 JMS 消息时生成。 它们用于测量处理消息所花费的时间,并通过传入的 JMS 消息头传播追踪上下文。spring-doc.cadn.net.cn

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

import io.micrometer.observation.ObservationRegistry;
import jakarta.jms.ConnectionFactory;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;

@Configuration
@EnableJms
public class JmsConfiguration {

	@Bean
	public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory, ObservationRegistry observationRegistry) {
		DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory);
		factory.setObservationRegistry(observationRegistry);
		return factory;
	}

}

需要默认的容器工厂来启用注解支持, 但请注意,@JmsListener 注解可以引用特定的容器工厂 Bean 以实现特定目的。 在所有情况下,只有当容器工厂上配置了观测注册表(observation registry)时,才会记录观测数据(Observations)。spring-doc.cadn.net.cn

当消息由 JmsTemplate 处理时,MessageListener 会记录类似的观察结果。 此类监听器是在会话回调(参见 MessageConsumer)中设置到 JmsTemplate.execute(SessionCallback<T>) 上的。spring-doc.cadn.net.cn

此观测(observation)默认使用 io.micrometer.jakarta9.instrument.jms.DefaultJmsProcessObservationConvention,其底层由 io.micrometer.jakarta9.instrument.jms.JmsProcessObservationContext 支持。spring-doc.cadn.net.cn

HTTP 服务器插桩

对于 Servlet 和响应式(Reactive)应用程序,HTTP 服务器交换观测指标会以名称 "http.server.requests" 创建; 如果使用 OpenTelemetry 规范,则名称为 "http.server.request.duration"spring-doc.cadn.net.cn

Servlet 应用程序

应用程序需要在其应用中配置 org.springframework.web.filter.ServerHttpObservationFilter Servlet 过滤器。spring-doc.cadn.net.cn

仅当 Exception 未被 Web 框架处理并冒泡至 Servlet 过滤器时,才会将此次观测记录为错误。 通常,由 Spring MVC 的 @ExceptionHandlerProblemDetail 支持 处理的所有异常都不会被记录到该观测中。 您可以在请求处理的任何阶段,自行在 ObservationContext 上设置错误字段:spring-doc.cadn.net.cn

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.filter.ServerHttpObservationFilter;

@Controller
public class UserController {

	@ExceptionHandler(MissingUserException.class)
	ResponseEntity<Void> handleMissingUser(HttpServletRequest request, MissingUserException exception) {
		// We want to record this exception with the observation
		ServerHttpObservationFilter.findObservationContext(request)
				.ifPresent(context -> context.setError(exception));
		return ResponseEntity.notFound().build();
	}

	static class MissingUserException extends RuntimeException {
	}

}
由于该检测(instrumentation)是在 Servlet 过滤器(Filter)级别完成的,因此观测范围(observation scope)仅涵盖排在此过滤器之后的其他过滤器以及请求的处理过程。 通常,Servlet 容器的错误处理是在更低的层级执行的,不会有任何活跃的观测(observation)或跨度(span)。 针对这种使用场景,需要容器特定的实现方式,例如 Tomcat 中的 org.apache.catalina.Valve;这超出了本项目的范围。

默认语义约定

默认使用 org.springframework.http.server.observation.DefaultServerRequestObservationConvention,其底层由 ServerRequestObservationContext 支持。spring-doc.cadn.net.cn

默认情况下,会创建以下 KeyValuesspring-doc.cadn.net.cn

表5. 低基数键

error (必填)spring-doc.cadn.net.cn

交换过程中抛出的异常的类名,如果未发生异常,则为 "none"spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

method (必填)spring-doc.cadn.net.cn

HTTP 请求方法的名称,如果该方法不是已知的标准方法,则为 "none"spring-doc.cadn.net.cn

outcome (必填)spring-doc.cadn.net.cn

HTTP 服务器交换的结果。spring-doc.cadn.net.cn

status (必填)spring-doc.cadn.net.cn

HTTP 响应的原始状态码,如果未创建响应,则为 "UNKNOWN"spring-doc.cadn.net.cn

uri (必填)spring-doc.cadn.net.cn

匹配处理器的 URI 模式(如果可用),否则对于 3xx 响应回退为 REDIRECTION,对于 404 响应回退为 NOT_FOUND,对于没有路径信息的请求回退为 root,对于所有其他请求回退为 UNKNOWNspring-doc.cadn.net.cn

表6. 高基数键

http.url (必填)spring-doc.cadn.net.cn

HTTP 请求 URI。spring-doc.cadn.net.cn

OpenTelemetry 语义约定

提供了一个 OpenTelemetry 变体,由 org.springframework.http.server.observation.OpenTelemetryServerRequestObservationConvention 支持,对应的类为 ServerRequestObservationContextspring-doc.cadn.net.cn

响应式应用程序

应用程序需要使用 WebHttpHandlerBuilder 配置 MeterRegistry 以启用服务器端监控。 这可以通过 WebHttpHandlerBuilder 完成,如下所示:spring-doc.cadn.net.cn

import io.micrometer.observation.ObservationRegistry;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;

@Configuration(proxyBeanMethods = false)
public class HttpHandlerConfiguration {

	private final ApplicationContext applicationContext;

	public HttpHandlerConfiguration(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	@Bean
	public HttpHandler httpHandler(ObservationRegistry registry) {
		return WebHttpHandlerBuilder.applicationContext(this.applicationContext)
				.observationRegistry(registry)
				.build();
	}
}

默认使用 org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention,其底层由 ServerRequestObservationContext 支持。spring-doc.cadn.net.cn

仅当 Exception 未被应用程序 Controller 处理时,才会将此次观测记录为错误。 通常,由 Spring WebFlux 的 @ExceptionHandlerProblemDetail 支持 处理的所有异常都不会被记录到观测中。 您可以在请求处理的任何阶段,自行在 ObservationContext 上设置错误字段:spring-doc.cadn.net.cn

import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.server.ServerWebExchange;

@Controller
public class UserController {

	@ExceptionHandler(MissingUserException.class)
	ResponseEntity<Void> handleMissingUser(ServerWebExchange exchange, MissingUserException exception) {
		// We want to record this exception with the observation
		ServerRequestObservationContext.findCurrent(exchange.getAttributes())
				.ifPresent(context -> context.setError(exception));
		return ResponseEntity.notFound().build();
	}

	static class MissingUserException extends RuntimeException {
	}

}

默认情况下,会创建以下 KeyValuesspring-doc.cadn.net.cn

表7. 低基数键

error (必填)spring-doc.cadn.net.cn

交换过程中抛出的异常的类名,如果未发生异常,则为 "none"spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

method (必填)spring-doc.cadn.net.cn

HTTP 请求方法的名称,如果该方法不是已知的标准方法,则为 "none"spring-doc.cadn.net.cn

outcome (必填)spring-doc.cadn.net.cn

HTTP 服务器交换的结果。spring-doc.cadn.net.cn

status (必填)spring-doc.cadn.net.cn

HTTP 响应的原始状态码,如果未创建响应,则为 "UNKNOWN"spring-doc.cadn.net.cn

uri (必填)spring-doc.cadn.net.cn

匹配处理器的 URI 模式(如果可用),否则对于 3xx 响应回退为 REDIRECTION,对于 404 响应回退为 NOT_FOUND,对于没有路径信息的请求回退为 root,对于所有其他请求回退为 UNKNOWNspring-doc.cadn.net.cn

表8. 高基数键

http.url (必填)spring-doc.cadn.net.cn

HTTP 请求 URI。spring-doc.cadn.net.cn

HTTP 客户端插桩

HTTP 客户端交换观测(observations)会为阻塞式和响应式客户端创建,其名称为 "http.client.requests"。 该观测衡量整个 HTTP 请求/响应交换过程,从建立连接一直到响应体反序列化完成。 与服务器端的对应机制不同,该仪器化(instrumentation)直接在客户端中实现,因此唯一需要的步骤就是在客户端上配置一个 ObservationRegistryspring-doc.cadn.net.cn

RestTemplate

应用程序必须在 ObservationRegistry 实例上配置一个 RestTemplate 才能启用仪器化;否则,观测操作将变为“空操作”(no-ops)。 Spring Boot 会自动配置已设置好观测注册表(observation registry)的 RestTemplateBuilder Bean。spring-doc.cadn.net.cn

Instrumentation 默认使用 org.springframework.http.client.observation.ClientRequestObservationConvention,其底层由 ClientRequestObservationContext 支持。spring-doc.cadn.net.cn

表9. 低基数键

method (必填)spring-doc.cadn.net.cn

HTTP 请求方法的名称,如果该方法不是已知的标准方法,则为 "none"spring-doc.cadn.net.cn

uri (必填)spring-doc.cadn.net.cn

用于 HTTP 请求的 URI 模板,如果未提供则为 "none"。URI 中的协议、主机和端口部分不被考虑。spring-doc.cadn.net.cn

client.name (必填)spring-doc.cadn.net.cn

从请求 URI 的主机名派生的客户端名称。spring-doc.cadn.net.cn

status (必填)spring-doc.cadn.net.cn

HTTP 响应的原始状态码,如果发生 "IO_ERROR" 则为 IOException,如果未收到响应则为 "CLIENT_ERROR"spring-doc.cadn.net.cn

outcome (必填)spring-doc.cadn.net.cn

HTTP 客户端交换的结果。spring-doc.cadn.net.cn

error (必填)spring-doc.cadn.net.cn

交换过程中抛出的异常的类名,如果未发生异常,则为 "none"spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

表10. 高基数键

http.url (必填)spring-doc.cadn.net.cn

HTTP 请求 URI。spring-doc.cadn.net.cn

REST 客户端

应用程序必须在 ObservationRegistry 上配置一个 RestClient.Builder 以启用监控;否则,监控操作将被视为“空操作”(no-ops)。spring-doc.cadn.net.cn

Instrumentation 默认使用 org.springframework.http.client.observation.ClientRequestObservationConvention,其底层由 ClientRequestObservationContext 支持。spring-doc.cadn.net.cn

表11. 低基数键

method (必填)spring-doc.cadn.net.cn

HTTP 请求方法的名称,如果请求无法创建,则为 "none"spring-doc.cadn.net.cn

uri (必填)spring-doc.cadn.net.cn

用于 HTTP 请求的 URI 模板,如果未提供则为 "none"。URI 中的协议、主机和端口部分不被考虑。spring-doc.cadn.net.cn

client.name (必填)spring-doc.cadn.net.cn

从请求 URI 的主机名派生的客户端名称。spring-doc.cadn.net.cn

status (必填)spring-doc.cadn.net.cn

HTTP 响应的原始状态码,如果发生 "IO_ERROR" 则为 IOException,如果未收到响应则为 "CLIENT_ERROR"spring-doc.cadn.net.cn

outcome (必填)spring-doc.cadn.net.cn

HTTP 客户端交换的结果。spring-doc.cadn.net.cn

error (必填)spring-doc.cadn.net.cn

交换过程中抛出的异常的类名,如果未发生异常,则为 "none"spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

表12. 高基数键

http.url (必填)spring-doc.cadn.net.cn

HTTP 请求 URI。spring-doc.cadn.net.cn

WebClient

应用程序必须在 ObservationRegistry 上配置一个 WebClient.Builder 以启用监控功能;否则,监控操作将被视为“空操作”(no-ops)。 Spring Boot 会自动配置已设置好观察注册表(observation registry)的 WebClient.Builder Bean。spring-doc.cadn.net.cn

Instrumentation 默认使用 org.springframework.web.reactive.function.client.ClientRequestObservationConvention,其底层由 ClientRequestObservationContext 支持。spring-doc.cadn.net.cn

表13. 低基数键

method (必填)spring-doc.cadn.net.cn

HTTP 请求方法的名称,如果该方法不是已知的标准方法,则为 "none"spring-doc.cadn.net.cn

uri (必填)spring-doc.cadn.net.cn

用于 HTTP 请求的 URI 模板,如果未提供则为 "none"。URI 中的协议、主机和端口部分不被考虑。spring-doc.cadn.net.cn

client.name (必填)spring-doc.cadn.net.cn

从请求 URI 的主机名派生的客户端名称。spring-doc.cadn.net.cn

status (必填)spring-doc.cadn.net.cn

HTTP 响应的原始状态码,如果发生 "IO_ERROR" 则为 IOException,如果未收到响应则为 "CLIENT_ERROR"spring-doc.cadn.net.cn

outcome (必填)spring-doc.cadn.net.cn

HTTP 客户端交换的结果。spring-doc.cadn.net.cn

error (必填)spring-doc.cadn.net.cn

交换过程中抛出的异常的类名,如果未发生异常,则为 "none"spring-doc.cadn.net.cn

exception (已弃用)spring-doc.cadn.net.cn

复制了 error 键,将来可能会被移除。spring-doc.cadn.net.cn

表14. 高基数键

http.url (必填)spring-doc.cadn.net.cn

HTTP 请求 URI。spring-doc.cadn.net.cn

应用程序事件和@EventListener

Spring Framework 不会为 @EventListener 调用 提供观测数据, 因为它们不具备此类埋点所需的正确语义。 默认情况下,事件的发布和处理是同步且在同一线程上完成的。 这意味着在该任务执行期间,ThreadLocal 变量和日志上下文将与事件发布者保持一致。spring-doc.cadn.net.cn

如果应用程序全局配置了一个自定义的 ApplicationEventMulticaster,并且该多播器使用的策略是在不同线程上调度事件处理,那么上述情况就不再成立。 所有 @EventListener 方法都将在不同于主事件发布线程的其他线程上执行。 在这种情况下,Micrometer 上下文传播库 可以帮助传播此类值,并更好地关联事件的处理过程。 应用程序可以配置所选的 TaskExecutor,使其使用一个 ContextPropagatingTaskDecorator 来装饰任务并传播上下文。 要实现此功能,类路径中必须包含 io.micrometer:context-propagation 库:spring-doc.cadn.net.cn

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.support.ContextPropagatingTaskDecorator;

@Configuration
public class ApplicationEventsConfiguration {

	@Bean(name = "applicationEventMulticaster")
	public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster() {
		SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
		SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
		// decorate task execution with a decorator that supports context propagation
		taskExecutor.setTaskDecorator(new ContextPropagatingTaskDecorator());
		eventMulticaster.setTaskExecutor(taskExecutor);
		return eventMulticaster;
	}

}

同样地,如果为每个使用 @EventListener 注解的方法本地地做出异步选择,即在该方法上添加 @Async 注解, 你可以通过引用其限定符(qualifier)来选择一个能够传播上下文的 TaskExecutor。 假设有如下配置了专用任务装饰器(task decorator)的 TaskExecutor Bean 定义:spring-doc.cadn.net.cn

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.support.ContextPropagatingTaskDecorator;

@Configuration
public class EventAsyncExecutionConfiguration {

	@Bean(name = "propagatingContextExecutor")
	public TaskExecutor propagatingContextExecutor() {
		SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
		// decorate task execution with a decorator that supports context propagation
		taskExecutor.setTaskDecorator(new ContextPropagatingTaskDecorator());
		return taskExecutor;
	}

}

使用 @Async 注解和相应的限定符对事件监听器进行标注,可以实现类似的上下文传播效果:spring-doc.cadn.net.cn

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

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class EmailNotificationListener {

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

	@EventListener(EmailReceivedEvent.class)
	@Async("propagatingContextExecutor")
	public void emailReceived(EmailReceivedEvent event) {
		// asynchronously process the received event
		// this logging statement will contain the expected MDC entries from the propagated context
		logger.info("email has been received");
	}

}