Observability
可观测性(Observability)是指从外部观察运行中系统内部状态的能力。它由三大支柱组成:日志(logging)、指标(metrics)和追踪(traces)。
对于指标(metrics)和追踪(traces),Spring Boot 使用 Micrometer Observation。要创建你自己的观测(observations)(这将生成指标和追踪),你可以注入一个 ObservationRegistry。
- Java
- Kotlin
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.stereotype.Component;
@Component
public class MyCustomObservation {
private final ObservationRegistry observationRegistry;
public MyCustomObservation(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
public void doSomething() {
Observation.createNotStarted("doSomething", this.observationRegistry)
.lowCardinalityKeyValue("locale", "en-US")
.highCardinalityKeyValue("userId", "42")
.observe(() -> {
// Execute business logic here
});
}
}
import io.micrometer.observation.Observation
import io.micrometer.observation.ObservationRegistry;
import org.springframework.stereotype.Component
@Component
class MyCustomObservation(private val observationRegistry: ObservationRegistry) {
fun doSomething() {
Observation.createNotStarted("doSomething", observationRegistry)
.lowCardinalityKeyValue("locale", "en-US")
.highCardinalityKeyValue("userId", "42")
.observe {
// Execute business logic here
}
}
}
低基数(low cardinality)标签将被添加到指标和追踪中,而高基数(high cardinality)标签仅会被添加到追踪中。
类型为 ObservationPredicate、GlobalObservationConvention、ObservationFilter 和 ObservationHandler 的 Bean 将自动注册到 ObservationRegistry 上。你还可以额外注册任意数量的 ObservationRegistryCustomizer Bean,以进一步配置该 registry。
JDBC 的可观测性可以通过一个独立的项目进行配置。Datasource Micrometer 项目 提供了一个 Spring Boot Starter,可在调用 JDBC 操作时自动创建观测数据。更多详情请参阅 参考文档。
R2DBC 的可观测性已内置于 Spring Boot 中。要启用它,请在项目中添加 io.r2dbc:r2dbc-proxy 依赖。
Context Propagation
可观测性支持依赖于 Context Propagation library 来在线程和响应式管道之间传递当前的观测上下文。默认情况下,ThreadLocal 的值不会在响应式操作符中自动恢复。该行为由 spring.reactor.context-propagation 属性控制,可将其设置为 auto 以启用自动传播。
如果你正在使用 @Async 方法或使用 AsyncTaskExecutor,则必须在执行器(executor)上注册 ContextPropagatingTaskDecorator,否则在线程切换时会丢失可观测性上下文(observability context)。可以通过以下配置实现:
- Java
- Kotlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.support.ContextPropagatingTaskDecorator;
@Configuration(proxyBeanMethods = false)
class ContextPropagationConfiguration {
@Bean
ContextPropagatingTaskDecorator contextPropagatingTaskDecorator() {
return new ContextPropagatingTaskDecorator();
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.support.ContextPropagatingTaskDecorator
@Configuration(proxyBeanMethods = false)
class ContextPropagationConfiguration {
@Bean
fun contextPropagatingTaskDecorator(): ContextPropagatingTaskDecorator {
return ContextPropagatingTaskDecorator()
}
}
有关 Observations 的更多详细信息,请参阅 Micrometer Observation 文档。
通用标签
通用标签通常用于对运行环境进行维度下钻,例如主机(host)、实例(instance)、区域(region)、堆栈(stack)等。通用标签会作为低基数(low cardinality)标签应用于所有观测数据,并且可以进行配置,如下例所示:
- Properties
- YAML
management.observations.key-values.region=us-east-1
management.observations.key-values.stack=prod
management:
observations:
key-values:
region: "us-east-1"
stack: "prod"
前面的示例为所有观测数据分别添加了 region 和 stack 标签,其值分别为 us-east-1 和 prod。
防止观测
如果你想阻止某些观测数据被上报,可以使用 management.observations.enable 属性:
- Properties
- YAML
management.observations.enable.denied.prefix=false
management.observations.enable.another.denied.prefix=false
management:
observations:
enable:
denied:
prefix: false
another:
denied:
prefix: false
前面的示例将阻止所有名称以 denied.prefix 或 another.denied.prefix 开头的观测。
如果想阻止 Spring Security 报告观测数据,请将属性 management.observations.enable.spring.security 设置为 false。
如果你需要对阻止观测(observations)的机制进行更精细的控制,可以注册类型为 ObservationPredicate 的 Bean。只有当所有 ObservationPredicate 类型的 Bean 对该观测都返回 true 时,该观测才会被上报。
- Java
- Kotlin
import io.micrometer.observation.Observation.Context;
import io.micrometer.observation.ObservationPredicate;
import org.springframework.stereotype.Component;
@Component
class MyObservationPredicate implements ObservationPredicate {
@Override
public boolean test(String name, Context context) {
return !name.contains("denied");
}
}
import io.micrometer.observation.Observation.Context
import io.micrometer.observation.ObservationPredicate
import org.springframework.stereotype.Component
@Component
class MyObservationPredicate : ObservationPredicate {
override fun test(name: String, context: Context): Boolean {
return !name.contains("denied")
}
}
前面的示例将阻止所有名称中包含 "denied" 的观测。
Micrometer Observation 注解支持
要启用对可观测性注解(如 @Observed、@Timed、@Counted、@MeterTag 和 @NewSpan)的扫描,请将 management.observations.annotations.enabled 属性设置为 true。此外,还需要添加对 org.aspectj:aspectjweaver 的依赖,该依赖是 spring-boot-starter-aspectj 的一部分。此功能由 Micrometer 直接支持。请参阅 Micrometer、Micrometer Observation 和 Micrometer Tracing 的参考文档。
当你对已经被自动埋点的方法或类进行注解时(例如,Spring Data 仓库 或 Spring MVC 控制器),将会产生重复的观测(observations)。在这种情况下,你可以通过 配置属性 或使用 ObservationPredicate 来禁用自动埋点,并仅依赖你的注解;或者,你也可以移除你的注解。
OpenTelemetry 支持
在你的应用程序中支持 OpenTelemetry 有多种方式。你可以使用 OpenTelemetry Java Agent 或 OpenTelemetry Spring Boot Starter,这些是由 OTel 社区支持的;其指标和追踪使用 OTel 库定义的语义约定。本文档描述的是由 Spring 团队官方支持的 OpenTelemetry 方式,即使用 Micrometer 和 OTLP 导出器;其指标和追踪使用 Spring 项目文档(例如 Spring Framework)中描述的语义约定。
Spring Boot 的 actuator 模块包含对 OpenTelemetry 的基本支持。
它提供了一个类型为 OpenTelemetry 的 Bean。如果应用上下文中存在类型为 SdkTracerProvider、ContextPropagators、SdkLoggerProvider 或 SdkMeterProvider 的 Bean,它们会自动注册。此外,它还提供了一个 Resource Bean。自动配置的 Resource 的属性可以通过 management.opentelemetry.resource-attributes 配置属性进行设置。自动配置的属性将与来自 OTEL_RESOURCE_ATTRIBUTES 和 OTEL_SERVICE_NAME 环境变量的属性合并,其中通过配置属性设置的属性优先级高于环境变量中的属性。
如果你已经定义了自己的 Resource bean,这种情况将不再成立。
Spring Boot 不提供 OpenTelemetry 指标或日志的自动导出功能。仅当与 Micrometer Tracing 一起使用时,才会自动配置 OpenTelemetry 追踪的导出。
环境变量
Spring Boot 支持以下环境变量来配置 OpenTelemetry 资源:
OTEL_RESOURCE_ATTRIBUTES 环境变量由一组键值对组成。例如:key1=value1,key2=value2,key3=spring%20boot。所有属性值均被视为字符串,且任何超出 baggage-octet 范围的字符都必须进行 百分号编码(percent-encoded)。
Micrometer 还支持以下环境变量,用于通过 OTLP 配置指标导出:
如 OpenTelemetry 文档 中所述的其他环境变量不受支持。
如果你想让 OpenTelemetry SDK 指定的所有环境变量都生效,就必须提供你自己的 OpenTelemetry bean。
这样做会关闭 Spring Boot 的 OpenTelemetry 自动配置,并可能破坏内置的可观测性功能。
首先,添加对 io.opentelemetry:opentelemetry-sdk-extension-autoconfigure 的依赖以获取 OpenTelemetry 的零代码 SDK 自动配置模块,然后添加以下配置:
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
class AutoConfiguredOpenTelemetrySdkConfiguration {
@Bean
OpenTelemetry autoConfiguredOpenTelemetrySdk() {
return AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();
}
}
日志记录
OpenTelemetryLoggingAutoConfiguration 用于配置 OpenTelemetry 的 SdkLoggerProvider。通过 OtlpLoggingAutoConfiguration 支持经由 OTLP 导出日志,该配置可启用通过 HTTP 或 gRPC 的 OTLP 日志导出功能。
然而,尽管存在一个 SdkLoggerProvider bean,Spring Boot 并不支持开箱即用地将日志桥接到该 bean。这可以通过第三方日志桥接器实现,如 使用 OpenTelemetry 进行日志记录 一节所述。
指标
Spring 产品组合中选择的指标库是 Micrometer,这意味着指标并非通过 OpenTelemetry 的 SdkMeterProvider 进行收集和导出。Spring Boot 并未提供 SdkMeterProvider Bean。
然而,如 Metrics with OTLP 一节所述,Micrometer 指标可以通过 OTLP 导出到任何支持 OpenTelemetry 的后端,使用 OtlpMeterRegistry。
Micrometer 的 OTLP registry 不使用 Resource bean,但设置 OTEL_RESOURCE_ATTRIBUTES、OTEL_SERVICE_NAME 或 management.opentelemetry.resource-attributes 是有效的。
通过 OpenTelemetry API 和 SDK 获取指标
如果你或你所包含的依赖项使用了 OpenTelemetry 的 MeterProvider,这些指标将不会被导出。
我们强烈建议你使用 Micrometer 来上报指标。如果你引入的某个依赖使用了 OpenTelemetry 的 MeterProvider,你可以在应用程序中包含以下配置来创建一个 MeterProvider Bean,然后将其注入到你的依赖中:
import java.time.Duration;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
class OpenTelemetryMetricsConfiguration {
@Bean
OtlpHttpMetricExporter metricExporter() {
String endpoint = "http://localhost:4318/v1/metrics";
return OtlpHttpMetricExporter.builder().setEndpoint(endpoint).build();
}
@Bean
PeriodicMetricReader metricReader(MetricExporter exporter) {
Duration interval = Duration.ofMinutes(1);
return PeriodicMetricReader.builder(exporter).setInterval(interval).build();
}
@Bean
SdkMeterProvider meterProvider(Resource resource, MetricReader metricReader) {
return SdkMeterProvider.builder().registerMetricReader(metricReader).setResource(resource).build();
}
}
此配置还通过 HTTP 启用 OTLP 指标导出。
Tracing
如果使用了 Micrometer tracing,OpenTelemetryTracingAutoConfiguration 会配置 OpenTelemetry 的 SdkTracerProvider。通过 OTLP 导出 traces 的功能由 OtlpTracingAutoConfiguration 启用,该配置支持通过 HTTP 或 gRPC 使用 OTLP 导出 traces。
我们强烈建议使用 Micrometer Observation 或 Tracing API,而不是直接使用 OpenTelemetry API。