Merge pull request #32973 from izeye

* gh-32973:
  Polish "Handle custom observation name for HTTP reqs in max URI tag filters"
  Handle custom observation name for HTTP reqs in max URI tag filters

Closes gh-32973
pull/32994/head
Andy Wilkinson 2 years ago
commit bdc960da4e

@ -27,7 +27,6 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; 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.MetricsProperties.Web.Server;
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;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
@ -108,12 +107,15 @@ public class WebFluxObservationAutoConfiguration {
@Bean @Bean
@Order(0) @Order(0)
MeterFilter metricsHttpServerUriTagFilter(MetricsProperties properties) { MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties,
Server serverProperties = properties.getWeb().getServer(); ObservationProperties observationProperties) {
String metricName = serverProperties.getRequest().getMetricName(); String observationName = observationProperties.getHttp().getServer().getRequests().getName();
String name = (observationName != null) ? observationName
: metricsProperties.getWeb().getServer().getRequest().getMetricName();
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
() -> "Reached the maximum number of URI tags for '%s'.".formatted(metricName)); () -> "Reached the maximum number of URI tags for '%s'.".formatted(name));
return MeterFilter.maximumAllowableTags(metricName, "uri", serverProperties.getMaxUriTags(), filter); return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(),
filter);
} }
} }

@ -84,10 +84,7 @@ public class WebMvcObservationAutoConfiguration {
public FilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(ObservationRegistry registry, public FilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(ObservationRegistry registry,
ObjectProvider<WebMvcTagsProvider> customTagsProvider, ObjectProvider<WebMvcTagsProvider> customTagsProvider,
ObjectProvider<WebMvcTagsContributor> contributorsProvider) { ObjectProvider<WebMvcTagsContributor> contributorsProvider) {
String name = httpRequestsMetricName(this.observationProperties, this.metricsProperties);
String observationName = this.observationProperties.getHttp().getServer().getRequests().getName();
String metricName = this.metricsProperties.getWeb().getServer().getRequest().getMetricName();
String name = (observationName != null) ? observationName : metricName;
ServerRequestObservationConvention convention = new DefaultServerRequestObservationConvention(name); ServerRequestObservationConvention convention = new DefaultServerRequestObservationConvention(name);
WebMvcTagsProvider tagsProvider = customTagsProvider.getIfAvailable(); WebMvcTagsProvider tagsProvider = customTagsProvider.getIfAvailable();
List<WebMvcTagsContributor> contributors = contributorsProvider.orderedStream().toList(); List<WebMvcTagsContributor> contributors = contributorsProvider.orderedStream().toList();
@ -101,6 +98,13 @@ public class WebMvcObservationAutoConfiguration {
return registration; return registration;
} }
private static String httpRequestsMetricName(ObservationProperties observationProperties,
MetricsProperties metricsProperties) {
String observationName = observationProperties.getHttp().getServer().getRequests().getName();
return (observationName != null) ? observationName
: metricsProperties.getWeb().getServer().getRequest().getMetricName();
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MeterRegistry.class) @ConditionalOnClass(MeterRegistry.class)
@ConditionalOnBean(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class)
@ -108,11 +112,12 @@ public class WebMvcObservationAutoConfiguration {
@Bean @Bean
@Order(0) @Order(0)
MeterFilter metricsHttpServerUriTagFilter(MetricsProperties properties) { MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties,
String metricName = properties.getWeb().getServer().getRequest().getMetricName(); ObservationProperties observationProperties) {
String name = httpRequestsMetricName(observationProperties, metricsProperties);
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
() -> String.format("Reached the maximum number of URI tags for '%s'.", metricName)); () -> String.format("Reached the maximum number of URI tags for '%s'.", name));
return MeterFilter.maximumAllowableTags(metricName, "uri", properties.getWeb().getServer().getMaxUriTags(), return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(),
filter); filter);
} }

@ -16,21 +16,28 @@
package org.springframework.boot.actuate.autoconfigure.observation.web.reactive; package org.springframework.boot.actuate.autoconfigure.observation.web.reactive;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.Tags;
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 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;
import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController;
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor; import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor;
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider; import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
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.OutputCaptureExtension; import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.filter.reactive.ServerHttpObservationFilter; import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
@ -76,6 +83,75 @@ class WebFluxObservationAutoConfigurationTests {
}); });
} }
@Test
void afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
ObservationAutoConfiguration.class, WebFluxAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2").run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("http.server.requests").meters().size()).isLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'http.server.requests'");
});
}
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomMetricName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
ObservationAutoConfiguration.class, WebFluxAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
"management.metrics.web.server.request.metric-name=my.http.server.requests")
.run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("my.http.server.requests").meters().size()).isLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
});
}
@Test
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
ObservationAutoConfiguration.class, WebFluxAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
"management.observations.http.server.requests.name=my.http.server.requests")
.run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("my.http.server.requests").meters().size()).isLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
});
}
@Test
void shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
ObservationAutoConfiguration.class, WebFluxAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=5").run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("http.server.requests").meters()).hasSize(3);
assertThat(output)
.doesNotContain("Reached the maximum number of URI tags for 'http.server.requests'");
});
}
private MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context)
throws Exception {
return getInitializedMeterRegistry(context, "/test0", "/test1", "/test2");
}
private MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context, String... urls)
throws Exception {
assertThat(context).hasSingleBean(ServerHttpObservationFilter.class);
WebTestClient client = WebTestClient.bindToApplicationContext(context).build();
for (String url : urls) {
client.get().uri(url).exchange().expectStatus().isOk();
}
return context.getBean(MeterRegistry.class);
}
@Deprecated(since = "3.0.0", forRemoval = true) @Deprecated(since = "3.0.0", forRemoval = true)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class CustomTagsProviderConfiguration { static class CustomTagsProviderConfiguration {

@ -148,6 +148,35 @@ class WebMvcObservationAutoConfigurationTests {
}); });
} }
@Test
@Deprecated(since = "3.0.0", forRemoval = true)
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomMetricName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
ObservationAutoConfiguration.class, WebMvcAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
"management.metrics.web.server.request.metric-name=my.http.server.requests")
.run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("my.http.server.requests").meters().size()).isLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
});
}
@Test
void afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class)
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
ObservationAutoConfiguration.class, WebMvcAutoConfiguration.class))
.withPropertyValues("management.metrics.web.server.max-uri-tags=2",
"management.observations.http.server.requests.name=my.http.server.requests")
.run((context) -> {
MeterRegistry registry = getInitializedMeterRegistry(context);
assertThat(registry.get("my.http.server.requests").meters().size()).isLessThanOrEqualTo(2);
assertThat(output).contains("Reached the maximum number of URI tags for 'my.http.server.requests'");
});
}
@Test @Test
void shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) { void shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestController.class) this.contextRunner.withUserConfiguration(TestController.class)

Loading…
Cancel
Save