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