Skip to content

Commit

Permalink
Reduce duplicate binding of meters to user-defined composites
Browse files Browse the repository at this point in the history
Fixes gh-42396
  • Loading branch information
wilkinsona committed Sep 20, 2024
1 parent 0aeea6f commit 267a642
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand Down Expand Up @@ -42,7 +42,7 @@
*/
class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializingSingleton {

private final boolean hasNoCompositeMeterRegistryBeans;
private final CompositeMeterRegistries compositeMeterRegistries;

private final ObjectProvider<MetricsProperties> properties;

Expand All @@ -59,17 +59,13 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing
MeterRegistryPostProcessor(ApplicationContext applicationContext,
ObjectProvider<MetricsProperties> metricsProperties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,
ObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {
this(hasNoCompositeMeterRegistryBeans(applicationContext), metricsProperties, customizers, filters, binders);
this(CompositeMeterRegistries.of(applicationContext), metricsProperties, customizers, filters, binders);
}

private static boolean hasNoCompositeMeterRegistryBeans(ApplicationContext applicationContext) {
return applicationContext.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length == 0;
}

MeterRegistryPostProcessor(boolean hasNoCompositeMeterRegistryBeans, ObjectProvider<MetricsProperties> properties,
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
ObjectProvider<MeterBinder> binders) {
this.hasNoCompositeMeterRegistryBeans = hasNoCompositeMeterRegistryBeans;
MeterRegistryPostProcessor(CompositeMeterRegistries compositeMeterRegistries,
ObjectProvider<MetricsProperties> properties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,
ObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {
this.compositeMeterRegistries = compositeMeterRegistries;
this.properties = properties;
this.customizers = customizers;
this.filters = filters;
Expand Down Expand Up @@ -130,11 +126,21 @@ private boolean isGlobalRegistry(MeterRegistry meterRegistry) {
}

private boolean isBindable(MeterRegistry meterRegistry) {
return this.hasNoCompositeMeterRegistryBeans || isCompositeMeterRegistry(meterRegistry);
return isAutoConfiguredComposite(meterRegistry) || isCompositeWithOnlyUserDefinedComposites(meterRegistry)
|| noCompositeMeterRegistries();
}

private boolean isAutoConfiguredComposite(MeterRegistry meterRegistry) {
return meterRegistry instanceof AutoConfiguredCompositeMeterRegistry;
}

private boolean isCompositeWithOnlyUserDefinedComposites(MeterRegistry meterRegistry) {
return this.compositeMeterRegistries == CompositeMeterRegistries.ONLY_USER_DEFINED
&& meterRegistry instanceof CompositeMeterRegistry;
}

private boolean isCompositeMeterRegistry(MeterRegistry meterRegistry) {
return meterRegistry instanceof CompositeMeterRegistry;
private boolean noCompositeMeterRegistries() {
return this.compositeMeterRegistries == CompositeMeterRegistries.NONE;
}

void applyBinders(MeterRegistry meterRegistry) {
Expand All @@ -149,4 +155,21 @@ void applyBinders(MeterRegistry meterRegistry) {
this.binders.orderedStream().forEach((binder) -> binder.bindTo(meterRegistry));
}

enum CompositeMeterRegistries {

NONE, AUTO_CONFIGURED, ONLY_USER_DEFINED;

private static CompositeMeterRegistries of(ApplicationContext context) {
if (hasBeansOfType(AutoConfiguredCompositeMeterRegistry.class, context)) {
return AUTO_CONFIGURED;
}
return hasBeansOfType(CompositeMeterRegistry.class, context) ? ONLY_USER_DEFINED : NONE;
}

private static boolean hasBeansOfType(Class<?> type, ApplicationContext context) {
return context.getBeanNamesForType(type, false, false).length > 0;
}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2024 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.
Expand All @@ -17,8 +17,10 @@
package org.springframework.boot.actuate.autoconfigure.metrics;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.MeterRegistry.Config;
import io.micrometer.core.instrument.Metrics;
Expand All @@ -32,6 +34,7 @@
import org.mockito.junit.jupiter.MockitoExtension;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryPostProcessor.CompositeMeterRegistries;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
Expand Down Expand Up @@ -76,21 +79,34 @@ class MeterRegistryPostProcessorTests {
}

@Test
void postProcessAndInitializeWhenCompositeAppliesCustomizer() {
void postProcessAndInitializeWhenUserDefinedCompositeAppliesCustomizer() {
this.customizers.add(this.mockCustomizer);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),
createObjectProvider(this.customizers), createObjectProvider(this.filters),
createObjectProvider(this.binders));
CompositeMeterRegistry composite = new CompositeMeterRegistry();
postProcessAndInitialize(processor, composite);
then(this.mockCustomizer).should().customize(composite);
}

@Test
void postProcessAndInitializeWhenAutoConfiguredCompositeAppliesCustomizer() {
this.customizers.add(this.mockCustomizer);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
createObjectProvider(this.properties), createObjectProvider(this.customizers), null,
createObjectProvider(this.binders));
AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,
Collections.emptyList());
postProcessAndInitialize(processor, composite);
then(this.mockCustomizer).should().customize(composite);
}

@Test
void postProcessAndInitializeAppliesCustomizer() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.customizers.add(this.mockCustomizer);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry);
Expand All @@ -101,7 +117,7 @@ void postProcessAndInitializeAppliesCustomizer() {
void postProcessAndInitializeAppliesFilter() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.filters.add(this.mockFilter);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry);
Expand All @@ -112,41 +128,75 @@ void postProcessAndInitializeAppliesFilter() {
void postProcessAndInitializeBindsTo() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockBinder).should().bindTo(this.mockRegistry);
}

@Test
void postProcessAndInitializeWhenCompositeBindsTo() {
void whenUserDefinedCompositeThenPostProcessAndInitializeCompositeBindsTo() {
this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),
createObjectProvider(this.customizers), createObjectProvider(this.filters),
createObjectProvider(this.binders));
CompositeMeterRegistry composite = new CompositeMeterRegistry();
postProcessAndInitialize(processor, composite);
then(this.mockBinder).should().bindTo(composite);
}

@Test
void postProcessAndInitializeWhenCompositeExistsDoesNotBindTo() {
void whenUserDefinedCompositeThenPostProcessAndInitializeStandardRegistryDoesNotBindTo() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),
createObjectProvider(this.customizers), createObjectProvider(this.filters), null);
postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockBinder).shouldHaveNoInteractions();
}

@Test
void whenAutoConfiguredCompositeThenPostProcessAndInitializeAutoConfiguredCompositeBindsTo() {
this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
createObjectProvider(this.properties), createObjectProvider(this.customizers), null,
createObjectProvider(this.binders));
AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,
Collections.emptyList());
postProcessAndInitialize(processor, composite);
then(this.mockBinder).should().bindTo(composite);
}

@Test
void whenAutoConfiguredCompositeThenPostProcessAndInitializeCompositeDoesNotBindTo() {
this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), null);
CompositeMeterRegistry composite = new CompositeMeterRegistry();
postProcessAndInitialize(processor, composite);
then(this.mockBinder).shouldHaveNoInteractions();
}

@Test
void whenAutoConfiguredCompositeThenPostProcessAndInitializeStandardRegistryDoesNotBindTo() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), null);
postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockBinder).shouldHaveNoInteractions();
}

@Test
void postProcessAndInitializeBeOrderedCustomizerThenFilterThenBindTo() {
void postProcessAndInitializeIsOrderedCustomizerThenFilterThenBindTo() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.customizers.add(this.mockCustomizer);
this.filters.add(this.mockFilter);
this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry);
Expand All @@ -160,7 +210,7 @@ void postProcessAndInitializeBeOrderedCustomizerThenFilterThenBindTo() {
void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.properties.setUseGlobalRegistry(true);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
try {
Expand All @@ -175,7 +225,7 @@ void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {
@Test
void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistry() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry);
Expand All @@ -186,7 +236,7 @@ void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistr
void postProcessDoesNotBindToUntilSingletonsInitialized() {
given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
processor.postProcessAfterInitialization(this.mockRegistry, "meterRegistry");
Expand Down

0 comments on commit 267a642

Please sign in to comment.