diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java index a1727b33fa..66840a728a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java @@ -16,10 +16,6 @@ package org.springframework.boot.actuate.autoconfigure.metrics; -import io.micrometer.core.instrument.Timer.Builder; - -import org.springframework.boot.actuate.metrics.AutoTimer; - /** * Nested configuration properties for items that are automatically timed. * @@ -28,7 +24,7 @@ import org.springframework.boot.actuate.metrics.AutoTimer; * @author Phillip Webb * @since 2.2.0 */ -public final class AutoTimeProperties implements AutoTimer { +public final class AutoTimeProperties { /** * Whether to enable auto-timing. @@ -51,7 +47,6 @@ public final class AutoTimeProperties implements AutoTimer { public AutoTimeProperties() { } - @Override public boolean isEnabled() { return this.enabled; } @@ -76,9 +71,4 @@ public final class AutoTimeProperties implements AutoTimer { this.percentiles = percentiles; } - @Override - public void apply(Builder builder) { - builder.publishPercentileHistogram(this.percentilesHistogram).publishPercentiles(this.percentiles); - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesAutoTimer.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesAutoTimer.java new file mode 100644 index 0000000000..0269c0bbba --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesAutoTimer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2022 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.actuate.autoconfigure.metrics; + +import io.micrometer.core.instrument.Timer.Builder; + +import org.springframework.boot.actuate.metrics.AutoTimer; + +/** + * {@link AutoTimer} whose behavior is configured by {@link AutoTimeProperties}. + * + * @author Andy Wilkinson + * @since 3.0.0 + */ +public class PropertiesAutoTimer implements AutoTimer { + + private final AutoTimeProperties properties; + + /** + * Create a new {@link PropertiesAutoTimer} configured using the given + * {@code properties}. + * @param properties the properties to configure auto-timing + */ + public PropertiesAutoTimer(AutoTimeProperties properties) { + this.properties = properties; + } + + @Override + public void apply(Builder builder) { + builder.publishPercentileHistogram(this.properties.isPercentilesHistogram()) + .publishPercentiles(this.properties.getPercentiles()); + } + + @Override + public boolean isEnabled() { + return this.properties.isEnabled(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfiguration.java index be668b344c..884cade3e5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfiguration.java @@ -23,6 +23,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegi import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties.Data.Repository; +import org.springframework.boot.actuate.autoconfigure.metrics.PropertiesAutoTimer; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.metrics.data.DefaultRepositoryTagsProvider; import org.springframework.boot.actuate.metrics.data.MetricsRepositoryMethodInvocationListener; @@ -67,7 +68,7 @@ public class RepositoryMetricsAutoConfiguration { ObjectProvider registry, RepositoryTagsProvider tagsProvider) { Repository properties = this.properties.getData().getRepository(); return new MetricsRepositoryMethodInvocationListener(registry::getObject, tagsProvider, - properties.getMetricName(), properties.getAutotime()); + properties.getMetricName(), new PropertiesAutoTimer(properties.getAutotime())); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/graphql/GraphQlMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/graphql/GraphQlMetricsAutoConfiguration.java index 4ee94ebd43..83c282c5aa 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/graphql/GraphQlMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/graphql/GraphQlMetricsAutoConfiguration.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; +import org.springframework.boot.actuate.autoconfigure.metrics.PropertiesAutoTimer; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.metrics.graphql.DefaultGraphQlTagsProvider; import org.springframework.boot.actuate.metrics.graphql.GraphQlMetricsInstrumentation; @@ -60,7 +61,8 @@ public class GraphQlMetricsAutoConfiguration { @Bean public GraphQlMetricsInstrumentation graphQlMetricsInstrumentation(MeterRegistry meterRegistry, GraphQlTagsProvider tagsProvider, MetricsProperties properties) { - return new GraphQlMetricsInstrumentation(meterRegistry, tagsProvider, properties.getGraphql().getAutotime()); + return new GraphQlMetricsInstrumentation(meterRegistry, tagsProvider, + new PropertiesAutoTimer(properties.getGraphql().getAutotime())); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java index ea40aadad0..80c2152ef3 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfigu import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties.Web.Server.ServerRequest; import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter; +import org.springframework.boot.actuate.autoconfigure.metrics.PropertiesAutoTimer; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; import org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter; @@ -68,7 +69,8 @@ public class WebFluxMetricsAutoConfiguration { @Bean public MetricsWebFilter webfluxMetrics(MeterRegistry registry, WebFluxTagsProvider tagConfigurer) { ServerRequest request = this.properties.getWeb().getServer().getRequest(); - return new MetricsWebFilter(registry, tagConfigurer, request.getMetricName(), request.getAutotime()); + return new MetricsWebFilter(registry, tagConfigurer, request.getMetricName(), + new PropertiesAutoTimer(request.getAutotime())); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfiguration.java index 70fcfb8b72..c05a9f9d95 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfigu import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties.Web.Server.ServerRequest; import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter; +import org.springframework.boot.actuate.autoconfigure.metrics.PropertiesAutoTimer; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; import org.springframework.boot.actuate.metrics.web.servlet.LongTaskTimingHandlerInterceptor; @@ -83,7 +84,7 @@ public class WebMvcMetricsAutoConfiguration { WebMvcTagsProvider tagsProvider) { ServerRequest request = this.properties.getWeb().getServer().getRequest(); WebMvcMetricsFilter filter = new WebMvcMetricsFilter(registry, tagsProvider, request.getMetricName(), - request.getAutotime()); + new PropertiesAutoTimer(request.getAutotime())); FilterRegistrationBean registration = new FilterRegistrationBean<>(filter); registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java new file mode 100644 index 0000000000..fe60a7f46f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateObservationConfigurationWithoutMetricsTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2022 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.actuate.autoconfigure.metrics.web.client; + +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.tck.TestObservationRegistry; +import io.micrometer.observation.tck.TestObservationRegistryAssert; +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.autoconfigure.web.client.RestTemplateAutoConfiguration; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.boot.testsupport.classpath.ClassPathExclusions; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpStatus; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; + +/** + * Tests for {@link RestTemplateObservationConfiguration} without Micrometer Metrics. + * + * @author Brian Clozel + * @author Andy Wilkinson + */ +@ExtendWith(OutputCaptureExtension.class) +@ClassPathExclusions("micrometer-core-*.jar") +class RestTemplateObservationConfigurationWithoutMetricsTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withBean(ObservationRegistry.class, TestObservationRegistry::create) + .withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, + RestTemplateAutoConfiguration.class, HttpClientObservationsAutoConfiguration.class)); + + @Test + void restTemplateCreatedWithBuilderIsInstrumented() { + this.contextRunner.run((context) -> { + RestTemplate restTemplate = buildRestTemplate(context); + restTemplate.getForEntity("/projects/{project}", Void.class, "spring-boot"); + TestObservationRegistry registry = context.getBean(TestObservationRegistry.class); + TestObservationRegistryAssert.assertThat(registry) + .hasObservationWithNameEqualToIgnoringCase("http.client.requests"); + }); + } + + private RestTemplate buildRestTemplate(AssertableApplicationContext context) { + RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class).build(); + MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate); + server.expect(requestTo("/projects/spring-boot")).andRespond(withStatus(HttpStatus.OK)); + return restTemplate; + } + +}