对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

可观测性支持

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

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

生成的观测列表

Spring 框架为可观察性提供了多种功能。 如本节开头所述,根据配置,观测可以生成计时器指标和/或跟踪信息。spring-doc.cadn.net.cn

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

"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

观测值使用 Micrometer 的官方命名规范,但指标名称会自动转换为 监控系统后端所偏好的格式 (Prometheus、Atlas、Graphite、InfluxDB……)。

Micrometer Observation 概念

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

  • Observation 是对应用程序中发生的事件的实际记录。这由 ObservationHandler 实现处理以生成指标或跟踪信息。spring-doc.cadn.net.cn

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

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

  • KeyValues 如果 KeyValue 元组的可能值数量较少且有界,则被称为“低基数”(HTTP 方法就是一个很好的例子)。 低基数值仅被计入指标中。 相反,“高基数”值是无界的(例如,HTTP 请求 URI),仅被计入追踪中。spring-doc.cadn.net.cn

  • 一个 ObservationDocumentation 文档会记录特定领域内的所有观测结果,列出预期的键名称及其含义。spring-doc.cadn.net.cn

配置观测

全局配置选项位于 ObservationRegistry#observationConfig() 级别。 每个被检测的组件将提供两个扩展点:spring-doc.cadn.net.cn

  • 设置 ObservationRegistry;如果不设置,观测数据将不会被记录,且操作将无效spring-doc.cadn.net.cn

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

使用自定义的观察(Observation)约定

以 Spring MVC "http.server.requests" 指标监控为例,结合 ServerHttpObservationFilter 进行说明。 该观测使用了带有 ServerRequestObservationContextServerRequestObservationConvention;可以在 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 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();
	}

	@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 来实现类似的目标——为观测值添加或删除键值。 过滤器不会取代默认约定,而是作为后处理组件使用。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;
	}
}

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

HTTP 服务器检测

对于Servlet和响应式应用程序,HTTP服务器交换观测的名称为 "http.server.requests"spring-doc.cadn.net.cn

Servlet 应用

应用程序需要在其应用中配置 org.springframework.web.filter.ServerHttpObservationFilter Servlet 过滤器。 它默认使用 org.springframework.http.server.observation.DefaultServerRequestObservationConvention,由 ServerRequestObservationContext 提供支持。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 {
	}

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

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

表 2. 低基数键

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

交换期间抛出的异常名称,如果没有发生异常则为 KeyValue#NONE_VALUEspring-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

表 3. 高基数键

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

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

响应式应用

应用程序需要在其应用中配置 org.springframework.web.filter.reactive.ServerHttpObservationFilter 响应式 WebFilter。 默认使用 org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention,由 ServerRequestObservationContext 提供支持。spring-doc.cadn.net.cn

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

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
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
		ServerHttpObservationFilter.findObservationContext(exchange)
				.ifPresent(context -> context.setError(exception));
		return ResponseEntity.notFound().build();
	}

	static class MissingUserException extends RuntimeException {
	}

}

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

表 4. 低基数键

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

交换期间抛出的异常名称,如果没有发生异常则为 "none"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

表 5. 高基数键

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

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

HTTP 客户端检测

HTTP 客户端交换观测值的名称为 "http.client.requests",用于阻塞和响应式客户端。 与服务器端对应的功能不同,该检测功能直接在客户端中实现,因此唯一需要的步骤是在客户端上配置一个 ObservationRegistryspring-doc.cadn.net.cn

RestTemplate

应用程序必须在 RestTemplate 实例上配置 ObservationRegistry 以启用检测;否则,观测将为“空操作”。 Spring Boot 将自动配置已设置观察注册表的 RestTemplateBuilder bean。spring-doc.cadn.net.cn

监控功能默认使用 org.springframework.http.client.observation.ClientRequestObservationConvention,由 ClientRequestObservationContext 提供支持。spring-doc.cadn.net.cn

表 6. 低基数键

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响应的原始状态码,如果出现IOException的情况则为"IO_ERROR",如果没有收到响应则为"CLIENT_ERROR"spring-doc.cadn.net.cn

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

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

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

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

表 7. 高基数键

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

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

WebClient

应用程序必须在 WebClient 构建器上配置一个 ObservationRegistry 以启用监控功能;否则,观测操作将是“无效操作”。 Spring Boot 将自动配置已设置好观测注册表的 WebClient.Builder Bean。spring-doc.cadn.net.cn

监控功能默认使用 org.springframework.web.reactive.function.client.ClientRequestObservationConvention,由 ClientRequestObservationContext 提供支持。spring-doc.cadn.net.cn

表 8. 低基数键

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响应的原始状态码,如果出现IOException的情况则为"IO_ERROR",如果没有收到响应则为"CLIENT_ERROR"spring-doc.cadn.net.cn

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

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

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

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

表 9. 高基数键

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

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