Apply micrometer MeterFilter beans automatically
Update `MeterRegistryPostProcessor` and `MetricsAutoConfiguration` so that micrometer `MeterFilter` beans are automatically applied. Fixes gh-11843
This commit is contained in:
parent
3f5adfbccc
commit
8f23ee4e58
|
@ -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<MeterRegistryCustomizer<?>> customizers;
|
||||
|
||||
private final Collection<MeterFilter> filters;
|
||||
|
||||
private final Collection<MeterBinder> binders;
|
||||
|
||||
private final boolean addToGlobalRegistry;
|
||||
|
||||
MeterRegistryPostProcessor(ObjectProvider<Collection<MeterBinder>> binders,
|
||||
ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers,
|
||||
MeterRegistryPostProcessor(Collection<MeterBinder> binders,
|
||||
Collection<MeterFilter> filters,
|
||||
Collection<MeterRegistryCustomizer<?>> 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));
|
||||
}
|
||||
|
|
|
@ -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<Collection<MeterBinder>> binders,
|
||||
ObjectProvider<Collection<MeterFilter>> filters,
|
||||
ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers,
|
||||
MetricsProperties properties) {
|
||||
return new MeterRegistryPostProcessor(binders, customizers,
|
||||
return new MeterRegistryPostProcessor(binders.getIfAvailable(),
|
||||
filters.getIfAvailable(), customizers.getIfAvailable(),
|
||||
properties.isUseGlobalRegistry());
|
||||
}
|
||||
|
||||
|
|
|
@ -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<MeterBinder> binderBeans = new ArrayList<>();
|
||||
private List<MeterBinder> binders = new ArrayList<>();
|
||||
|
||||
private List<MeterRegistryCustomizer<?>> customizerBeans = new ArrayList<>();
|
||||
private List<MeterFilter> filters = new ArrayList<>();
|
||||
|
||||
private ObjectProvider<Collection<MeterBinder>> binders = TestObjectProvider
|
||||
.of(this.binderBeans);
|
||||
|
||||
private ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers = TestObjectProvider
|
||||
.of(this.customizerBeans);
|
||||
private List<MeterRegistryCustomizer<?>> customizers = new ArrayList<>();
|
||||
|
||||
@Mock
|
||||
private MeterBinder mockBinder;
|
||||
|
||||
@Mock
|
||||
private MeterFilter mockFilter;
|
||||
|
||||
@Mock
|
||||
private MeterRegistryCustomizer<MeterRegistry> 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<T> implements ObjectProvider<T> {
|
||||
|
||||
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 <T> TestObjectProvider<T> of(T value) {
|
||||
return new TestObjectProvider<>(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue