Move HTTP client observation support into relevant modules
This commit is contained in:
committed by
Phillip Webb
parent
f7cc6473b2
commit
6f05c190e1
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.actuate.autoconfigure.observation.web.client;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
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.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;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for HTTP client-related
|
||||
* observations.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @author Raheela Aslam
|
||||
* @author Brian Clozel
|
||||
* @author Moritz Halbritter
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = { ObservationAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class },
|
||||
afterName = { "org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration",
|
||||
"org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration",
|
||||
"org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration" })
|
||||
@ConditionalOnClass(Observation.class)
|
||||
@ConditionalOnBean(ObservationRegistry.class)
|
||||
@Import({ RestTemplateObservationConfiguration.class, WebClientObservationConfiguration.class,
|
||||
RestClientObservationConfiguration.class })
|
||||
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
|
||||
public class HttpClientObservationsAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(MeterRegistry.class)
|
||||
@ConditionalOnBean(MeterRegistry.class)
|
||||
static class MeterFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
MeterFilter metricsHttpClientUriTagFilter(ObservationProperties observationProperties,
|
||||
MetricsProperties metricsProperties) {
|
||||
Client clientProperties = metricsProperties.getWeb().getClient();
|
||||
String name = observationProperties.getHttp().getClient().getRequests().getName();
|
||||
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(
|
||||
() -> "Reached the maximum number of URI tags for '%s'. Are you using 'uriVariables'?"
|
||||
.formatted(name));
|
||||
return MeterFilter.maximumAllowableTags(name, "uri", clientProperties.getMaxUriTags(), denyFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@ org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAuto
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.data.RepositoryMetricsAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.task.TaskExecutorMetricsAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.observability.ObservabilityAutoConfiguration
|
||||
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
|
||||
org.springframework.boot.actuate.autoconfigure.r2dbc.ConnectionFactoryHealthContributorAutoConfiguration
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
@@ -50,6 +49,7 @@ import org.springframework.boot.metrics.autoconfigure.system.SystemMetricsAutoCo
|
||||
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.restclient.autoconfigure.observation.RestTemplateObservationAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
|
||||
@@ -147,7 +147,7 @@ class MetricsIntegrationTests {
|
||||
ObservabilityAutoConfiguration.class, JvmMetricsAutoConfiguration.class,
|
||||
LogbackMetricsAutoConfiguration.class, SystemMetricsAutoConfiguration.class,
|
||||
DataSourcePoolMetricsAutoConfiguration.class, HibernateMetricsAutoConfiguration.class,
|
||||
HttpClientObservationsAutoConfiguration.class, WebFluxObservationAutoConfiguration.class,
|
||||
RestTemplateObservationAutoConfiguration.class, WebFluxObservationAutoConfiguration.class,
|
||||
WebMvcObservationAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, RestTemplateAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
|
||||
@@ -15,6 +15,7 @@ dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-http-converter"))
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-metrics"))
|
||||
optional(project(":spring-boot-project:spring-boot-reactor-netty"))
|
||||
optional("org.apache.httpcomponents.client5:httpclient5")
|
||||
optional("org.apache.httpcomponents.core5:httpcore5-reactive")
|
||||
@@ -25,6 +26,7 @@ dependencies {
|
||||
testImplementation(project(":spring-boot-project:spring-boot-tomcat"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
||||
testImplementation("org.springframework:spring-webflux")
|
||||
testImplementation("io.micrometer:micrometer-observation-test")
|
||||
|
||||
testRuntimeOnly("ch.qos.logback:logback-classic")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.http.client.autoconfigure.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
|
||||
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.metrics.OnlyOnceLoggingDenyMeterFilter;
|
||||
import org.springframework.boot.metrics.autoconfigure.MetricsProperties;
|
||||
import org.springframework.boot.metrics.autoconfigure.MetricsProperties.Web.Client;
|
||||
import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for HTTP client-related metrics.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @author Raheela Aslam
|
||||
* @author Brian Clozel
|
||||
* @author Moritz Halbritter
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration(afterName = "org.springframework.boot.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration")
|
||||
@ConditionalOnClass({ ObservationProperties.class, MeterRegistry.class, MetricsProperties.class })
|
||||
@ConditionalOnBean(MeterRegistry.class)
|
||||
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
|
||||
public class HttpClientMetricsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
MeterFilter metricsHttpClientUriTagFilter(ObservationProperties observationProperties,
|
||||
MetricsProperties metricsProperties) {
|
||||
Client clientProperties = metricsProperties.getWeb().getClient();
|
||||
String name = observationProperties.getHttp().getClient().getRequests().getName();
|
||||
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(
|
||||
() -> "Reached the maximum number of URI tags for '%s'. Are you using 'uriVariables'?".formatted(name));
|
||||
return MeterFilter.maximumAllowableTags(name, "uri", clientProperties.getMaxUriTags(), denyFilter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for web client observation support.
|
||||
* Auto-configuration for client-side HTTP metrics.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.http.client.autoconfigure.metrics;
|
||||
@@ -1,2 +1,3 @@
|
||||
org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration
|
||||
org.springframework.boot.http.client.autoconfigure.metrics.HttpClientMetricsAutoConfiguration
|
||||
org.springframework.boot.http.client.reactive.autoconfigure.ClientHttpConnectorAutoConfiguration
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.http.client.autoconfigure.metrics;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.metrics.autoconfigure.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpClientMetricsAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class HttpClientMetricsAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(HttpClientMetricsAutoConfiguration.class, MetricsAutoConfiguration.class))
|
||||
.withBean(SimpleMeterRegistry.class)
|
||||
.withPropertyValues("management.metrics.web.client.max-uri-tags=2")
|
||||
.run((context) -> {
|
||||
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
meterRegistry.timer("http.client.requests", "uri", "/test/" + i).record(Duration.ofSeconds(1));
|
||||
}
|
||||
assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(2);
|
||||
assertThat(output).contains("Reached the maximum number of URI tags for 'http.client.requests'.")
|
||||
.contains("Are you using 'uriVariables'?");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,10 +14,12 @@ dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-http-converter"))
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-micrometer-observation"))
|
||||
optional("io.projectreactor.netty:reactor-netty-http")
|
||||
optional("org.apache.httpcomponents.client5:httpclient5")
|
||||
optional("org.eclipse.jetty:jetty-client")
|
||||
|
||||
testImplementation(project(":spring-boot-project:spring-boot-metrics"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-test"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-tomcat"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
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.ObservationProperties;
|
||||
import org.springframework.boot.restclient.RestClientCustomizer;
|
||||
import org.springframework.boot.restclient.actuate.observation.ObservationRestClientCustomizer;
|
||||
import org.springframework.boot.restclient.observation.ObservationRestClientCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.observation.ClientRequestObservationConvention;
|
||||
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
|
||||
import org.springframework.web.client.RestClient;
|
||||
@@ -34,11 +35,14 @@ import org.springframework.web.client.RestClient;
|
||||
* Configure the instrumentation of {@link RestClient}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ RestClient.class, ObservationRestClientCustomizer.class })
|
||||
@ConditionalOnBean(RestClient.Builder.class)
|
||||
class RestClientObservationConfiguration {
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ RestClient.class, ObservationRestClientCustomizer.class, ObservationRegistry.class,
|
||||
ObservationProperties.class })
|
||||
@ConditionalOnBean({ RestClient.Builder.class, ObservationRegistry.class })
|
||||
@EnableConfigurationProperties(ObservationProperties.class)
|
||||
public class RestClientObservationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
RestClientCustomizer observationRestClientCustomizer(ObservationRegistry observationRegistry,
|
||||
@@ -14,18 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
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.ObservationProperties;
|
||||
import org.springframework.boot.restclient.RestTemplateBuilder;
|
||||
import org.springframework.boot.restclient.actuate.observation.ObservationRestTemplateCustomizer;
|
||||
import org.springframework.boot.restclient.observation.ObservationRestTemplateCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.observation.ClientRequestObservationConvention;
|
||||
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -34,11 +35,14 @@ import org.springframework.web.client.RestTemplate;
|
||||
* Configure the instrumentation of {@link RestTemplate}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ RestTemplate.class, ObservationRestTemplateCustomizer.class })
|
||||
@ConditionalOnBean(RestTemplateBuilder.class)
|
||||
class RestTemplateObservationConfiguration {
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ RestTemplate.class, ObservationRestTemplateCustomizer.class, ObservationRegistry.class,
|
||||
ObservationProperties.class })
|
||||
@ConditionalOnBean({ ObservationRegistry.class, RestTemplateBuilder.class })
|
||||
@EnableConfigurationProperties(ObservationProperties.class)
|
||||
public class RestTemplateObservationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationRestTemplateCustomizer observationRestTemplateCustomizer(ObservationRegistry observationRegistry,
|
||||
@@ -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 RestClient and RestTemplate observation.
|
||||
*/
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.restclient.actuate.observation;
|
||||
package org.springframework.boot.restclient.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.restclient.actuate.observation;
|
||||
package org.springframework.boot.restclient.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
/**
|
||||
* Observation integration for RestClient and RestTemplate.
|
||||
*/
|
||||
package org.springframework.boot.restclient.actuate.observation;
|
||||
package org.springframework.boot.restclient.observation;
|
||||
@@ -1,3 +1,5 @@
|
||||
org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration
|
||||
org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration
|
||||
org.springframework.boot.restclient.service.autoconfigure.HttpServiceClientAutoConfiguration
|
||||
org.springframework.boot.restclient.autoconfigure.observation.RestClientObservationAutoConfiguration
|
||||
org.springframework.boot.restclient.autoconfigure.observation.RestTemplateObservationAutoConfiguration
|
||||
org.springframework.boot.restclient.service.autoconfigure.HttpServiceClientAutoConfiguration
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
@@ -26,15 +26,12 @@ 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.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;
|
||||
import org.springframework.boot.restclient.observation.ObservationRestClientCustomizer;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -50,18 +47,18 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers.
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestClientObservationConfiguration}.
|
||||
* Tests for {@link RestClientObservationAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class RestClientObservationConfigurationTests {
|
||||
class RestClientObservationAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withBean(ObservationRegistry.class, TestObservationRegistry::create)
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, RestClientAutoConfiguration.class,
|
||||
HttpClientObservationsAutoConfiguration.class));
|
||||
RestClientObservationAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void contributesCustomizerBean() {
|
||||
@@ -102,35 +99,11 @@ 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);
|
||||
MockRestServiceServer server = restClientWithMockServer.mockServer();
|
||||
RestClient restClient = restClientWithMockServer.restClient();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
server.expect(requestTo("/test/" + i)).andRespond(withStatus(HttpStatus.OK));
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
restClient.get().uri("/test/" + i, String.class).retrieve().toBodilessEntity();
|
||||
}
|
||||
TestObservationRegistry registry = context.getBean(TestObservationRegistry.class);
|
||||
assertThat(registry).hasNumberOfObservationsWithNameEqualTo("http.client.requests", 3);
|
||||
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||
assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(2);
|
||||
assertThat(output).contains("Reached the maximum number of URI tags for 'http.client.requests'.")
|
||||
.contains("Are you using 'uriVariables'?");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void backsOffWhenRestClientBuilderIsMissing() {
|
||||
new ApplicationContextRunner().with(MetricsRun.simple())
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
|
||||
HttpClientObservationsAutoConfiguration.class))
|
||||
RestClientObservationAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ObservationRestClientCustomizer.class));
|
||||
}
|
||||
|
||||
@@ -144,9 +117,9 @@ class RestClientObservationConfigurationTests {
|
||||
|
||||
private RestClientWithMockServer buildRestClientAndMockServer(AssertableApplicationContext context) {
|
||||
Builder builder = context.getBean(Builder.class);
|
||||
MockServerRestClientCustomizer customizer = new MockServerRestClientCustomizer();
|
||||
customizer.customize(builder);
|
||||
return new RestClientWithMockServer(builder.build(), customizer.getServer());
|
||||
MockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();
|
||||
server.expect(requestTo("/projects/spring-boot")).andRespond(withStatus(HttpStatus.OK));
|
||||
return new RestClientWithMockServer(builder.build(), server);
|
||||
}
|
||||
|
||||
private record RestClientWithMockServer(RestClient restClient, MockRestServiceServer mockServer) {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
@@ -24,12 +24,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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;
|
||||
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.http.HttpStatus;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestClient.Builder;
|
||||
|
||||
@@ -38,7 +38,7 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers.
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestClientObservationConfiguration} without Micrometer Metrics.
|
||||
* Tests for {@link RestClientObservationAutoConfiguration} without Micrometer Metrics.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Andy Wilkinson
|
||||
@@ -46,12 +46,12 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
@ClassPathExclusions("micrometer-core-*.jar")
|
||||
class RestClientObservationConfigurationWithoutMetricsTests {
|
||||
class RestClientObservationAutoConfigurationWithoutMetricsTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withBean(ObservationRegistry.class, TestObservationRegistry::create)
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, RestClientAutoConfiguration.class,
|
||||
HttpClientObservationsAutoConfiguration.class));
|
||||
RestClientObservationAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void restClientCreatedWithBuilderIsInstrumented() {
|
||||
@@ -65,9 +65,8 @@ class RestClientObservationConfigurationWithoutMetricsTests {
|
||||
|
||||
private RestClient buildRestClient(AssertableApplicationContext context) {
|
||||
Builder builder = context.getBean(Builder.class);
|
||||
MockServerRestClientCustomizer customizer = new MockServerRestClientCustomizer();
|
||||
customizer.customize(builder);
|
||||
customizer.getServer().expect(requestTo("/projects/spring-boot")).andRespond(withStatus(HttpStatus.OK));
|
||||
MockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();
|
||||
server.expect(requestTo("/projects/spring-boot")).andRespond(withStatus(HttpStatus.OK));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
@@ -26,15 +26,13 @@ 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.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;
|
||||
import org.springframework.boot.restclient.observation.ObservationRestTemplateCustomizer;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -49,17 +47,17 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers.
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestTemplateObservationConfiguration}.
|
||||
* Tests for {@link RestTemplateObservationAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class RestTemplateObservationConfigurationTests {
|
||||
class RestTemplateObservationAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withBean(ObservationRegistry.class, TestObservationRegistry::create)
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
|
||||
RestTemplateAutoConfiguration.class, HttpClientObservationsAutoConfiguration.class));
|
||||
RestTemplateAutoConfiguration.class, RestTemplateObservationAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void contributesCustomizerBean() {
|
||||
@@ -100,34 +98,11 @@ 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();
|
||||
MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
server.expect(requestTo("/test/" + i)).andRespond(withStatus(HttpStatus.OK));
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
restTemplate.getForObject("/test/" + i, String.class);
|
||||
}
|
||||
TestObservationRegistry registry = context.getBean(TestObservationRegistry.class);
|
||||
assertThat(registry).hasNumberOfObservationsWithNameEqualTo("http.client.requests", 3);
|
||||
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||
assertThat(meterRegistry.find("http.client.requests").timers()).hasSize(2);
|
||||
assertThat(output).contains("Reached the maximum number of URI tags for 'http.client.requests'.")
|
||||
.contains("Are you using 'uriVariables'?");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void backsOffWhenRestTemplateBuilderIsMissing() {
|
||||
new ApplicationContextRunner().with(MetricsRun.simple())
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
|
||||
HttpClientObservationsAutoConfiguration.class))
|
||||
RestTemplateObservationAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ObservationRestTemplateCustomizer.class));
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.restclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
@@ -38,19 +38,19 @@ import static org.springframework.test.web.client.match.MockRestRequestMatchers.
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestTemplateObservationConfiguration} without Micrometer Metrics.
|
||||
* Tests for {@link RestTemplateObservationAutoConfiguration} without Micrometer Metrics.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
@ClassPathExclusions("micrometer-core-*.jar")
|
||||
class RestTemplateObservationConfigurationWithoutMetricsTests {
|
||||
class RestTemplateObservationAutoConfigurationWithoutMetricsTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withBean(ObservationRegistry.class, TestObservationRegistry::create)
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,
|
||||
RestTemplateAutoConfiguration.class, HttpClientObservationsAutoConfiguration.class));
|
||||
RestTemplateAutoConfiguration.class, RestTemplateObservationAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void restTemplateCreatedWithBuilderIsInstrumented() {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.restclient.actuate.observation;
|
||||
package org.springframework.boot.restclient.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.restclient.actuate.observation;
|
||||
package org.springframework.boot.restclient.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
@@ -15,6 +15,7 @@ dependencies {
|
||||
implementation(project(":spring-boot-project:spring-boot-http-codec"))
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-metrics"))
|
||||
optional(project(":spring-boot-project:spring-boot-reactor-netty"))
|
||||
optional("org.apache.httpcomponents.client5:httpclient5")
|
||||
optional("org.apache.httpcomponents.core5:httpcore5-reactive")
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.observation.web.client;
|
||||
package org.springframework.boot.webclient.autoconfigure.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.metrics.autoconfigure.MetricsProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;
|
||||
import org.springframework.boot.webclient.actuate.observation.ObservationWebClientCustomizer;
|
||||
import org.springframework.boot.webclient.observation.ObservationWebClientCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.function.client.ClientRequestObservationConvention;
|
||||
import org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -33,15 +33,19 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* Configure the instrumentation of {@link WebClient}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ WebClient.class, ObservationWebClientCustomizer.class })
|
||||
class WebClientObservationConfiguration {
|
||||
@AutoConfiguration(
|
||||
beforeName = "org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration")
|
||||
@ConditionalOnClass({ WebClient.class, ObservationWebClientCustomizer.class, ObservationRegistry.class,
|
||||
ObservationProperties.class })
|
||||
@EnableConfigurationProperties(ObservationProperties.class)
|
||||
public class WebClientObservationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
ObservationWebClientCustomizer observationWebClientCustomizer(ObservationRegistry observationRegistry,
|
||||
ObjectProvider<ClientRequestObservationConvention> customConvention,
|
||||
ObservationProperties observationProperties, MetricsProperties metricsProperties) {
|
||||
ObservationProperties observationProperties) {
|
||||
String name = observationProperties.getHttp().getClient().getRequests().getName();
|
||||
ClientRequestObservationConvention observationConvention = customConvention
|
||||
.getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));
|
||||
@@ -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 WebClient observation support.
|
||||
*/
|
||||
package org.springframework.boot.webclient.autoconfigure.observation;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.webclient.actuate.observation;
|
||||
package org.springframework.boot.webclient.observation;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
/**
|
||||
* Observation integration for WebClient.
|
||||
*/
|
||||
package org.springframework.boot.webclient.actuate.observation;
|
||||
package org.springframework.boot.webclient.observation;
|
||||
@@ -1,2 +1,3 @@
|
||||
org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration
|
||||
org.springframework.boot.webclient.autoconfigure.observation.WebClientObservationAutoConfiguration
|
||||
org.springframework.boot.webclient.service.autoconfigure.ReactiveHttpServiceClientAutoConfiguration
|
||||
|
||||
@@ -29,15 +29,13 @@ import org.junit.jupiter.api.Test;
|
||||
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.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;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.boot.webclient.actuate.observation.ObservationWebClientCustomizer;
|
||||
import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;
|
||||
import org.springframework.boot.webclient.autoconfigure.observation.WebClientObservationAutoConfiguration;
|
||||
import org.springframework.boot.webclient.observation.ObservationWebClientCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -53,18 +51,18 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebClientObservationConfiguration}
|
||||
* Tests for {@link WebClientObservationAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class WebClientObservationConfigurationTests {
|
||||
class WebClientObservationAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple())
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withBean(ObservationRegistry.class, TestObservationRegistry::create)
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, WebClientAutoConfiguration.class,
|
||||
HttpClientObservationsAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, WebClientAutoConfiguration.class))
|
||||
.withUserConfiguration(WebClientObservationAutoConfiguration.class);
|
||||
|
||||
@Test
|
||||
void contributesCustomizerBean() {
|
||||
@@ -98,49 +96,6 @@ class WebClientObservationConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {
|
||||
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.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) {
|
||||
WebClient webClient = mockWebClient(context.getBean(WebClient.Builder.class));
|
||||
TestObservationRegistry registry = context.getBean(TestObservationRegistry.class);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
webClient.get()
|
||||
.uri("https://example.org/projects/" + i)
|
||||
.retrieve()
|
||||
.toBodilessEntity()
|
||||
.block(Duration.ofSeconds(30));
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
private void validateWebClient(WebClient.Builder builder, TestObservationRegistry registry) {
|
||||
WebClient webClient = mockWebClient(builder);
|
||||
assertThat(registry).doesNotHaveAnyObservation();
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.webclient.actuate.observation;
|
||||
package org.springframework.boot.webclient.observation;
|
||||
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
Reference in New Issue
Block a user