mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Remove ServerHttpObservationFilter from WebFlux
This commit removes the auto-configuration of the `ServerHttpObservationFilter` bean for WebFlux applications as it's been deprecated by Spring Framework. The Observability instrumentation is now handled at the `WebHttpHandlerBuilder` in Framework directly and doesn't need any auto-configuration from Spring Boot. Closes gh-37344
This commit is contained in:
parent
8a1f6d4f32
commit
c8d036eaa8
@ -21,9 +21,6 @@ import io.micrometer.core.instrument.config.MeterFilter;
|
|||||||
import io.micrometer.observation.Observation;
|
import io.micrometer.observation.Observation;
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
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.MetricsProperties;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter;
|
import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
||||||
@ -33,16 +30,10 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention;
|
|
||||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;
|
|
||||||
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring
|
* {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring
|
||||||
@ -53,48 +44,22 @@ import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
|
|||||||
* @author Dmytro Nosan
|
* @author Dmytro Nosan
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class,
|
@AutoConfiguration(after = { SimpleMetricsExportAutoConfiguration.class, ObservationAutoConfiguration.class })
|
||||||
SimpleMetricsExportAutoConfiguration.class, ObservationAutoConfiguration.class })
|
@ConditionalOnClass({ Observation.class, MeterRegistry.class })
|
||||||
@ConditionalOnClass(Observation.class)
|
@ConditionalOnBean({ ObservationRegistry.class, MeterRegistry.class })
|
||||||
@ConditionalOnBean(ObservationRegistry.class)
|
|
||||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||||
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
|
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
|
||||||
@SuppressWarnings("removal")
|
|
||||||
public class WebFluxObservationAutoConfiguration {
|
public class WebFluxObservationAutoConfiguration {
|
||||||
|
|
||||||
private final ObservationProperties observationProperties;
|
|
||||||
|
|
||||||
public WebFluxObservationAutoConfiguration(ObservationProperties observationProperties) {
|
|
||||||
this.observationProperties = observationProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(ServerHttpObservationFilter.class)
|
@Order(0)
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
|
MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties,
|
||||||
public ServerHttpObservationFilter webfluxObservationFilter(ObservationRegistry registry,
|
ObservationProperties observationProperties) {
|
||||||
ObjectProvider<ServerRequestObservationConvention> customConvention) {
|
String name = observationProperties.getHttp().getServer().getRequests().getName();
|
||||||
String name = this.observationProperties.getHttp().getServer().getRequests().getName();
|
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
|
||||||
ServerRequestObservationConvention convention = customConvention
|
() -> "Reached the maximum number of URI tags for '%s'.".formatted(name));
|
||||||
.getIfAvailable(() -> new DefaultServerRequestObservationConvention(name));
|
return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(),
|
||||||
return new ServerHttpObservationFilter(registry, convention);
|
filter);
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
@ConditionalOnClass(MeterRegistry.class)
|
|
||||||
@ConditionalOnBean(MeterRegistry.class)
|
|
||||||
static class MeterFilterConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Order(0)
|
|
||||||
MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties,
|
|
||||||
ObservationProperties observationProperties) {
|
|
||||||
String name = observationProperties.getHttp().getServer().getRequests().getName();
|
|
||||||
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
|
|
||||||
() -> "Reached the maximum number of URI tags for '%s'.".formatted(name));
|
|
||||||
return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(),
|
|
||||||
filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.observation.web.reactive;
|
package org.springframework.boot.actuate.autoconfigure.observation.web.reactive;
|
||||||
|
|
||||||
import java.util.List;
|
import java.time.Duration;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
import io.micrometer.core.instrument.MeterRegistry;
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||||
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
|
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
|
||||||
@ -33,16 +33,6 @@ import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplic
|
|||||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||||
import org.springframework.boot.test.system.CapturedOutput;
|
import org.springframework.boot.test.system.CapturedOutput;
|
||||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention;
|
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
|
||||||
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
|
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
|
||||||
import org.springframework.web.server.WebFilter;
|
|
||||||
import org.springframework.web.server.WebFilterChain;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -54,7 +44,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
*/
|
*/
|
||||||
@ExtendWith(OutputCaptureExtension.class)
|
@ExtendWith(OutputCaptureExtension.class)
|
||||||
@SuppressWarnings("removal")
|
|
||||||
class WebFluxObservationAutoConfigurationTests {
|
class WebFluxObservationAutoConfigurationTests {
|
||||||
|
|
||||||
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||||
@ -62,31 +51,6 @@ class WebFluxObservationAutoConfigurationTests {
|
|||||||
.withConfiguration(
|
.withConfiguration(
|
||||||
AutoConfigurations.of(ObservationAutoConfiguration.class, WebFluxObservationAutoConfiguration.class));
|
AutoConfigurations.of(ObservationAutoConfiguration.class, WebFluxObservationAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldProvideWebFluxObservationFilter() {
|
|
||||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ServerHttpObservationFilter.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldProvideWebFluxObservationFilterOrdered() {
|
|
||||||
this.contextRunner.withBean(FirstWebFilter.class).withBean(ThirdWebFilter.class).run((context) -> {
|
|
||||||
List<WebFilter> webFilters = context.getBeanProvider(WebFilter.class).orderedStream().toList();
|
|
||||||
assertThat(webFilters.get(0)).isInstanceOf(FirstWebFilter.class);
|
|
||||||
assertThat(webFilters.get(1)).isInstanceOf(ServerHttpObservationFilter.class);
|
|
||||||
assertThat(webFilters.get(2)).isInstanceOf(ThirdWebFilter.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldUseCustomConventionWhenAvailable() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomConventionConfiguration.class).run((context) -> {
|
|
||||||
assertThat(context).hasSingleBean(ServerHttpObservationFilter.class);
|
|
||||||
assertThat(context).getBean(ServerHttpObservationFilter.class)
|
|
||||||
.extracting("observationConvention")
|
|
||||||
.isInstanceOf(CustomConvention.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {
|
void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {
|
||||||
this.contextRunner.withUserConfiguration(TestController.class)
|
this.contextRunner.withUserConfiguration(TestController.class)
|
||||||
@ -108,7 +72,7 @@ class WebFluxObservationAutoConfigurationTests {
|
|||||||
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
|
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
|
||||||
"management.observations.http.server.requests.name=my.http.server.requests")
|
"management.observations.http.server.requests.name=my.http.server.requests")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
MeterRegistry registry = getInitializedMeterRegistry(context);
|
MeterRegistry registry = getInitializedMeterRegistry(context, "my.http.server.requests");
|
||||||
assertThat(registry.get("my.http.server.requests").meters()).hasSizeLessThanOrEqualTo(2);
|
assertThat(registry.get("my.http.server.requests").meters()).hasSizeLessThanOrEqualTo(2);
|
||||||
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
|
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
|
||||||
});
|
});
|
||||||
@ -127,53 +91,17 @@ class WebFluxObservationAutoConfigurationTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context)
|
private MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context) {
|
||||||
throws Exception {
|
return getInitializedMeterRegistry(context, "http.server.requests");
|
||||||
return getInitializedMeterRegistry(context, "/test0", "/test1", "/test2");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context, String... urls)
|
private MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context,
|
||||||
throws Exception {
|
String metricName) {
|
||||||
assertThat(context).hasSingleBean(ServerHttpObservationFilter.class);
|
MeterRegistry meterRegistry = context.getBean(MeterRegistry.class);
|
||||||
WebTestClient client = WebTestClient.bindToApplicationContext(context).build();
|
meterRegistry.timer(metricName, "uri", "/test0").record(Duration.of(500, ChronoUnit.SECONDS));
|
||||||
for (String url : urls) {
|
meterRegistry.timer(metricName, "uri", "/test1").record(Duration.of(500, ChronoUnit.SECONDS));
|
||||||
client.get().uri(url).exchange().expectStatus().isOk();
|
meterRegistry.timer(metricName, "uri", "/test2").record(Duration.of(500, ChronoUnit.SECONDS));
|
||||||
}
|
return meterRegistry;
|
||||||
return context.getBean(MeterRegistry.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class CustomConventionConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
CustomConvention customConvention() {
|
|
||||||
return new CustomConvention();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CustomConvention extends DefaultServerRequestObservationConvention {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
|
||||||
static class FirstWebFilter implements WebFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
|
||||||
return chain.filter(exchange);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE + 2)
|
|
||||||
static class ThirdWebFilter implements WebFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
|
||||||
return chain.filter(exchange);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -245,9 +245,6 @@ When it does so, the orders shown in the following table will be used:
|
|||||||
|===
|
|===
|
||||||
| Web Filter | Order
|
| Web Filter | Order
|
||||||
|
|
||||||
| `ServerHttpObservationFilter` (Micrometer Observability)
|
|
||||||
| `Ordered.HIGHEST_PRECEDENCE + 1`
|
|
||||||
|
|
||||||
| `WebFilterChainProxy` (Spring Security)
|
| `WebFilterChainProxy` (Spring Security)
|
||||||
| `-100`
|
| `-100`
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user