Configure MeterBinders after beans have been created
Update `MeterRegistryPostProcessor` to configure `MeterRegistry` beans in two distinct sweeps. The first sweep applies customizers and filters as the `MeterRegistry` bean is initialized, the second sweep applies `MeterBinder` beans once all singletons have been instantiated. Prior to this commit, it was not possible for a `MeterBinder` bean to directly or indirectly use a `MeterRegistry`. It was also possible for bound meters to cause a deadlock during refresh processing if those meters could be updated on a thread other than main, such as GC notifications. Fixes gh-30636 Fixes gh-33070
This commit is contained in:
committed by
Andy Wilkinson
parent
e60084112e
commit
e5a0b164ac
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.actuate.autoconfigure.metrics;
|
||||
|
||||
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.boot.util.LambdaSafe;
|
||||
|
||||
/**
|
||||
* Configurer to apply {@link MeterRegistryCustomizer customizers}, {@link MeterFilter
|
||||
* filters}, {@link MeterBinder binders} and {@link Metrics#addRegistry global
|
||||
* registration} to {@link MeterRegistry meter registries}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MeterRegistryConfigurer {
|
||||
|
||||
private final ObjectProvider<MeterRegistryCustomizer<?>> customizers;
|
||||
|
||||
private final ObjectProvider<MeterFilter> filters;
|
||||
|
||||
private final ObjectProvider<MeterBinder> binders;
|
||||
|
||||
private final boolean addToGlobalRegistry;
|
||||
|
||||
private final boolean hasCompositeMeterRegistry;
|
||||
|
||||
MeterRegistryConfigurer(ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
|
||||
ObjectProvider<MeterBinder> binders, boolean addToGlobalRegistry, boolean hasCompositeMeterRegistry) {
|
||||
this.customizers = customizers;
|
||||
this.filters = filters;
|
||||
this.binders = binders;
|
||||
this.addToGlobalRegistry = addToGlobalRegistry;
|
||||
this.hasCompositeMeterRegistry = hasCompositeMeterRegistry;
|
||||
}
|
||||
|
||||
void configure(MeterRegistry registry) {
|
||||
// Customizers must be applied before binders, as they may add custom
|
||||
// tags or alter timer or summary configuration.
|
||||
customize(registry);
|
||||
if (!(registry instanceof AutoConfiguredCompositeMeterRegistry)) {
|
||||
addFilters(registry);
|
||||
}
|
||||
if (!this.hasCompositeMeterRegistry || registry instanceof CompositeMeterRegistry) {
|
||||
addBinders(registry);
|
||||
}
|
||||
if (this.addToGlobalRegistry && registry != Metrics.globalRegistry) {
|
||||
Metrics.addRegistry(registry);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void customize(MeterRegistry registry) {
|
||||
LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers.orderedStream().toList(), registry)
|
||||
.withLogger(MeterRegistryConfigurer.class).invoke((customizer) -> customizer.customize(registry));
|
||||
}
|
||||
|
||||
private void addFilters(MeterRegistry registry) {
|
||||
this.filters.orderedStream().forEach(registry.config()::meterFilter);
|
||||
}
|
||||
|
||||
private void addBinders(MeterRegistry registry) {
|
||||
this.binders.orderedStream().forEach((binder) -> binder.bindTo(registry));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,65 +16,138 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} that delegates to a lazily created
|
||||
* {@link MeterRegistryConfigurer} to post-process {@link MeterRegistry} beans.
|
||||
* {@link BeanPostProcessor} for {@link MeterRegistry} beans.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MeterRegistryPostProcessor implements BeanPostProcessor {
|
||||
class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializingSingleton {
|
||||
|
||||
private final ObjectProvider<MeterBinder> meterBinders;
|
||||
private final boolean hasNoCompositeMeterRegistryBeans;
|
||||
|
||||
private final ObjectProvider<MeterFilter> meterFilters;
|
||||
private final boolean useGlobalRegistry;
|
||||
|
||||
private final ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers;
|
||||
private final ObjectProvider<MeterRegistryCustomizer<?>> customizers;
|
||||
|
||||
private final ObjectProvider<MetricsProperties> metricsProperties;
|
||||
private final ObjectProvider<MeterFilter> filters;
|
||||
|
||||
private volatile MeterRegistryConfigurer configurer;
|
||||
private final ObjectProvider<MeterBinder> binders;
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
private volatile boolean deferBinding = true;
|
||||
|
||||
private final Set<MeterRegistry> deferredBindings = new LinkedHashSet<>();
|
||||
|
||||
MeterRegistryPostProcessor(ApplicationContext applicationContext, MetricsProperties metricsProperties,
|
||||
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
|
||||
ObjectProvider<MeterBinder> binders) {
|
||||
this(hasNoCompositeMeterRegistryBeans(applicationContext), metricsProperties.isUseGlobalRegistry(), customizers,
|
||||
filters, binders);
|
||||
}
|
||||
|
||||
private static boolean hasNoCompositeMeterRegistryBeans(ApplicationContext applicationContext) {
|
||||
return applicationContext.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length == 0;
|
||||
}
|
||||
|
||||
MeterRegistryPostProcessor(boolean hasNoCompositeMeterRegistryBeans, boolean useGlobalRegistry,
|
||||
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
|
||||
ObjectProvider<MeterBinder> binders) {
|
||||
this.hasNoCompositeMeterRegistryBeans = hasNoCompositeMeterRegistryBeans;
|
||||
this.useGlobalRegistry = useGlobalRegistry;
|
||||
this.customizers = customizers;
|
||||
this.filters = filters;
|
||||
this.binders = binders;
|
||||
|
||||
MeterRegistryPostProcessor(ObjectProvider<MeterBinder> meterBinders, ObjectProvider<MeterFilter> meterFilters,
|
||||
ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers,
|
||||
ObjectProvider<MetricsProperties> metricsProperties, ApplicationContext applicationContext) {
|
||||
this.meterBinders = meterBinders;
|
||||
this.meterFilters = meterFilters;
|
||||
this.meterRegistryCustomizers = meterRegistryCustomizers;
|
||||
this.metricsProperties = metricsProperties;
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof MeterRegistry meterRegistry) {
|
||||
getConfigurer().configure(meterRegistry);
|
||||
postProcessMeterRegistry(meterRegistry);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private MeterRegistryConfigurer getConfigurer() {
|
||||
if (this.configurer == null) {
|
||||
boolean hasCompositeMeterRegistry = this.applicationContext
|
||||
.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length != 0;
|
||||
this.configurer = new MeterRegistryConfigurer(this.meterRegistryCustomizers, this.meterFilters,
|
||||
this.meterBinders, this.metricsProperties.getObject().isUseGlobalRegistry(),
|
||||
hasCompositeMeterRegistry);
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
synchronized (this.deferredBindings) {
|
||||
this.deferBinding = false;
|
||||
this.deferredBindings.forEach(this::applyBinders);
|
||||
}
|
||||
return this.configurer;
|
||||
}
|
||||
|
||||
private void postProcessMeterRegistry(MeterRegistry meterRegistry) {
|
||||
// Customizers must be applied before binders, as they may add custom tags or
|
||||
// alter timer or summary configuration.
|
||||
applyCustomizers(meterRegistry);
|
||||
applyFilters(meterRegistry);
|
||||
addToGlobalRegistryIfNecessary(meterRegistry);
|
||||
if (isBindable(meterRegistry)) {
|
||||
applyBinders(meterRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void applyCustomizers(MeterRegistry meterRegistry) {
|
||||
List<MeterRegistryCustomizer<?>> customizers = this.customizers.orderedStream().toList();
|
||||
LambdaSafe.callbacks(MeterRegistryCustomizer.class, customizers, meterRegistry)
|
||||
.withLogger(MeterRegistryPostProcessor.class)
|
||||
.invoke((customizer) -> customizer.customize(meterRegistry));
|
||||
}
|
||||
|
||||
private void applyFilters(MeterRegistry meterRegistry) {
|
||||
if (meterRegistry instanceof AutoConfiguredCompositeMeterRegistry) {
|
||||
return;
|
||||
}
|
||||
this.filters.orderedStream().forEach(meterRegistry.config()::meterFilter);
|
||||
}
|
||||
|
||||
private void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) {
|
||||
if (this.useGlobalRegistry && !isGlobalRegistry(meterRegistry)) {
|
||||
Metrics.addRegistry(meterRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGlobalRegistry(MeterRegistry meterRegistry) {
|
||||
return meterRegistry == Metrics.globalRegistry;
|
||||
}
|
||||
|
||||
private boolean isBindable(MeterRegistry meterRegistry) {
|
||||
return this.hasNoCompositeMeterRegistryBeans || isCompositeMeterRegistry(meterRegistry);
|
||||
}
|
||||
|
||||
private boolean isCompositeMeterRegistry(MeterRegistry meterRegistry) {
|
||||
return meterRegistry instanceof CompositeMeterRegistry;
|
||||
}
|
||||
|
||||
void applyBinders(MeterRegistry meterRegistry) {
|
||||
if (this.deferBinding) {
|
||||
synchronized (this.deferredBindings) {
|
||||
if (this.deferBinding) {
|
||||
this.deferredBindings.add(meterRegistry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.binders.orderedStream().forEach((binder) -> binder.bindTo(meterRegistry));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,12 +50,11 @@ public class MetricsAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static MeterRegistryPostProcessor meterRegistryPostProcessor(ObjectProvider<MeterBinder> meterBinders,
|
||||
ObjectProvider<MeterFilter> meterFilters,
|
||||
ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers,
|
||||
ObjectProvider<MetricsProperties> metricsProperties, ApplicationContext applicationContext) {
|
||||
return new MeterRegistryPostProcessor(meterBinders, meterFilters, meterRegistryCustomizers, metricsProperties,
|
||||
applicationContext);
|
||||
public static MeterRegistryPostProcessor meterRegistryPostProcessor(ApplicationContext applicationContext,
|
||||
MetricsProperties metricsProperties, ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers,
|
||||
ObjectProvider<MeterFilter> meterFilters, ObjectProvider<MeterBinder> meterBinders) {
|
||||
return new MeterRegistryPostProcessor(applicationContext, metricsProperties, meterRegistryCustomizers,
|
||||
meterFilters, meterBinders);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.actuate.autoconfigure.amqp;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Integration test to check that {@link RabbitMetricsAutoConfiguration} does not cause a
|
||||
* dependency cycle when used with {@link MeterBinder}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see <a href="https://github.com/spring-projects/spring-boot/issues/30636">gh-30636</a>
|
||||
*/
|
||||
class RabbitMetricsAutoConfigurationMeterBinderCycleIntegrationTests {
|
||||
|
||||
@Test
|
||||
void doesNotFormCycle() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
|
||||
context.getBean(TestService.class);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ TestService.class, RabbitAutoConfiguration.class, MetricsAutoConfiguration.class,
|
||||
SimpleMetricsExportAutoConfiguration.class, RabbitMetricsAutoConfiguration.class })
|
||||
static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
static class TestService implements MeterBinder {
|
||||
|
||||
TestService(RabbitTemplate rabbitTemplate) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTo(MeterRegistry registry) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,28 +40,28 @@ import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link MeterRegistryConfigurer}.
|
||||
* Tests for {@link MeterRegistryPostProcessor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MeterRegistryConfigurerTests {
|
||||
|
||||
private List<MeterBinder> binders = new ArrayList<>();
|
||||
|
||||
private List<MeterFilter> filters = new ArrayList<>();
|
||||
class MeterRegistryPostProcessorTests {
|
||||
|
||||
private List<MeterRegistryCustomizer<?>> customizers = new ArrayList<>();
|
||||
|
||||
private List<MeterFilter> filters = new ArrayList<>();
|
||||
|
||||
private List<MeterBinder> binders = new ArrayList<>();
|
||||
|
||||
@Mock
|
||||
private MeterBinder mockBinder;
|
||||
private MeterRegistryCustomizer<MeterRegistry> mockCustomizer;
|
||||
|
||||
@Mock
|
||||
private MeterFilter mockFilter;
|
||||
|
||||
@Mock
|
||||
private MeterRegistryCustomizer<MeterRegistry> mockCustomizer;
|
||||
private MeterBinder mockBinder;
|
||||
|
||||
@Mock
|
||||
private MeterRegistry mockRegistry;
|
||||
@@ -70,73 +70,79 @@ class MeterRegistryConfigurerTests {
|
||||
private Config mockConfig;
|
||||
|
||||
@Test
|
||||
void configureWhenCompositeShouldApplyCustomizer() {
|
||||
void postProcessAndInitializeWhenCompositeAppliesCustomizer() {
|
||||
this.customizers.add(this.mockCustomizer);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, false);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
CompositeMeterRegistry composite = new CompositeMeterRegistry();
|
||||
configurer.configure(composite);
|
||||
postProcessAndInitialize(processor, composite);
|
||||
then(this.mockCustomizer).should().customize(composite);
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldApplyCustomizer() {
|
||||
void postProcessAndInitializeAppliesCustomizer() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
this.customizers.add(this.mockCustomizer);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
then(this.mockCustomizer).should().customize(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldApplyFilter() {
|
||||
void postProcessAndInitializeAppliesFilter() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
this.filters.add(this.mockFilter);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
then(this.mockConfig).should().meterFilter(this.mockFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldApplyBinder() {
|
||||
void postProcessAndInitializeBindsTo() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
this.binders.add(this.mockBinder);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
then(this.mockBinder).should().bindTo(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldApplyBinderToComposite() {
|
||||
void postProcessAndInitializeWhenCompositeBindsTo() {
|
||||
this.binders.add(this.mockBinder);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, true);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
CompositeMeterRegistry composite = new CompositeMeterRegistry();
|
||||
configurer.configure(composite);
|
||||
postProcessAndInitialize(processor, composite);
|
||||
then(this.mockBinder).should().bindTo(composite);
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldNotApplyBinderWhenCompositeExists() {
|
||||
void postProcessAndInitializeWhenCompositeExistsDoesNotBindTo() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), null, false, true);
|
||||
configurer.configure(this.mockRegistry);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters), null);
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
then(this.mockBinder).shouldHaveNoInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldBeCalledInOrderCustomizerFilterBinder() {
|
||||
void postProcessAndInitializeBeOrderedCustomizerThenFilterThenBindTo() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
this.customizers.add(this.mockCustomizer);
|
||||
this.filters.add(this.mockFilter);
|
||||
this.binders.add(this.mockBinder);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
InOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer);
|
||||
then(this.mockCustomizer).should(ordered).customize(this.mockRegistry);
|
||||
then(this.mockConfig).should(ordered).meterFilter(this.mockFilter);
|
||||
@@ -144,12 +150,13 @@ class MeterRegistryConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), true, false);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, true,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
try {
|
||||
configurer.configure(this.mockRegistry);
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
assertThat(Metrics.globalRegistry.getRegistries()).contains(this.mockRegistry);
|
||||
}
|
||||
finally {
|
||||
@@ -158,14 +165,33 @@ class MeterRegistryConfigurerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenNotAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistry() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(createObjectProvider(this.customizers),
|
||||
createObjectProvider(this.filters), createObjectProvider(this.binders), false, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
postProcessAndInitialize(processor, this.mockRegistry);
|
||||
assertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postProcessDoesNotBindToUntilSingletonsInitialized() {
|
||||
given(this.mockRegistry.config()).willReturn(this.mockConfig);
|
||||
this.binders.add(this.mockBinder);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false,
|
||||
createObjectProvider(this.customizers), createObjectProvider(this.filters),
|
||||
createObjectProvider(this.binders));
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "meterRegistry");
|
||||
then(this.mockBinder).shouldHaveNoInteractions();
|
||||
processor.afterSingletonsInstantiated();
|
||||
then(this.mockBinder).should().bindTo(this.mockRegistry);
|
||||
}
|
||||
|
||||
private void postProcessAndInitialize(MeterRegistryPostProcessor processor, MeterRegistry registry) {
|
||||
processor.postProcessAfterInitialization(registry, "meterRegistry");
|
||||
processor.afterSingletonsInstantiated();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> ObjectProvider<T> createObjectProvider(List<T> objects) {
|
||||
ObjectProvider<T> objectProvider = mock(ObjectProvider.class);
|
||||
@@ -41,11 +41,12 @@ import org.springframework.context.annotation.Configuration;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MeterRegistryConfigurer}.
|
||||
* Integration tests for {@link MeterRegistryPostProcessor} configured by
|
||||
* {@link MetricsAutoConfiguration}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
class MeterRegistryConfigurerIntegrationTests {
|
||||
class MetricsAutoConfigurationMeterRegistryPostProcessorIntegrationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.with(MetricsRun.limitedTo(AtlasMetricsExportAutoConfiguration.class,
|
||||
@@ -68,7 +69,6 @@ class MeterRegistryConfigurerIntegrationTests {
|
||||
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,
|
||||
SimpleMetricsExportAutoConfiguration.class))
|
||||
.withUserConfiguration(TestConfiguration.class).run((context) -> {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<suppress files="LogbackLoggingSystem\.java" checks="IllegalImport" />
|
||||
<suppress files="LogbackLoggingSystemTests\.java" checks="IllegalImport" />
|
||||
<suppress files="LogbackConfigurationAotContributionTests\.java" checks="IllegalImport" />
|
||||
<suppress files="MeterRegistryConfigurerIntegrationTests\.java" checks="IllegalImport" />
|
||||
<suppress files="MetricsAutoConfigurationMeterRegistryPostProcessorIntegrationTests\.java" checks="IllegalImport" message="LoggerFactory"/>
|
||||
<suppress files="SpringApplicationTests\.java" checks="FinalClass" />
|
||||
<suppress files=".+Configuration\.java" checks="HideUtilityClassConstructor" />
|
||||
<suppress files=".+Application\.java" checks="HideUtilityClassConstructor" />
|
||||
|
||||
Reference in New Issue
Block a user