diff --git a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfiguration.java b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfiguration.java index 917722f7eb7..a7892c81513 100644 --- a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfiguration.java +++ b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfiguration.java @@ -17,7 +17,6 @@ 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; @@ -51,13 +50,12 @@ public final class HttpClientMetricsAutoConfiguration { @Bean @Order(0) - MeterFilter metricsHttpClientUriTagFilter(ObservationProperties observationProperties, + OnlyOnceLoggingDenyMeterFilter 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); + String meterNamePrefix = observationProperties.getHttp().getClient().getRequests().getName(); + int maxUriTags = clientProperties.getMaxUriTags(); + return new OnlyOnceLoggingDenyMeterFilter(meterNamePrefix, "uri", maxUriTags, "Are you using 'uriVariables'?"); } } diff --git a/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfigurationTests.java b/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfigurationTests.java index b2eefc71659..7c605e62307 100644 --- a/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfigurationTests.java +++ b/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfigurationTests.java @@ -52,7 +52,7 @@ class HttpClientMetricsAutoConfigurationTests { 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'.") + assertThat(output).contains("Reached the maximum number of 'uri' tags for 'http.client.requests'.") .contains("Are you using 'uriVariables'?"); }); } diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilter.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilter.java index ecb4b66c981..fdd07171510 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilter.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilter.java @@ -16,6 +16,8 @@ package org.springframework.boot.micrometer.metrics; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -24,33 +26,90 @@ import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilterReply; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; /** - * {@link MeterFilter} to log only once a warning message and deny a {@link Id Meter.Id}. + * {@link MeterFilter} to log a single warning message and deny a {@link Id Meter.Id} + * after a number of attempts for a given tag. * * @author Jon Schneider * @author Dmytro Nosan + * @author Phillip Webb * @since 4.0.0 */ public final class OnlyOnceLoggingDenyMeterFilter implements MeterFilter { - private static final Log logger = LogFactory.getLog(OnlyOnceLoggingDenyMeterFilter.class); + private final Log logger; private final AtomicBoolean alreadyWarned = new AtomicBoolean(); + private final String meterNamePrefix; + + private final int maximumTagValues; + + private final String tagKey; + private final Supplier message; - public OnlyOnceLoggingDenyMeterFilter(Supplier message) { + private final Set observedTagValues = ConcurrentHashMap.newKeySet(); + + /** + * Create a new {@link OnlyOnceLoggingDenyMeterFilter} with an upper bound on the + * number of tags produced by matching metrics. + * @param meterNamePrefix the prefix of the meter name to apply the filter to + * @param tagKey the tag to place an upper bound on + * @param maximumTagValues the total number of tag values that are allowable + */ + public OnlyOnceLoggingDenyMeterFilter(String meterNamePrefix, String tagKey, int maximumTagValues) { + this(meterNamePrefix, tagKey, maximumTagValues, (String) null); + } + + /** + * Create a new {@link OnlyOnceLoggingDenyMeterFilter} with an upper bound on the + * number of tags produced by matching metrics. + * @param meterNamePrefix the prefix of the meter name to apply the filter to + * @param tagKey the tag to place an upper bound on + * @param maximumTagValues the total number of tag values that are allowable + * @param hint an additional hint to add to the logged message or {@code null} + */ + public OnlyOnceLoggingDenyMeterFilter(String meterNamePrefix, String tagKey, int maximumTagValues, + @Nullable String hint) { + this(null, meterNamePrefix, tagKey, maximumTagValues, + () -> String.format("Reached the maximum number of '%s' tags for '%s'.%s", tagKey, meterNamePrefix, + (hint != null) ? " " + hint : "")); + } + + private OnlyOnceLoggingDenyMeterFilter(@Nullable Log logger, String meterNamePrefix, String tagKey, + int maximumTagValues, Supplier message) { Assert.notNull(message, "'message' must not be null"); + Assert.isTrue(maximumTagValues >= 0, "'maximumTagValues' must be positive"); + this.logger = (logger != null) ? logger : LogFactory.getLog(OnlyOnceLoggingDenyMeterFilter.class); + this.meterNamePrefix = meterNamePrefix; + this.maximumTagValues = maximumTagValues; + this.tagKey = tagKey; this.message = message; } @Override public MeterFilterReply accept(Id id) { - if (logger.isWarnEnabled() && this.alreadyWarned.compareAndSet(false, true)) { - logger.warn(this.message.get()); + if (this.meterNamePrefix == null) { + return logAndDeny(); + } + String tagValue = id.getName().startsWith(this.meterNamePrefix) ? id.getTag(this.tagKey) : null; + if (tagValue != null && !this.observedTagValues.contains(tagValue)) { + if (this.observedTagValues.size() >= this.maximumTagValues) { + return logAndDeny(); + } + this.observedTagValues.add(tagValue); + } + return MeterFilterReply.NEUTRAL; + } + + private MeterFilterReply logAndDeny() { + if (this.logger.isWarnEnabled() && this.alreadyWarned.compareAndSet(false, true)) { + this.logger.warn(this.message.get()); } return MeterFilterReply.DENY; } diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java index 7a9b5551f61..c1175f26326 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java @@ -19,6 +19,7 @@ package org.springframework.boot.micrometer.metrics.autoconfigure; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.stream.Stream; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Metrics; @@ -30,6 +31,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.micrometer.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.util.LambdaSafe; import org.springframework.context.ApplicationContext; @@ -109,10 +111,13 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing } private void applyFilters(MeterRegistry meterRegistry) { - if (meterRegistry instanceof AutoConfiguredCompositeMeterRegistry) { - return; + if (this.filters != null) { + Stream filters = this.filters.orderedStream(); + if (isAutoConfiguredComposite(meterRegistry)) { + filters = filters.filter(OnlyOnceLoggingDenyMeterFilter.class::isInstance); + } + filters.forEach(meterRegistry.config()::meterFilter); } - this.filters.orderedStream().forEach(meterRegistry.config()::meterFilter); } private void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) { diff --git a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilterTests.java b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilterTests.java new file mode 100644 index 00000000000..21e7fdfbb49 --- /dev/null +++ b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/OnlyOnceLoggingDenyMeterFilterTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.micrometer.metrics; + +import java.util.Collections; + +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Meter.Type; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.config.MeterFilterReply; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OnlyOnceLoggingDenyMeterFilter}. + * + * @author Phillip Webb + */ +class OnlyOnceLoggingDenyMeterFilterTests { + + @Test + void applyWhenNameDoesNotHavePrefixReturnsNeutral() { + OnlyOnceLoggingDenyMeterFilter filter = new OnlyOnceLoggingDenyMeterFilter("test", "k", 1); + assertThat(filter.accept(meterId("tset", "k", "v"))).isEqualTo(MeterFilterReply.NEUTRAL); + assertThat(filter).extracting("observedTagValues").asInstanceOf(InstanceOfAssertFactories.COLLECTION).isEmpty(); + } + + @Test + void applyWhenNameHasPrefixButNoTagKeyReturnsNeutral() { + OnlyOnceLoggingDenyMeterFilter filter = new OnlyOnceLoggingDenyMeterFilter("test", "k", 1); + assertThat(filter.accept(meterId("test", "k", "v"))).isEqualTo(MeterFilterReply.NEUTRAL); + assertThat(filter).extracting("observedTagValues") + .asInstanceOf(InstanceOfAssertFactories.COLLECTION) + .containsExactly("v"); + } + + @Test + void applyWhenNameHasPrefixAndTagKeyReturnsNeutralUntilLimit() { + OnlyOnceLoggingDenyMeterFilter filter = new OnlyOnceLoggingDenyMeterFilter("test", "k", 1); + assertThat(filter.accept(meterId("test", "k", "v1"))).isEqualTo(MeterFilterReply.NEUTRAL); + assertThat(filter.accept(meterId("test", "k", "v2"))).isEqualTo(MeterFilterReply.DENY); + assertThat(filter.accept(meterId("test", "k", "v3"))).isEqualTo(MeterFilterReply.DENY); + assertThat(filter).extracting("observedTagValues") + .asInstanceOf(InstanceOfAssertFactories.COLLECTION) + .containsExactly("v1"); + } + + private Meter.Id meterId(String name, String tagKey, String tagValue) { + MeterRegistry registry = new SimpleMeterRegistry(); + Meter meter = Meter.builder(name, Type.COUNTER, Collections.emptyList()) + .tag(tagKey, tagValue) + .register(registry); + return meter.getId(); + } + +} diff --git a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java index 6e801cc73da..ddbf73a312f 100644 --- a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java +++ b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.micrometer.metrics.autoconfigure; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; @@ -27,6 +28,7 @@ import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.composite.CompositeMeterRegistry; import io.micrometer.core.instrument.config.MeterFilter; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InOrder; @@ -36,6 +38,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.micrometer.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryPostProcessor.CompositeMeterRegistries; import static org.assertj.core.api.Assertions.assertThat; @@ -131,6 +134,22 @@ class MeterRegistryPostProcessorTests { then(this.mockConfig).should().meterFilter(this.mockFilter); } + @Test + void postProcessAndInitializeOnlyAppliesLmiitedFiltersToAutoConfigured() { + OnlyOnceLoggingDenyMeterFilter onlyOnceFilter = mock(); + this.filters.add(this.mockFilter); + this.filters.add(onlyOnceFilter); + MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED, + createObjectProvider(this.properties), createObjectProvider(this.customizers), + createObjectProvider(this.filters), createObjectProvider(this.binders)); + AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM, + Collections.emptyList()); + postProcessAndInitialize(processor, composite); + assertThat(composite).extracting("filters") + .asInstanceOf(InstanceOfAssertFactories.ARRAY) + .containsExactly(onlyOnceFilter); + } + @Test void postProcessAndInitializeBindsTo() { given(this.mockRegistry.config()).willReturn(this.mockConfig); @@ -273,11 +292,18 @@ class MeterRegistryPostProcessorTests { } private ObjectProvider createEmptyObjectProvider() { - return new ObjectProvider() { + return new ObjectProvider<>() { + @Override public T getObject() throws BeansException { throw new NoSuchBeanDefinitionException("No bean"); } + + @Override + public Stream orderedStream() { + return Stream.empty(); + } + }; } diff --git a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java index ce987d75885..5772f05b014 100644 --- a/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java +++ b/module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.webflux.autoconfigure; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; @@ -64,12 +63,10 @@ public final class WebFluxObservationAutoConfiguration { @Bean @Order(0) - MeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties) { - String name = this.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); + OnlyOnceLoggingDenyMeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties) { + String meterNamePrefix = this.observationProperties.getHttp().getServer().getRequests().getName(); + int maxUriTags = metricsProperties.getWeb().getServer().getMaxUriTags(); + return new OnlyOnceLoggingDenyMeterFilter(meterNamePrefix, "uri", maxUriTags); } @Bean diff --git a/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/observation/autoconfigure/WebFluxObservationAutoConfigurationTests.java b/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/observation/autoconfigure/WebFluxObservationAutoConfigurationTests.java index 050dda738fa..2fe1e5aa1ec 100644 --- a/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/observation/autoconfigure/WebFluxObservationAutoConfigurationTests.java +++ b/module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/observation/autoconfigure/WebFluxObservationAutoConfigurationTests.java @@ -66,7 +66,7 @@ class WebFluxObservationAutoConfigurationTests { .run((context) -> { MeterRegistry registry = getInitializedMeterRegistry(context); assertThat(registry.get("http.server.requests").meters()).hasSizeLessThanOrEqualTo(2); - assertThat(output).contains("Reached the maximum number of URI tags for 'http.server.requests'"); + assertThat(output).contains("Reached the maximum number of 'uri' tags for 'http.server.requests'"); }); } @@ -80,7 +80,7 @@ class WebFluxObservationAutoConfigurationTests { .run((context) -> { MeterRegistry registry = getInitializedMeterRegistry(context, "my.http.server.requests"); 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'"); }); } @@ -93,7 +93,8 @@ class WebFluxObservationAutoConfigurationTests { .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'"); + assertThat(output) + .doesNotContain("Reached the maximum number of 'uri' tags for 'http.server.requests'"); }); } diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java index 458027fec8e..2e7af780c66 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.webmvc.autoconfigure; import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; import jakarta.servlet.DispatcherType; @@ -86,13 +85,11 @@ public final class WebMvcObservationAutoConfiguration { @Bean @Order(0) - MeterFilter metricsHttpServerUriTagFilter(ObservationProperties observationProperties, + OnlyOnceLoggingDenyMeterFilter metricsHttpServerUriTagFilter(ObservationProperties observationProperties, MetricsProperties metricsProperties) { - String name = observationProperties.getHttp().getServer().getRequests().getName(); - MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter( - () -> String.format("Reached the maximum number of URI tags for '%s'.", name)); - return MeterFilter.maximumAllowableTags(name, "uri", metricsProperties.getWeb().getServer().getMaxUriTags(), - filter); + String meterNamePrefix = observationProperties.getHttp().getServer().getRequests().getName(); + int maxUriTags = metricsProperties.getWeb().getServer().getMaxUriTags(); + return new OnlyOnceLoggingDenyMeterFilter(meterNamePrefix, "uri", maxUriTags); } } diff --git a/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java b/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java index 8d09db131b6..e8fc3100b03 100644 --- a/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java +++ b/module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java @@ -139,7 +139,7 @@ class WebMvcObservationAutoConfigurationTests { .run((context) -> { MeterRegistry registry = getInitializedMeterRegistry(context); assertThat(registry.get("http.server.requests").meters()).hasSizeLessThanOrEqualTo(2); - assertThat(output).contains("Reached the maximum number of URI tags for 'http.server.requests'"); + assertThat(output).contains("Reached the maximum number of 'uri' tags for 'http.server.requests'"); }); } @@ -153,7 +153,7 @@ class WebMvcObservationAutoConfigurationTests { .run((context) -> { MeterRegistry registry = getInitializedMeterRegistry(context); 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'"); }); } @@ -166,7 +166,8 @@ class WebMvcObservationAutoConfigurationTests { .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'"); + assertThat(output) + .doesNotContain("Reached the maximum number of 'uri' tags for 'http.server.requests'"); }); }