diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessor.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessor.java index d7de4d0a58..232a9f67a2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessor.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessor.java @@ -23,17 +23,17 @@ import io.micrometer.core.instrument.MeterRegistry; 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.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.util.LambdaSafe; /** - * {@link BeanPostProcessor} to apply {@link MeterRegistryCustomizer customizers} and - * {@link MeterBinder binters} and {@link Metrics#addRegistry global registration} to - * {@link MeterRegistry meter registries}. This post processor intentionally skips - * {@link CompositeMeterRegistry} with the assumptions that the registries it contains are - * beans and will be customized directly. + * {@link BeanPostProcessor} to apply {@link MeterRegistryCustomizer customizers}, + * {@link MeterFilter filters}, {@link MeterBinder binders} and {@link Metrics#addRegistry + * global registration} to {@link MeterRegistry meter registries}. This post processor + * intentionally skips {@link CompositeMeterRegistry} with the assumptions that the + * registries it contains are beans and will be customized directly. * * @author Jon Schneider * @author Phillip Webb @@ -42,15 +42,19 @@ class MeterRegistryPostProcessor implements BeanPostProcessor { private final Collection> customizers; + private final Collection filters; + private final Collection binders; private final boolean addToGlobalRegistry; - MeterRegistryPostProcessor(ObjectProvider> binders, - ObjectProvider>> customizers, + MeterRegistryPostProcessor(Collection binders, + Collection filters, + Collection> customizers, boolean addToGlobalRegistry) { - this.binders = binders.getIfAvailable(Collections::emptyList); - this.customizers = customizers.getIfAvailable(Collections::emptyList); + this.binders = (binders != null ? binders : Collections.emptyList()); + this.filters = (filters != null ? filters : Collections.emptyList()); + this.customizers = (customizers != null ? customizers : Collections.emptyList()); this.addToGlobalRegistry = addToGlobalRegistry; } @@ -74,6 +78,7 @@ class MeterRegistryPostProcessor implements BeanPostProcessor { // Customizers must be applied before binders, as they may add custom tags or // alter timer or summary configuration. customize(registry); + addFilters(registry); addBinders(registry); if (this.addToGlobalRegistry && registry != Metrics.globalRegistry) { Metrics.addRegistry(registry); @@ -87,6 +92,10 @@ class MeterRegistryPostProcessor implements BeanPostProcessor { .invoke((customizer) -> customizer.customize(registry)); } + private void addFilters(MeterRegistry registry) { + this.filters.forEach(registry.config()::meterFilter); + } + private void addBinders(MeterRegistry registry) { this.binders.forEach((binder) -> binder.bindTo(registry)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java index ff31bc4ec7..1a8256c524 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java @@ -22,6 +22,7 @@ import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.binder.MeterBinder; +import io.micrometer.core.instrument.config.MeterFilter; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; @@ -73,9 +74,11 @@ public class MetricsAutoConfiguration { @Bean public static MeterRegistryPostProcessor meterRegistryPostProcessor( ObjectProvider> binders, + ObjectProvider> filters, ObjectProvider>> customizers, MetricsProperties properties) { - return new MeterRegistryPostProcessor(binders, customizers, + return new MeterRegistryPostProcessor(binders.getIfAvailable(), + filters.getIfAvailable(), customizers.getIfAvailable(), properties.isUseGlobalRegistry()); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessorTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessorTests.java index edf4fce9ab..7859670b08 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessorTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessorTests.java @@ -17,24 +17,22 @@ package org.springframework.boot.actuate.autoconfigure.metrics; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.MeterRegistry.Config; 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.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.util.Assert; - import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -46,34 +44,37 @@ import static org.mockito.Mockito.verifyZeroInteractions; */ public class MeterRegistryPostProcessorTests { - private List binderBeans = new ArrayList<>(); + private List binders = new ArrayList<>(); - private List> customizerBeans = new ArrayList<>(); + private List filters = new ArrayList<>(); - private ObjectProvider> binders = TestObjectProvider - .of(this.binderBeans); - - private ObjectProvider>> customizers = TestObjectProvider - .of(this.customizerBeans); + private List> customizers = new ArrayList<>(); @Mock private MeterBinder mockBinder; + @Mock + private MeterFilter mockFilter; + @Mock private MeterRegistryCustomizer mockCustomizer; @Mock private MeterRegistry mockRegistry; + @Mock + private Config mockConfig; + @Before public void setup() { MockitoAnnotations.initMocks(this); + given(this.mockRegistry.config()).willReturn(this.mockConfig); } @Test public void postProcessWhenNotRegistryShouldReturnBean() { MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, false); + this.binders, this.filters, this.customizers, false); Object bean = new Object(); String beanName = "name"; assertThat(processor.postProcessBeforeInitialization(bean, beanName)) @@ -84,10 +85,10 @@ public class MeterRegistryPostProcessorTests { @Test public void postProcessorWhenCompositeShouldSkip() { - this.binderBeans.add(this.mockBinder); - this.customizerBeans.add(this.mockCustomizer); + this.binders.add(this.mockBinder); + this.customizers.add(this.mockCustomizer); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, false); + this.binders, this.filters, this.customizers, false); assertThat(processor.postProcessAfterInitialization(new CompositeMeterRegistry(), "name")); verifyZeroInteractions(this.mockBinder, this.mockCustomizer); @@ -95,38 +96,49 @@ public class MeterRegistryPostProcessorTests { @Test public void postProcessShouldApplyCustomizer() { - this.customizerBeans.add(this.mockCustomizer); + this.customizers.add(this.mockCustomizer); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, false); + this.binders, this.filters, this.customizers, false); assertThat(processor.postProcessAfterInitialization(this.mockRegistry, "name")); verify(this.mockCustomizer).customize(this.mockRegistry); } @Test - public void postProcessShouldApplyBinder() { - this.binderBeans.add(this.mockBinder); + public void postProcessShouldApplyFilter() { + this.filters.add(this.mockFilter); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, false); + this.binders, this.filters, this.customizers, false); + assertThat(processor.postProcessAfterInitialization(this.mockRegistry, "name")); + verify(this.mockConfig).meterFilter(this.mockFilter); + } + + @Test + public void postProcessShouldApplyBinder() { + this.binders.add(this.mockBinder); + MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( + this.binders, this.filters, this.customizers, false); assertThat(processor.postProcessAfterInitialization(this.mockRegistry, "name")); verify(this.mockBinder).bindTo(this.mockRegistry); } @Test - public void postProcessShouldCustomizeBeforeApplyingBinder() { - this.binderBeans.add(this.mockBinder); - this.customizerBeans.add(this.mockCustomizer); + public void postProcessShouldBeCallInOrderCustomizeFilterBinder() { + this.customizers.add(this.mockCustomizer); + this.filters.add(this.mockFilter); + this.binders.add(this.mockBinder); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, false); + this.binders, this.filters, this.customizers, false); processor.postProcessAfterInitialization(this.mockRegistry, "name"); - InOrder ordered = inOrder(this.mockCustomizer, this.mockBinder); + InOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer); ordered.verify(this.mockCustomizer).customize(this.mockRegistry); + ordered.verify(this.mockConfig).meterFilter(this.mockFilter); ordered.verify(this.mockBinder).bindTo(this.mockRegistry); } @Test public void postProcessWhenAddToGlobalRegistryShouldAddToGlobalRegistry() { MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, true); + this.binders, this.filters, this.customizers, true); try { processor.postProcessAfterInitialization(this.mockRegistry, "name"); assertThat(Metrics.globalRegistry.getRegistries()) @@ -140,45 +152,10 @@ public class MeterRegistryPostProcessorTests { @Test public void postProcessWhenNotAddToGlobalRegistryShouldAddToGlobalRegistry() { MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( - this.binders, this.customizers, false); + this.binders, this.filters, this.customizers, false); processor.postProcessAfterInitialization(this.mockRegistry, "name"); assertThat(Metrics.globalRegistry.getRegistries()) .doesNotContain(this.mockRegistry); } - private static class TestObjectProvider implements ObjectProvider { - - private final T value; - - TestObjectProvider(T value) { - this.value = value; - } - - @Override - public T getObject() throws BeansException { - Assert.state(this.value != null, "No value"); - return this.value; - } - - @Override - public T getObject(Object... args) throws BeansException { - return this.value; - } - - @Override - public T getIfAvailable() throws BeansException { - return this.value; - } - - @Override - public T getIfUnique() throws BeansException { - throw new UnsupportedOperationException(); - } - - public static TestObjectProvider of(T value) { - return new TestObjectProvider<>(value); - } - - } - }