diff --git a/settings.gradle b/settings.gradle index 9334004c0d..4615db379b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -100,6 +100,7 @@ include "spring-boot-project:spring-boot-liquibase" include "spring-boot-project:spring-boot-neo4j" include "spring-boot-project:spring-boot-mail" include "spring-boot-project:spring-boot-metrics" +include "spring-boot-project:spring-boot-micrometer-observation" include "spring-boot-project:spring-boot-mongodb" include "spring-boot-project:spring-boot-mustache" include "spring-boot-project:spring-boot-netty" diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure-all/build.gradle index 0b3ee85eb8..05d5f1c2b0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/build.gradle @@ -39,6 +39,7 @@ dependencies { optional(project(":spring-boot-project:spring-boot-jsonb")) optional(project(":spring-boot-project:spring-boot-kafka")) optional(project(":spring-boot-project:spring-boot-metrics")) + optional(project(":spring-boot-project:spring-boot-micrometer-observation")) optional(project(":spring-boot-project:spring-boot-opentelemetry")) optional(project(":spring-boot-project:spring-boot-r2dbc")) optional(project(":spring-boot-project:spring-boot-restclient")) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java index cbf87a3b9e..39957888a1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfiguration.java @@ -23,8 +23,6 @@ import org.glassfish.jersey.micrometer.server.ObservationApplicationEventListene import org.glassfish.jersey.server.ResourceConfig; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -34,6 +32,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer; import org.springframework.boot.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.metrics.autoconfigure.MetricsProperties; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observability/ObservabilityAutoConfiguration.java similarity index 67% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observability/ObservabilityAutoConfiguration.java index 3f56ef6691..3a5a80db99 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observability/ObservabilityAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.actuate.autoconfigure.observability; import java.util.List; @@ -22,32 +22,24 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters; import io.micrometer.core.instrument.observation.MeterObservationHandler; -import io.micrometer.observation.GlobalObservationConvention; import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationFilter; -import io.micrometer.observation.ObservationHandler; -import io.micrometer.observation.ObservationPredicate; import io.micrometer.observation.ObservationRegistry; -import io.micrometer.observation.aop.ObservedAspect; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler; import io.micrometer.tracing.handler.TracingObservationHandler; -import org.aspectj.weaver.Advice; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGrouping; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; /** * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Observation API. @@ -58,34 +50,12 @@ import org.springframework.core.annotation.Order; * @author Vedran Pavic * @since 3.0.0 */ -@AutoConfiguration(after = { CompositeMeterRegistryAutoConfiguration.class, MicrometerTracingAutoConfiguration.class }) +@AutoConfiguration( + beforeName = "org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration", + afterName = "org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration", + after = MicrometerTracingAutoConfiguration.class) @ConditionalOnClass(ObservationRegistry.class) -@EnableConfigurationProperties(ObservationProperties.class) -public class ObservationAutoConfiguration { - - @Bean - static ObservationRegistryPostProcessor observationRegistryPostProcessor( - ObjectProvider> observationRegistryCustomizers, - ObjectProvider observationPredicates, - ObjectProvider> observationConventions, - ObjectProvider> observationHandlers, - ObjectProvider observationHandlerGrouping, - ObjectProvider observationFilters) { - return new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates, - observationConventions, observationHandlers, observationHandlerGrouping, observationFilters); - } - - @Bean - @ConditionalOnMissingBean - ObservationRegistry observationRegistry() { - return ObservationRegistry.create(); - } - - @Bean - @Order(0) - PropertiesObservationFilterPredicate propertiesObservationFilter(ObservationProperties properties) { - return new PropertiesObservationFilterPredicate(properties); - } +public class ObservabilityAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(MeterRegistry.class) @@ -126,6 +96,7 @@ public class ObservationAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean(MeterRegistry.class) @ConditionalOnMissingBean(MeterObservationHandler.class) + @EnableConfigurationProperties(ObservationProperties.class) static class MeterObservationHandlerConfiguration { @ConditionalOnMissingBean(type = "io.micrometer.tracing.Tracer") @@ -158,17 +129,4 @@ public class ObservationAutoConfiguration { } - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(Advice.class) - @ConditionalOnBooleanProperty("management.observations.annotations.enabled") - static class ObservedAspectConfiguration { - - @Bean - @ConditionalOnMissingBean - ObservedAspect observedAspect(ObservationRegistry observationRegistry) { - return new ObservedAspect(observationRegistry); - } - - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observability/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observability/package-info.java new file mode 100644 index 0000000000..84e8f137c0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observability/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Auto-configuration for observability (metrics and tracing). + */ +package org.springframework.boot.actuate.autoconfigure.observability; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/batch/BatchObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/batch/BatchObservationAutoConfiguration.java index da8385415c..20a08067a0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/batch/BatchObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/batch/BatchObservationAutoConfiguration.java @@ -19,12 +19,12 @@ package org.springframework.boot.actuate.autoconfigure.observation.batch; import io.micrometer.observation.ObservationRegistry; import org.springframework.batch.core.configuration.annotation.BatchObservabilityBeanPostProcessor; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.context.annotation.Bean; /** diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/graphql/GraphQlObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/graphql/GraphQlObservationAutoConfiguration.java index 8f4fcc13a0..7234a15733 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/graphql/GraphQlObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/graphql/GraphQlObservationAutoConfiguration.java @@ -21,12 +21,12 @@ import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.graphql.execution.GraphQlSource; import org.springframework.graphql.observation.DataFetcherObservationConvention; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/HttpClientObservationsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/HttpClientObservationsAutoConfiguration.java index a5e58f8c71..f6cc8acd5d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/HttpClientObservationsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/HttpClientObservationsAutoConfiguration.java @@ -21,8 +21,6 @@ import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -32,6 +30,8 @@ import org.springframework.boot.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.metrics.autoconfigure.MetricsProperties; import org.springframework.boot.metrics.autoconfigure.MetricsProperties.Web.Client; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfiguration.java index 76bf11b049..763147e46c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfiguration.java @@ -19,9 +19,9 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.client; import io.micrometer.observation.ObservationRegistry; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.boot.restclient.RestClientCustomizer; import org.springframework.boot.restclient.actuate.observation.ObservationRestClientCustomizer; import org.springframework.context.annotation.Bean; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfiguration.java index 02e831aa7f..7013a6838a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfiguration.java @@ -19,9 +19,9 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.client; import io.micrometer.observation.ObservationRegistry; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.boot.restclient.RestTemplateBuilder; import org.springframework.boot.restclient.actuate.observation.ObservationRestTemplateCustomizer; import org.springframework.context.annotation.Bean; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfiguration.java index f0e3f51fa4..e4b3e42371 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfiguration.java @@ -19,9 +19,9 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.client; import io.micrometer.observation.ObservationRegistry; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.metrics.autoconfigure.MetricsProperties; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.boot.webclient.actuate.observation.ObservationWebClientCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfiguration.java index 893cc86a71..60c9e2f8c4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfiguration.java @@ -21,8 +21,6 @@ import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -33,6 +31,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.metrics.autoconfigure.MetricsProperties; import org.springframework.boot.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; import org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfiguration.java index 259ad0a6d0..03405ea731 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfiguration.java @@ -23,8 +23,6 @@ import io.micrometer.observation.ObservationRegistry; import jakarta.servlet.DispatcherType; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -37,6 +35,8 @@ import org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAuto import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; import org.springframework.boot.metrics.autoconfigure.MetricsProperties; import org.springframework.boot.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/R2dbcObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/R2dbcObservationAutoConfiguration.java index 0bd6d8fb08..63df16147e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/R2dbcObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/r2dbc/R2dbcObservationAutoConfiguration.java @@ -25,12 +25,12 @@ import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.r2dbc.OptionsCapableConnectionFactory; import org.springframework.boot.r2dbc.autoconfigure.ProxyConnectionFactoryCustomizer; import org.springframework.context.annotation.Bean; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfiguration.java index 76146b0a9e..545fa6d99e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfiguration.java @@ -18,11 +18,11 @@ package org.springframework.boot.actuate.autoconfigure.scheduling; import io.micrometer.observation.ObservationRegistry; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/additional-spring-configuration-metadata.json index a26ba23757..79c10e639f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -308,12 +308,6 @@ "level": "error" } }, - { - "name": "management.observations.annotations.enabled", - "type": "java.lang.Boolean", - "description": "Whether auto-configuration of Micrometer annotations is enabled.", - "defaultValue": false - }, { "name": "management.otlp.logging.export.enabled", "type": "java.lang.Boolean", diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 7b3b4186d5..df4c825693 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -16,9 +16,9 @@ org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAuto org.springframework.boot.actuate.autoconfigure.metrics.data.RepositoryMetricsAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetricsAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.task.TaskExecutorMetricsAutoConfiguration +org.springframework.boot.actuate.autoconfigure.observability.ObservabilityAutoConfiguration org.springframework.boot.actuate.autoconfigure.observation.batch.BatchObservationAutoConfiguration org.springframework.boot.actuate.autoconfigure.observation.graphql.GraphQlObservationAutoConfiguration -org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration org.springframework.boot.actuate.autoconfigure.observation.web.reactive.WebFluxObservationAutoConfiguration org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java index 1cca1b8f2c..ad1c5e4d7d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/jersey/JerseyServerMetricsAutoConfigurationTests.java @@ -20,6 +20,9 @@ import java.net.URI; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.observation.MeterObservationHandler; +import io.micrometer.observation.Observation.Context; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -28,12 +31,12 @@ import org.glassfish.jersey.server.ResourceConfig; import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration; import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer; import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; import org.springframework.boot.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -80,7 +83,7 @@ class JerseyServerMetricsAutoConfigurationTests { @Test void httpRequestsAreTimed() { - this.webContextRunner.run((context) -> { + this.webContextRunner.withUserConfiguration(MetricsConfiguration.class).run((context) -> { doRequest(context); Thread.sleep(500); MeterRegistry registry = context.getBean(MeterRegistry.class); @@ -128,4 +131,14 @@ class JerseyServerMetricsAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class MetricsConfiguration { + + @Bean + MeterObservationHandler meterObservationHandler(MeterRegistry registry) { + return new DefaultMeterObservationHandler(registry); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java index 3524900e16..0578161f0c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java @@ -34,7 +34,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.observability.ObservabilityAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.web.reactive.WebFluxObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration; @@ -47,6 +47,7 @@ import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; import org.springframework.boot.metrics.autoconfigure.jvm.JvmMetricsAutoConfiguration; import org.springframework.boot.metrics.autoconfigure.logging.logback.LogbackMetricsAutoConfiguration; import org.springframework.boot.metrics.autoconfigure.system.SystemMetricsAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.restclient.RestTemplateBuilder; import org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -143,14 +144,14 @@ class MetricsIntegrationTests { @Configuration(proxyBeanMethods = false) @ImportAutoConfiguration({ MetricsAutoConfiguration.class, ObservationAutoConfiguration.class, - JvmMetricsAutoConfiguration.class, LogbackMetricsAutoConfiguration.class, - SystemMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, - HibernateMetricsAutoConfiguration.class, HttpClientObservationsAutoConfiguration.class, - WebFluxObservationAutoConfiguration.class, WebMvcObservationAutoConfiguration.class, - JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, - RestTemplateAutoConfiguration.class, WebMvcAutoConfiguration.class, - DispatcherServletAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class, - TomcatServletWebServerAutoConfiguration.class }) + ObservabilityAutoConfiguration.class, JvmMetricsAutoConfiguration.class, + LogbackMetricsAutoConfiguration.class, SystemMetricsAutoConfiguration.class, + DataSourcePoolMetricsAutoConfiguration.class, HibernateMetricsAutoConfiguration.class, + HttpClientObservationsAutoConfiguration.class, WebFluxObservationAutoConfiguration.class, + WebMvcObservationAutoConfiguration.class, JacksonAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, RestTemplateAutoConfiguration.class, + WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, + TomcatServletWebServerAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class }) @Import(PersonController.class) static class MetricsApp { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observability/ObservabilityAutoConfigurationTests.java similarity index 71% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observability/ObservabilityAutoConfigurationTests.java index fb85657d3b..b9d0a3d57e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observability/ObservabilityAutoConfigurationTests.java @@ -14,36 +14,31 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.actuate.autoconfigure.observability; import java.util.ArrayList; import java.util.List; -import io.micrometer.common.KeyValue; -import io.micrometer.common.KeyValues; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; import io.micrometer.core.instrument.observation.MeterObservationHandler; -import io.micrometer.core.instrument.search.MeterNotFoundException; -import io.micrometer.observation.GlobalObservationConvention; import io.micrometer.observation.Observation; import io.micrometer.observation.Observation.Context; -import io.micrometer.observation.ObservationFilter; import io.micrometer.observation.ObservationHandler; import io.micrometer.observation.ObservationHandler.AllMatchingCompositeObservationHandler; import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler; -import io.micrometer.observation.ObservationPredicate; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.aop.ObservedAspect; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler; import io.micrometer.tracing.handler.TracingObservationHandler; -import org.aspectj.weaver.Advice; import org.junit.jupiter.api.Test; import org.mockito.Answers; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGrouping; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -53,52 +48,29 @@ import org.springframework.core.annotation.Order; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; /** - * Tests for {@link ObservationAutoConfiguration}. + * Tests for {@link ObservabilityAutoConfiguration}. * * @author Moritz Halbritter * @author Jonatan Ivanov * @author Vedran Pavic */ -class ObservationAutoConfigurationTests { +class ObservabilityAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple()) .withPropertyValues("management.observations.annotations.enabled=true") .withClassLoader(new FilteredClassLoader("io.micrometer.tracing")) - .withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class)); + .withConfiguration( + AutoConfigurations.of(ObservationAutoConfiguration.class, ObservabilityAutoConfiguration.class)); private final ApplicationContextRunner tracingContextRunner = new ApplicationContextRunner() .with(MetricsRun.simple()) .withPropertyValues("management.observations.annotations.enabled=true") .withUserConfiguration(TracerConfiguration.class) - .withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class)); - - @Test - void beansShouldNotBeSuppliedWhenMicrometerObservationIsNotOnClassPath() { - this.tracingContextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.observation")) - .run((context) -> { - assertThat(context).hasSingleBean(MeterRegistry.class); - assertThat(context).doesNotHaveBean(ObservationRegistry.class); - assertThat(context).doesNotHaveBean(ObservationHandler.class); - assertThat(context).doesNotHaveBean(ObservedAspect.class); - assertThat(context).doesNotHaveBean(ObservationHandlerGrouping.class); - }); - } - - @Test - void supplyObservationRegistryWhenMicrometerCoreAndTracingAreNotOnClassPath() { - this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.core", "io.micrometer.tracing")) - .run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - Observation.start("test-observation", observationRegistry).stop(); - assertThat(context).doesNotHaveBean(ObservationHandler.class); - assertThat(context).hasSingleBean(ObservedAspect.class); - assertThat(context).doesNotHaveBean(ObservationHandlerGrouping.class); - }); - } + .withConfiguration( + AutoConfigurations.of(ObservationAutoConfiguration.class, ObservabilityAutoConfiguration.class)); @Test void supplyMeterHandlerAndGroupingWhenMicrometerCoreIsOnClassPathButTracingIsNot() { @@ -144,7 +116,8 @@ class ObservationAutoConfigurationTests { void supplyMeterHandlerAndGroupingWhenMicrometerCoreAndTracingAreOnClassPathButThereIsNoTracer() { new ApplicationContextRunner().with(MetricsRun.simple()) .withPropertyValues("management.observations.annotations.enabled=true") - .withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class)) + .withConfiguration( + AutoConfigurations.of(ObservationAutoConfiguration.class, ObservabilityAutoConfiguration.class)) .run((context) -> { ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); Observation.start("test-observation", observationRegistry).stop(); @@ -178,77 +151,6 @@ class ObservationAutoConfigurationTests { .run((context) -> assertThat(context).doesNotHaveBean(ObservationHandler.class)); } - @Test - void allowsObservedAspectToBeDisabled() { - this.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class)) - .run((context) -> assertThat(context).doesNotHaveBean(ObservedAspect.class)); - } - - @Test - void allowsObservedAspectToBeDisabledWithProperty() { - this.contextRunner.withPropertyValues("management.observations.annotations.enabled=false") - .run((context) -> assertThat(context).doesNotHaveBean(ObservedAspect.class)); - } - - @Test - void allowsObservedAspectToBeCustomized() { - this.contextRunner.withUserConfiguration(CustomObservedAspectConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(ObservedAspect.class) - .getBean(ObservedAspect.class) - .isSameAs(context.getBean("customObservedAspect"))); - } - - @Test - void autoConfiguresObservationPredicates() { - this.contextRunner.withUserConfiguration(ObservationPredicates.class).run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - // This is allowed by ObservationPredicates.customPredicate - Observation.start("observation1", observationRegistry).stop(); - // This isn't allowed by ObservationPredicates.customPredicate - Observation.start("observation2", observationRegistry).stop(); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry.get("observation1").timer().count()).isOne(); - assertThatExceptionOfType(MeterNotFoundException.class) - .isThrownBy(() -> meterRegistry.get("observation2").timer()); - }); - } - - @Test - void autoConfiguresObservationFilters() { - this.contextRunner.withUserConfiguration(ObservationFilters.class).run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - Observation.start("filtered", observationRegistry).stop(); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry.get("filtered").tag("filter", "one").timer().count()).isOne(); - }); - } - - @Test - void shouldSupplyPropertiesObservationFilterBean() { - this.contextRunner - .run((context) -> assertThat(context).hasSingleBean(PropertiesObservationFilterPredicate.class)); - } - - @Test - void shouldApplyCommonKeyValuesToObservations() { - this.contextRunner.withPropertyValues("management.observations.key-values.a=alpha").run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - Observation.start("keyvalues", observationRegistry).stop(); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry.get("keyvalues").tag("a", "alpha").timer().count()).isOne(); - }); - } - - @Test - void autoConfiguresGlobalObservationConventions() { - this.contextRunner.withUserConfiguration(CustomGlobalObservationConvention.class).run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - Context micrometerContext = new Context(); - Observation.start("test-observation", () -> micrometerContext, observationRegistry).stop(); - assertThat(micrometerContext.getAllKeyValues()).containsExactly(KeyValue.of("key1", "value1")); - }); - } - @Test void autoConfiguresObservationHandlers() { this.contextRunner.withUserConfiguration(ObservationHandlers.class).run((context) -> { @@ -323,27 +225,6 @@ class ObservationAutoConfigurationTests { }); } - @Test - void shouldNotDisableSpringSecurityObservationsByDefault() { - this.contextRunner.run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - Observation.start("spring.security.filterchains", observationRegistry).stop(); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry.get("spring.security.filterchains").timer().count()).isOne(); - }); - } - - @Test - void shouldDisableSpringSecurityObservationsIfPropertyIsSet() { - this.contextRunner.withPropertyValues("management.observations.enable.spring.security=false").run((context) -> { - ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); - Observation.start("spring.security.filterchains", observationRegistry).stop(); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThatExceptionOfType(MeterNotFoundException.class) - .isThrownBy(() -> meterRegistry.get("spring.security.filterchains").timer()); - }); - } - @Test void shouldEnableLongTaskTimersByDefault() { this.contextRunner.run((context) -> { @@ -384,63 +265,6 @@ class ObservationAutoConfigurationTests { }); } - @Configuration(proxyBeanMethods = false) - static class ObservationPredicates { - - @Bean - ObservationPredicate customPredicate() { - return (s, context) -> s.equals("observation1"); - } - - } - - @Configuration(proxyBeanMethods = false) - static class ObservationFilters { - - @Bean - @Order(1) - ObservationFilter observationFilterOne() { - return (context) -> context.addLowCardinalityKeyValue(KeyValue.of("filter", "one")); - } - - @Bean - @Order(0) - ObservationFilter observationFilterTwo() { - return (context) -> context.addLowCardinalityKeyValue(KeyValue.of("filter", "two")); - } - - } - - @Configuration(proxyBeanMethods = false) - static class CustomObservedAspectConfiguration { - - @Bean - ObservedAspect customObservedAspect(ObservationRegistry observationRegistry) { - return new ObservedAspect(observationRegistry); - } - - } - - @Configuration(proxyBeanMethods = false) - static class CustomGlobalObservationConvention { - - @Bean - GlobalObservationConvention customConvention() { - return new GlobalObservationConvention<>() { - @Override - public boolean supportsContext(Context context) { - return true; - } - - @Override - public KeyValues getLowCardinalityKeyValues(Context context) { - return KeyValues.of("key1", "value1"); - } - }; - } - - } - @Configuration(proxyBeanMethods = false) @Import(CalledHandlersConfiguration.class) static class ObservationHandlers { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationTests.java index 5382f83389..c6858f6331 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationTests.java @@ -18,14 +18,17 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.client; import io.micrometer.common.KeyValues; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.observation.MeterObservationHandler; +import io.micrometer.observation.Observation.Context; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.restclient.actuate.observation.ObservationRestClientCustomizer; import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.restclient.test.MockServerRestClientCustomizer; @@ -102,6 +105,7 @@ class RestClientObservationConfigurationTests { @Test void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) { this.contextRunner.with(MetricsRun.simple()) + .withUserConfiguration(MetricsConfiguration.class) .withPropertyValues("management.metrics.web.client.max-uri-tags=2") .run((context) -> { RestClientWithMockServer restClientWithMockServer = buildRestClientAndMockServer(context); @@ -167,4 +171,14 @@ class RestClientObservationConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class MetricsConfiguration { + + @Bean + MeterObservationHandler meterObservationHandler(MeterRegistry registry) { + return new DefaultMeterObservationHandler(registry); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationWithoutMetricsTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationWithoutMetricsTests.java index 2f678cdea0..96b988f820 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationWithoutMetricsTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestClientObservationConfigurationWithoutMetricsTests.java @@ -21,8 +21,8 @@ import io.micrometer.observation.tck.TestObservationRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration; import org.springframework.boot.restclient.test.MockServerRestClientCustomizer; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationTests.java index f42792920f..05fc2e32c7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationTests.java @@ -18,14 +18,17 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.client; import io.micrometer.common.KeyValues; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.observation.MeterObservationHandler; +import io.micrometer.observation.Observation.Context; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.restclient.RestTemplateBuilder; import org.springframework.boot.restclient.actuate.observation.ObservationRestTemplateCustomizer; import org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration; @@ -100,6 +103,7 @@ class RestTemplateObservationConfigurationTests { @Test void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) { this.contextRunner.with(MetricsRun.simple()) + .withUserConfiguration(MetricsConfiguration.class) .withPropertyValues("management.metrics.web.client.max-uri-tags=2") .run((context) -> { RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class).build(); @@ -153,4 +157,14 @@ class RestTemplateObservationConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class MetricsConfiguration { + + @Bean + MeterObservationHandler meterObservationHandler(MeterRegistry registry) { + return new DefaultMeterObservationHandler(registry); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java index bbde69babc..3d743f9c53 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java @@ -21,8 +21,8 @@ import io.micrometer.observation.tck.TestObservationRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.restclient.RestTemplateBuilder; import org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfigurationTests.java index e5f8f248f8..ccb0ece56b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/client/WebClientObservationConfigurationTests.java @@ -20,6 +20,9 @@ import java.time.Duration; import io.micrometer.common.KeyValues; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.observation.MeterObservationHandler; +import io.micrometer.observation.Observation.Context; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry; import org.junit.jupiter.api.Test; @@ -27,8 +30,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Mono; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; @@ -97,28 +100,32 @@ class WebClientObservationConfigurationTests { @Test void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) { - this.contextRunner.withPropertyValues("management.metrics.web.client.max-uri-tags=2").run((context) -> { - TestObservationRegistry registry = getInitializedRegistry(context); - assertThat(registry).hasNumberOfObservationsWithNameEqualTo("http.client.requests", 3); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(1); - // MeterFilter.maximumAllowableTags() works with prefix matching. - assertThat(meterRegistry.find("http.client.requests.active").longTaskTimers()).hasSize(1); - assertThat(output).contains("Reached the maximum number of URI tags for 'http.client.requests'.") - .contains("Are you using 'uriVariables'?"); - }); + this.contextRunner.withUserConfiguration(MetricsConfiguration.class) + .withPropertyValues("management.metrics.web.client.max-uri-tags=2") + .run((context) -> { + TestObservationRegistry registry = getInitializedRegistry(context); + assertThat(registry).hasNumberOfObservationsWithNameEqualTo("http.client.requests", 3); + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(1); + // MeterFilter.maximumAllowableTags() works with prefix matching. + assertThat(meterRegistry.find("http.client.requests.active").longTaskTimers()).hasSize(1); + assertThat(output).contains("Reached the maximum number of URI tags for 'http.client.requests'.") + .contains("Are you using 'uriVariables'?"); + }); } @Test void shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) { - this.contextRunner.withPropertyValues("management.metrics.web.client.max-uri-tags=5").run((context) -> { - TestObservationRegistry registry = getInitializedRegistry(context); - assertThat(registry).hasNumberOfObservationsWithNameEqualTo("http.client.requests", 3); - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(3); - assertThat(output).doesNotContain("Reached the maximum number of URI tags for 'http.client.requests'.") - .doesNotContain("Are you using 'uriVariables'?"); - }); + this.contextRunner.withUserConfiguration(MetricsConfiguration.class) + .withPropertyValues("management.metrics.web.client.max-uri-tags=5") + .run((context) -> { + TestObservationRegistry registry = getInitializedRegistry(context); + assertThat(registry).hasNumberOfObservationsWithNameEqualTo("http.client.requests", 3); + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(3); + assertThat(output).doesNotContain("Reached the maximum number of URI tags for 'http.client.requests'.") + .doesNotContain("Are you using 'uriVariables'?"); + }); } private TestObservationRegistry getInitializedRegistry(AssertableApplicationContext context) { @@ -172,4 +179,14 @@ class WebClientObservationConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class MetricsConfiguration { + + @Bean + MeterObservationHandler meterObservationHandler(MeterRegistry registry) { + return new DefaultMeterObservationHandler(registry); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfigurationTests.java index 89d67e89cc..c58fd8a31d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/reactive/WebFluxObservationAutoConfigurationTests.java @@ -25,9 +25,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfigurationTests.java index 357824b641..87ed353fc4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/web/servlet/WebMvcObservationAutoConfigurationTests.java @@ -19,6 +19,10 @@ package org.springframework.boot.actuate.autoconfigure.observation.web.servlet; import java.util.EnumSet; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters; +import io.micrometer.core.instrument.observation.MeterObservationHandler; +import io.micrometer.observation.Observation.Context; import io.micrometer.observation.tck.TestObservationRegistry; import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; @@ -27,9 +31,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; @@ -64,7 +68,7 @@ class WebMvcObservationAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(WebMvcObservationAutoConfiguration.class)); @Test - void backsOffWhenMeterRegistryIsMissing() { + void backsOffWhenObservationRegistryIsMissing() { new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(WebMvcObservationAutoConfiguration.class)) .run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class)); @@ -128,7 +132,7 @@ class WebMvcObservationAutoConfigurationTests { @Test void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) { - this.contextRunner.withUserConfiguration(TestController.class) + this.contextRunner.withUserConfiguration(TestController.class, MetricsConfiguration.class) .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class, WebMvcAutoConfiguration.class)) .withPropertyValues("management.metrics.web.server.max-uri-tags=2") @@ -141,7 +145,7 @@ class WebMvcObservationAutoConfigurationTests { @Test void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) { - this.contextRunner.withUserConfiguration(TestController.class) + this.contextRunner.withUserConfiguration(TestController.class, MetricsConfiguration.class) .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class, WebMvcAutoConfiguration.class)) .withPropertyValues("management.metrics.web.server.max-uri-tags=2", @@ -155,7 +159,7 @@ class WebMvcObservationAutoConfigurationTests { @Test void shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) { - this.contextRunner.withUserConfiguration(TestController.class) + this.contextRunner.withUserConfiguration(TestController.class, MetricsConfiguration.class) .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class, WebMvcAutoConfiguration.class)) .withPropertyValues("management.metrics.web.server.max-uri-tags=5") @@ -237,4 +241,14 @@ class WebMvcObservationAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class MetricsConfiguration { + + @Bean + MeterObservationHandler meterObservationHandler(MeterRegistry registry) { + return new DefaultMeterObservationHandler(registry, IgnoredMeters.LONG_TASK_TIMER); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfigurationTests.java index f7b3d014dd..5359fa0fdd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksObservabilityAutoConfigurationTests.java @@ -21,11 +21,11 @@ import java.util.List; import io.micrometer.observation.ObservationRegistry; import org.junit.jupiter.api.Test; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksObservabilityAutoConfiguration.ObservabilitySchedulingConfigurer; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.context.annotation.ImportCandidates; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.scheduling.config.ScheduledTaskRegistrar; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java index e4ff557d83..b349a34729 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java @@ -50,10 +50,10 @@ import org.assertj.core.api.Assertions; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfigurationTests.SpanHandlerConfiguration.AdditionalSpanHandler; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.context.properties.IncompatibleConfigurationException; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryTracingAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryTracingAutoConfigurationTests.java index 981fb96358..e5ccf3439f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryTracingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryTracingAutoConfigurationTests.java @@ -60,9 +60,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.context.annotation.Configurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.classpath.ForkedClassPath; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingAutoConfigurationIntegrationTests.java index e6392d0e2f..c891c755f9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/otlp/OtlpTracingAutoConfigurationIntegrationTests.java @@ -46,10 +46,10 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfigurationIntegrationTests.MockGrpcServer.RecordedGrpcRequest; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/prometheus/PrometheusExemplarsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/prometheus/PrometheusExemplarsAutoConfigurationTests.java index 63d1efb918..a7bf5c3cfd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/prometheus/PrometheusExemplarsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/prometheus/PrometheusExemplarsAutoConfigurationTests.java @@ -20,19 +20,23 @@ import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; import io.micrometer.prometheusmetrics.PrometheusMeterRegistry; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler; import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter; import io.prometheus.metrics.tracer.common.SpanContext; import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.metrics.autoconfigure.export.prometheus.PrometheusMetricsExportAutoConfiguration; +import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -85,8 +89,9 @@ class PrometheusExemplarsAutoConfigurationTests { @Test void prometheusOpenMetricsOutputWithoutExemplarsOnHistogramCount() { - this.contextRunner.withPropertyValues( - "management.prometheus.metrics.export.properties.io.prometheus.exporter.exemplarsOnAllMetricTypes=false") + this.contextRunner.withUserConfiguration(TracingConfiguration.class) + .withPropertyValues( + "management.prometheus.metrics.export.properties.io.prometheus.exporter.exemplarsOnAllMetricTypes=false") .run((context) -> { assertThat(context).hasSingleBean(SpanContext.class); ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); @@ -112,7 +117,7 @@ class PrometheusExemplarsAutoConfigurationTests { @Test void prometheusOpenMetricsOutputShouldContainExemplars() { - this.contextRunner.run((context) -> { + this.contextRunner.withUserConfiguration(TracingConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(SpanContext.class); ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); Observation.start("test.observation", observationRegistry).stop(); @@ -157,4 +162,16 @@ class PrometheusExemplarsAutoConfigurationTests { private record TraceInfo(String traceId, String spanId) { } + @Configuration(proxyBeanMethods = false) + static class TracingConfiguration { + + @Bean + TracingAwareMeterObservationHandler tracingAwareMeterObservationHandler( + MeterRegistry meterRegistry, Tracer tracer) { + DefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry); + return new TracingAwareMeterObservationHandler<>(delegate, tracer); + } + + } + } diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 32f138c8dd..4ad02da886 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -2039,6 +2039,7 @@ bom { "spring-boot-loader-tools", "spring-boot-mail", "spring-boot-metrics", + "spring-boot-micrometer-observation", "spring-boot-mongodb", "spring-boot-mustache", "spring-boot-neo4j", diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index b81e785df9..09db5d4655 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -108,6 +108,7 @@ dependencies { autoConfiguration(project(path: ":spring-boot-project:spring-boot-liquibase", configuration: "autoConfigurationMetadata")) autoConfiguration(project(path: ":spring-boot-project:spring-boot-mail", configuration: "autoConfigurationMetadata")) autoConfiguration(project(path: ":spring-boot-project:spring-boot-metrics", configuration: "autoConfigurationMetadata")) + autoConfiguration(project(path: ":spring-boot-project:spring-boot-micrometer-observation", configuration: "autoConfigurationMetadata")) autoConfiguration(project(path: ":spring-boot-project:spring-boot-mongodb", configuration: "autoConfigurationMetadata")) autoConfiguration(project(path: ":spring-boot-project:spring-boot-mustache", configuration: "autoConfigurationMetadata")) autoConfiguration(project(path: ":spring-boot-project:spring-boot-neo4j", configuration: "autoConfigurationMetadata")) @@ -193,6 +194,7 @@ dependencies { configurationProperties(project(path: ":spring-boot-project:spring-boot-liquibase", configuration: "configurationPropertiesMetadata")) configurationProperties(project(path: ":spring-boot-project:spring-boot-mail", configuration: "configurationPropertiesMetadata")) configurationProperties(project(path: ":spring-boot-project:spring-boot-metrics", configuration: "configurationPropertiesMetadata")) + configurationProperties(project(path: ":spring-boot-project:spring-boot-micrometer-observation", configuration: "configurationPropertiesMetadata")) configurationProperties(project(path: ":spring-boot-project:spring-boot-mongodb", configuration: "configurationPropertiesMetadata")) configurationProperties(project(path: ":spring-boot-project:spring-boot-mustache", configuration: "configurationPropertiesMetadata")) configurationProperties(project(path: ":spring-boot-project:spring-boot-neo4j", configuration: "configurationPropertiesMetadata")) diff --git a/spring-boot-project/spring-boot-metrics/build.gradle b/spring-boot-project/spring-boot-metrics/build.gradle index 9d4645d6e1..38ec42c9fa 100644 --- a/spring-boot-project/spring-boot-metrics/build.gradle +++ b/spring-boot-project/spring-boot-metrics/build.gradle @@ -11,6 +11,7 @@ description = "Spring Boot Metrics" dependencies { api(project(":spring-boot-project:spring-boot")) + api(project(":spring-boot-project:spring-boot-micrometer-observation")) api("io.micrometer:micrometer-core") optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure")) diff --git a/spring-boot-project/spring-boot-micrometer-observation/build.gradle b/spring-boot-project/spring-boot-micrometer-observation/build.gradle new file mode 100644 index 0000000000..db444516c9 --- /dev/null +++ b/spring-boot-project/spring-boot-micrometer-observation/build.gradle @@ -0,0 +1,21 @@ +plugins { + id "java-library" + id "org.springframework.boot.auto-configuration" + id "org.springframework.boot.configuration-properties" + id "org.springframework.boot.deployed" + id "org.springframework.boot.optional-dependencies" +} + +description = "Spring Boot New Project" + +dependencies { + api(project(":spring-boot-project:spring-boot")) + + optional(project(":spring-boot-project:spring-boot-autoconfigure")) + optional("org.aspectj:aspectjweaver") + + testImplementation(project(":spring-boot-project:spring-boot-test")) + testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) + + testRuntimeOnly("ch.qos.logback:logback-classic") +} diff --git a/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfiguration.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfiguration.java new file mode 100644 index 0000000000..102d6ca181 --- /dev/null +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfiguration.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure; + +import io.micrometer.observation.GlobalObservationConvention; +import io.micrometer.observation.ObservationFilter; +import io.micrometer.observation.ObservationHandler; +import io.micrometer.observation.ObservationPredicate; +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.aop.ObservedAspect; +import org.aspectj.weaver.Advice; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Observation API. + * + * @author Moritz Halbritter + * @author Brian Clozel + * @author Jonatan Ivanov + * @author Vedran Pavic + * @since 4.0.0 + */ +@AutoConfiguration +@ConditionalOnClass(ObservationRegistry.class) +@EnableConfigurationProperties(ObservationProperties.class) +public class ObservationAutoConfiguration { + + @Bean + static ObservationRegistryPostProcessor observationRegistryPostProcessor( + ObjectProvider> observationRegistryCustomizers, + ObjectProvider observationPredicates, + ObjectProvider> observationConventions, + ObjectProvider> observationHandlers, + ObjectProvider observationHandlerGrouping, + ObjectProvider observationFilters) { + return new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates, + observationConventions, observationHandlers, observationHandlerGrouping, observationFilters); + } + + @Bean + @ConditionalOnMissingBean + ObservationRegistry observationRegistry() { + return ObservationRegistry.create(); + } + + @Bean + @Order(0) + PropertiesObservationFilterPredicate propertiesObservationFilter(ObservationProperties properties) { + return new PropertiesObservationFilterPredicate(properties); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Advice.class) + @ConditionalOnBooleanProperty("management.observations.annotations.enabled") + static class ObservedAspectConfiguration { + + @Bean + @ConditionalOnMissingBean + ObservedAspect observedAspect(ObservationRegistry observationRegistry) { + return new ObservedAspect(observationRegistry); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationHandlerGrouping.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGrouping.java similarity index 89% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationHandlerGrouping.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGrouping.java index 3a1b9a8c6e..46b56e037d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationHandlerGrouping.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGrouping.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import java.util.ArrayList; import java.util.List; @@ -32,17 +32,18 @@ import org.springframework.util.MultiValueMap; * * @author Andy Wilkinson * @author Moritz Halbritter + * @since 4.0.0 */ @SuppressWarnings("rawtypes") -class ObservationHandlerGrouping { +public class ObservationHandlerGrouping { private final List> categories; - ObservationHandlerGrouping(Class category) { + public ObservationHandlerGrouping(Class category) { this(List.of(category)); } - ObservationHandlerGrouping(List> categories) { + public ObservationHandlerGrouping(List> categories) { this.categories = categories; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationProperties.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java similarity index 97% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationProperties.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java index 7662c04a7e..bed3d4bef7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationProperties.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import java.util.LinkedHashMap; import java.util.Map; @@ -27,7 +27,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * * @author Brian Clozel * @author Moritz Halbritter - * @since 3.0.0 + * @since 4.0.0 */ @ConfigurationProperties("management.observations") public class ObservationProperties { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurer.java similarity index 89% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurer.java index 85d75727c3..4447ea4cec 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurer.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import java.util.List; @@ -74,8 +74,14 @@ class ObservationRegistryConfigurer { } private void registerHandlers(ObservationRegistry registry) { - this.observationHandlerGrouping.ifAvailable( - (grouping) -> grouping.apply(asOrderedList(this.observationHandlers), registry.observationConfig())); + ObservationHandlerGrouping grouping = this.observationHandlerGrouping.getIfAvailable(); + List> orderedHandlers = asOrderedList(this.observationHandlers); + if (grouping != null) { + grouping.apply(orderedHandlers, registry.observationConfig()); + } + else { + orderedHandlers.forEach((handler) -> registry.observationConfig().observationHandler(handler)); + } } private void registerObservationPredicates(ObservationRegistry registry) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryCustomizer.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryCustomizer.java similarity index 92% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryCustomizer.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryCustomizer.java index cc15a68cf0..5599b2ada6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryCustomizer.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryCustomizer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import io.micrometer.observation.ObservationRegistry; @@ -24,7 +24,7 @@ import io.micrometer.observation.ObservationRegistry; * * @param the registry type to customize * @author Moritz Halbritter - * @since 3.0.0 + * @since 4.0.0 */ @FunctionalInterface public interface ObservationRegistryCustomizer { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryPostProcessor.java similarity index 97% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryPostProcessor.java index 798a4da38f..c142afe647 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryPostProcessor.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryPostProcessor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import io.micrometer.observation.GlobalObservationConvention; import io.micrometer.observation.ObservationFilter; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/PropertiesObservationFilterPredicate.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicate.java similarity index 97% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/PropertiesObservationFilterPredicate.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicate.java index 57c6dc308d..4dfa3b2dd4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/PropertiesObservationFilterPredicate.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicate.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import java.util.Map; import java.util.Map.Entry; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/package-info.java b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/package-info.java similarity index 83% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/package-info.java rename to spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/package-info.java index 8e609c7ec2..1788fec96b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/package-info.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for the Micrometer Observation API. + * Auto-configuration for Micrometer Observation. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; diff --git a/spring-boot-project/spring-boot-micrometer-observation/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-micrometer-observation/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000000..358dc1cb77 --- /dev/null +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,11 @@ +{ + "groups": [], + "properties": [ + { + "name": "management.observations.annotations.enabled", + "type": "java.lang.Boolean", + "description": "Whether auto-configuration of Micrometer annotations is enabled.", + "defaultValue": false + } + ] +} diff --git a/spring-boot-project/spring-boot-micrometer-observation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-project/spring-boot-micrometer-observation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000..a96535b1fe --- /dev/null +++ b/spring-boot-project/spring-boot-micrometer-observation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration diff --git a/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfigurationTests.java b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfigurationTests.java new file mode 100644 index 0000000000..8d6402a77d --- /dev/null +++ b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfigurationTests.java @@ -0,0 +1,256 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.observation.autoconfigure; + +import io.micrometer.common.KeyValue; +import io.micrometer.common.KeyValues; +import io.micrometer.observation.GlobalObservationConvention; +import io.micrometer.observation.Observation; +import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationFilter; +import io.micrometer.observation.ObservationHandler; +import io.micrometer.observation.ObservationHandler.AllMatchingCompositeObservationHandler; +import io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler; +import io.micrometer.observation.ObservationPredicate; +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.aop.ObservedAspect; +import org.aspectj.weaver.Advice; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ObservationAutoConfiguration}. + * + * @author Moritz Halbritter + * @author Jonatan Ivanov + * @author Vedran Pavic + */ +class ObservationAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("management.observations.annotations.enabled=true") + .withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class)) + .withUserConfiguration(ObservationHandlers.class); + + @Test + void beansShouldNotBeSuppliedWhenMicrometerObservationIsNotOnClassPath() { + this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.observation")).run((context) -> { + assertThat(context).doesNotHaveBean(ObservationRegistry.class); + assertThat(context).doesNotHaveBean(ObservedAspect.class); + }); + } + + @Test + void supplyObservationRegistry() { + this.contextRunner.run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation.start("test-observation", observationRegistry).stop(); + assertThat(context).hasSingleBean(ObservedAspect.class); + assertThat(context).doesNotHaveBean(ObservationHandlerGrouping.class); + }); + } + + @Test + void allowsObservedAspectToBeDisabled() { + this.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class)) + .run((context) -> assertThat(context).doesNotHaveBean(ObservedAspect.class)); + } + + @Test + void allowsObservedAspectToBeDisabledWithProperty() { + this.contextRunner.withPropertyValues("management.observations.annotations.enabled=false") + .run((context) -> assertThat(context).doesNotHaveBean(ObservedAspect.class)); + } + + @Test + void allowsObservedAspectToBeCustomized() { + this.contextRunner.withUserConfiguration(CustomObservedAspectConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(ObservedAspect.class) + .getBean(ObservedAspect.class) + .isSameAs(context.getBean("customObservedAspect"))); + } + + @Test + void autoConfiguresObservationPredicates() { + this.contextRunner.withUserConfiguration(ObservationPredicates.class).run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + // This is allowed by ObservationPredicates.customPredicate + Observation observation = Observation.start("observation1", observationRegistry); + assertThat(observation).isNotEqualTo(Observation.NOOP); + observation.stop(); + // This isn't allowed by ObservationPredicates.customPredicate + observation = Observation.start("observation2", observationRegistry); + assertThat(observation).isEqualTo(Observation.NOOP); + observation.stop(); + }); + } + + @Test + void autoConfiguresObservationFilters() { + this.contextRunner.withUserConfiguration(ObservationFilters.class).run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation observation = Observation.start("filtered", observationRegistry); + observation.stop(); + observation.getContext().getLowCardinalityKeyValues().forEach((kv) -> System.out.println(kv.getKey())); + assertThat(observation.getContext().getLowCardinalityKeyValue("filter").getValue()).isEqualTo("one"); + }); + } + + @Test + void shouldSupplyPropertiesObservationFilterBean() { + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(PropertiesObservationFilterPredicate.class)); + } + + @Test + void shouldApplyCommonKeyValuesToObservations() { + this.contextRunner.withPropertyValues("management.observations.key-values.a=alpha").run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation observation = Observation.start("keyvalues", observationRegistry); + observation.stop(); + assertThat(observation.getContext().getLowCardinalityKeyValue("a").getValue()).isEqualTo("alpha"); + }); + } + + @Test + void autoConfiguresGlobalObservationConventions() { + this.contextRunner.withUserConfiguration(CustomGlobalObservationConvention.class).run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Context micrometerContext = new Context(); + Observation.start("test-observation", () -> micrometerContext, observationRegistry).stop(); + assertThat(micrometerContext.getAllKeyValues()).containsExactly(KeyValue.of("key1", "value1")); + }); + } + + @Test + void shouldNotDisableSpringSecurityObservationsByDefault() { + this.contextRunner.run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation observation = Observation.start("spring.security.filterchains", observationRegistry); + assertThat(observation).isNotEqualTo(Observation.NOOP); + observation.stop(); + }); + } + + @Test + void shouldDisableSpringSecurityObservationsIfPropertyIsSet() { + this.contextRunner.withPropertyValues("management.observations.enable.spring.security=false").run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation observation = Observation.start("spring.security.filterchains", observationRegistry); + assertThat(observation).isEqualTo(Observation.NOOP); + observation.stop(); + }); + } + + @Configuration(proxyBeanMethods = false) + static class ObservationPredicates { + + @Bean + ObservationPredicate customPredicate() { + return (s, context) -> s.equals("observation1"); + } + + } + + @Configuration(proxyBeanMethods = false) + static class ObservationFilters { + + @Bean + @Order(1) + ObservationFilter observationFilterOne() { + return (context) -> context.addLowCardinalityKeyValue(KeyValue.of("filter", "one")); + } + + @Bean + @Order(0) + ObservationFilter observationFilterTwo() { + return (context) -> context.addLowCardinalityKeyValue(KeyValue.of("filter", "two")); + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomObservedAspectConfiguration { + + @Bean + ObservedAspect customObservedAspect(ObservationRegistry observationRegistry) { + return new ObservedAspect(observationRegistry); + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomGlobalObservationConvention { + + @Bean + GlobalObservationConvention customConvention() { + return new GlobalObservationConvention<>() { + @Override + public boolean supportsContext(Context context) { + return true; + } + + @Override + public KeyValues getLowCardinalityKeyValues(Context context) { + return KeyValues.of("key1", "value1"); + } + }; + } + + } + + @Configuration(proxyBeanMethods = false) + static class ObservationHandlers { + + @Bean + @Order(4) + AllMatchingCompositeObservationHandler customAllMatchingCompositeObservationHandler() { + return new AllMatchingCompositeObservationHandler(); + } + + @Bean + @Order(3) + FirstMatchingCompositeObservationHandler customFirstMatchingCompositeObservationHandler() { + return new FirstMatchingCompositeObservationHandler(); + } + + @Bean + @Order(2) + ObservationHandler customObservationHandler() { + return new CustomObservationHandler(); + } + + } + + private static final class CustomObservationHandler implements ObservationHandler { + + @Override + public boolean supportsContext(Context context) { + return true; + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationHandlerGroupingTests.java b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroupingTests.java similarity index 98% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationHandlerGroupingTests.java rename to spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroupingTests.java index b8e81c6f71..c102dab325 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationHandlerGroupingTests.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroupingTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import java.lang.reflect.Method; import java.util.List; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurerIntegrationTests.java b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurerIntegrationTests.java similarity index 97% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurerIntegrationTests.java rename to spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurerIntegrationTests.java index 3eeb2ee2c8..9448b45953 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationRegistryConfigurerIntegrationTests.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurerIntegrationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import java.util.ArrayList; import java.util.List; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/PropertiesObservationFilterPredicateTests.java b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicateTests.java similarity index 98% rename from spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/PropertiesObservationFilterPredicateTests.java rename to spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicateTests.java index da2733fb6c..1e8dda2434 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure-all/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/PropertiesObservationFilterPredicateTests.java +++ b/spring-boot-project/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicateTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.observation; +package org.springframework.boot.micrometer.observation.autoconfigure; import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/build.gradle b/spring-boot-project/spring-boot-test-autoconfigure/build.gradle index 70b60329c9..5091e073e1 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-test-autoconfigure/build.gradle @@ -71,6 +71,7 @@ dependencies { exclude(group: "org.liquibase") } optional(project(":spring-boot-project:spring-boot-metrics")) + optional(project(":spring-boot-project:spring-boot-micrometer-observation")) optional(project(":spring-boot-project:spring-boot-mongodb")) optional(project(":spring-boot-project:spring-boot-r2dbc")) optional(project(":spring-boot-project:spring-boot-reactor-netty")) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability.imports b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability.imports index 80293e2d86..d9f9a9e987 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability.imports +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability.imports @@ -1,7 +1,7 @@ # AutoConfigureObservability auto-configuration imports # Observation -org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration +org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration # Metrics org.springframework.boot.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration @@ -11,3 +11,6 @@ org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration # Tracing org.springframework.boot.actuate.autoconfigure.tracing.NoopTracerAutoConfiguration org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration + +# Observability +org.springframework.boot.actuate.autoconfigure.observability.ObservabilityAutoConfiguration diff --git a/src/checkstyle/import-control.xml b/src/checkstyle/import-control.xml index 95bf9403b5..ebc0c3c0ce 100644 --- a/src/checkstyle/import-control.xml +++ b/src/checkstyle/import-control.xml @@ -57,6 +57,10 @@ + + + +