对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
可观测性支持
Micrometer 定义了一个 Observation 概念,该概念在应用程序中同时启用 Metrics 和 Traces。 Metrics Support 提供了一种创建计时器、仪表或计数器的方法,用于收集有关应用程序运行时行为的统计信息。 指标可以帮助您跟踪错误率、使用模式、性能等。 跟踪提供了整个系统的整体视图,跨越了应用程序边界;您可以放大特定用户请求,并跟踪它们在应用程序中的整个完成情况。
Spring 框架检测其自身代码库的各个部分以发布观察结果,如果ObservationRegistry
已配置。
您可以了解有关在 Spring Boot 中配置可观测性基础设施的更多信息。
生成的 Observation 列表
Spring Framework 检测各种功能以实现可观察性。 如本节开头所述,观察可以生成计时器指标和/或跟踪,具体取决于配置。
观察项名称 | 描述 |
---|---|
HTTP 客户端交换所花费的时间 |
|
框架级别的 HTTP 服务器交换的处理时间 |
观测使用 Micrometer 的官方命名约定,但 Metrics 名称将自动转换为监控系统后端首选的格式(Prometheus、Atlas、Graphite、InfluxDB 等)。 |
千分尺观察概念
如果您不熟悉千分尺观察,以下是您应该了解的概念的快速总结。
-
Observation
是应用程序中发生的事情的实际记录。这由ObservationHandler
实现来生成指标或跟踪。 -
每个观察结果都有一个对应的
ObservationContext
实现;此类型包含用于提取其元数据的所有相关信息。 对于 HTTP 服务器观察,上下文实现可以保存 HTTP 请求、HTTP 响应、处理过程中引发的任何异常等。 -
每
Observation
保留KeyValues
元数据。对于 HTTP 服务器观察,这可能是 HTTP 请求方法、HTTP 响应状态等。 此元数据由ObservationConvention
应该声明ObservationContext
他们支持。 -
KeyValues
如果KeyValue
tuple (HTTP 方法就是一个很好的例子)。 低基数值仅贡献给量度。 相反,“高基数”值是无限的(例如,HTTP 请求 URI),并且仅参与跟踪。 -
一
ObservationDocumentation
记录特定域中的所有观察结果,列出预期的键名称及其含义。
配置观测
全局配置选项位于ObservationRegistry#observationConfig()
水平。
每个 instrumented 组件将提供两个扩展点:
-
设置
ObservationRegistry
;如果未设置,则不会记录观测值,并且将为 NO-OPS -
提供自定义
ObservationConvention
更改默认观测项名称和提取的KeyValues
使用自定义 Observation 约定
让我们以 Spring MVC“http.server.requests”指标插桩为例,其中ServerHttpObservationFilter
.
此观察使用ServerRequestObservationConvention
替换为ServerRequestObservationContext
;可以在 Servlet 过滤器上配置自定义约定。
如果要自定义使用观察生成的元数据,可以扩展DefaultServerRequestObservationConvention
根据您的要求:
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());
}
}
如果您想要完全控制,您可以为您感兴趣的观察实现整个约定协定:
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
– 添加或删除观察的关键值。
过滤器不会替换默认约定,而是用作后处理组件。
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
.
HTTP 服务器检测
HTTP 服务器交换观察是使用名称"http.server.requests"
适用于 Servlet 和 Reactive 应用程序。
Servlet 应用程序
应用程序需要配置org.springframework.web.filter.ServerHttpObservationFilter
Servlet 过滤器。
它使用org.springframework.http.server.observation.DefaultServerRequestObservationConvention
默认情况下,由ServerRequestObservationContext
.
这只会在出现Exception
尚未由 Web 框架处理,并且已冒泡到 Servlet 过滤器。
通常,所有异常都由 Spring MVC 的@ExceptionHandler
和ProblemDetail
支持不会与观测值一起记录。
在请求处理过程中,您可以随时在ObservationContext
你自己:
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 级别完成的,因此观察范围仅涵盖在此过滤器之后排序的过滤器以及请求的处理。
通常,Servlet 容器错误处理在较低级别执行,并且不会有任何活动的观察或 span。
对于此用例,需要特定于容器的实现,例如org.apache.catalina.Valve 对于 Tomcat;这超出了本项目的范围。 |
默认情况下,以下KeyValues
创建:
名字 |
描述 |
|
交换期间引发的异常的名称,或 |
|
HTTP 请求方法的名称或 |
|
HTTP 服务器交换的结果。 |
|
HTTP 响应原始状态代码,或 |
|
匹配处理程序的 URI 模式(如果可用),回退到 |
名字 |
描述 |
|
HTTP 请求 URI。 |
响应式应用程序
应用程序需要配置org.springframework.web.filter.reactive.ServerHttpObservationFilter
反应性的WebFilter
在他们的应用程序中。
它使用org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention
默认情况下,由ServerRequestObservationContext
.
这只会在出现Exception
尚未由 Web 框架处理,并且已冒泡到WebFilter
.
通常,所有异常都由 Spring WebFlux 的@ExceptionHandler
和ProblemDetail
支持不会与观测值一起记录。
在请求处理过程中,您可以随时在ObservationContext
你自己:
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 {
}
}
默认情况下,以下KeyValues
创建:
名字 |
描述 |
|
交换期间引发的异常的名称,或 |
|
HTTP 请求方法的名称或 |
|
HTTP 服务器交换的结果。 |
|
HTTP 响应原始状态代码,或 |
|
匹配处理程序的 URI 模式(如果可用),回退到 |
名字 |
描述 |
|
HTTP 请求 URI。 |
HTTP 客户端检测
HTTP 客户端交换观察是使用名称"http.client.requests"
用于阻塞和反应式客户端。
与服务器对应项不同,插桩直接在客户端中实现,因此唯一需要的步骤是配置ObservationRegistry
在客户端上。
RestTemplate (休息模板)
应用程序必须配置ObservationRegistry
上RestTemplate
实例来启用插桩;没有它,观察就是 “无作”。
Spring Boot 将自动配置RestTemplateBuilder
已经设置了 observation 注册表的 bean。
插桩使用org.springframework.http.client.observation.ClientRequestObservationConvention
默认情况下,由ClientRequestObservationContext
.
名字 |
描述 |
|
HTTP 请求方法的名称或 |
|
用于 HTTP 请求的 URI 模板,或 |
|
从请求 URI 主机派生的客户端名称。 |
|
HTTP 响应原始状态代码,或 |
|
HTTP 客户端交换的结果。 |
|
交换期间引发的异常的名称,或 |
名字 |
描述 |
|
HTTP 请求 URI。 |
Web客户端
应用程序必须配置ObservationRegistry
在WebClient
builder 启用插桩;没有它,观察就是 “无作”。
Spring Boot 将自动配置WebClient.Builder
已经设置了 observation 注册表的 bean。
插桩使用org.springframework.web.reactive.function.client.ClientRequestObservationConvention
默认情况下,由ClientRequestObservationContext
.
名字 |
描述 |
|
HTTP 请求方法的名称或 |
|
用于 HTTP 请求的 URI 模板,或 |
|
从请求 URI 主机派生的客户端名称。 |
|
HTTP 响应原始状态代码,或 |
|
HTTP 客户端交换的结果。 |
|
交换期间引发的异常的名称,或 |
名字 |
描述 |
|
HTTP 请求 URI。 |