Skip to content

Commit 1b8f5fe

Browse files
committed
spring-projectsGH-2148: Fix MeterRegistry Detection
Resolves spring-projects#2148 - use Boot's `AutoConfiguredCompositeMeterRegistry`, if only one (tested with a Boot application) - use `@Primary` registry bean **cherry-pick to 2.8.x**
1 parent 43cb781 commit 1b8f5fe

File tree

2 files changed

+126
-5
lines changed

2 files changed

+126
-5
lines changed

spring-kafka/src/main/java/org/springframework/kafka/support/micrometer/MicrometerHolder.java

+52-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,16 @@
1616

1717
package org.springframework.kafka.support.micrometer;
1818

19+
import java.util.Collections;
1920
import java.util.Map;
21+
import java.util.Map.Entry;
2022
import java.util.concurrent.ConcurrentHashMap;
23+
import java.util.stream.Collectors;
2124

25+
import org.springframework.beans.factory.config.BeanDefinition;
26+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2227
import org.springframework.context.ApplicationContext;
28+
import org.springframework.context.ConfigurableApplicationContext;
2329
import org.springframework.lang.Nullable;
2430

2531
import io.micrometer.core.instrument.MeterRegistry;
@@ -69,12 +75,56 @@ public MicrometerHolder(@Nullable ApplicationContext context, String name,
6975
this.timerDesc = timerDesc;
7076
this.name = name;
7177
this.tags = tags;
78+
registries = filterRegistries(registries, context);
7279
if (registries.size() == 1) {
7380
this.registry = registries.values().iterator().next();
7481
buildTimer(NONE_EXCEPTION_METERS_KEY);
7582
}
7683
else {
77-
throw new IllegalStateException("No micrometer registry present (or more than one)");
84+
throw new IllegalStateException("No micrometer registry present (or more than one and "
85+
+ "none marked @Primary)");
86+
}
87+
}
88+
89+
private Map<String, MeterRegistry> filterRegistries(Map<String, MeterRegistry> registries,
90+
ApplicationContext context) {
91+
92+
if (registries.size() == 1) {
93+
return registries;
94+
}
95+
Map<String, MeterRegistry> filtered = registries.entrySet()
96+
.stream()
97+
.filter(entry -> entry.getValue()
98+
.getClass()
99+
.getName()
100+
.equals("org.springframework.boot.actuate.autoconfigure.metrics."
101+
+ "AutoConfiguredCompositeMeterRegistry"))
102+
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
103+
if (filtered.size() == 1) {
104+
return filtered;
105+
}
106+
MeterRegistry primary = null;
107+
if (context instanceof ConfigurableApplicationContext) {
108+
BeanDefinitionRegistry bdr = (BeanDefinitionRegistry) ((ConfigurableApplicationContext) context)
109+
.getBeanFactory();
110+
for (Entry<String, MeterRegistry> entry : registries.entrySet()) {
111+
BeanDefinition beanDefinition = bdr.getBeanDefinition(entry.getKey());
112+
if (beanDefinition.isPrimary()) {
113+
if (primary != null) {
114+
primary = null;
115+
break;
116+
}
117+
else {
118+
primary = entry.getValue();
119+
}
120+
}
121+
}
122+
}
123+
if (primary != null) {
124+
return Collections.singletonMap("primary", primary);
125+
}
126+
else {
127+
return registries;
78128
}
79129
}
80130

spring-kafka/src/test/java/org/springframework/kafka/support/micrometer/MicrometerHolderTests.java

+74-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.kafka.support.micrometer;
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2021
import static org.mockito.ArgumentMatchers.any;
2122
import static org.mockito.ArgumentMatchers.anyBoolean;
2223
import static org.mockito.BDDMockito.given;
@@ -31,6 +32,9 @@
3132
import org.junit.jupiter.api.Test;
3233

3334
import org.springframework.context.ApplicationContext;
35+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
36+
import org.springframework.context.annotation.Bean;
37+
import org.springframework.context.annotation.Primary;
3438
import org.springframework.test.util.ReflectionTestUtils;
3539

3640
import io.micrometer.core.instrument.MeterRegistry;
@@ -44,11 +48,12 @@ public class MicrometerHolderTests {
4448

4549
@SuppressWarnings({ "unchecked", "deprecation" })
4650
@Test
47-
public void testMicrometerHolderRecordSuccessWorksGracefullyAfterDestroy() {
51+
void testMicrometerHolderRecordSuccessWorksGracefullyAfterDestroy() {
4852
MeterRegistry meterRegistry = new SimpleMeterRegistry();
4953
ApplicationContext ctx = mock(ApplicationContext.class);
5054
Timer.Sample sample = mock(Timer.Sample.class);
51-
given(ctx.getBeansOfType(any(), anyBoolean(), anyBoolean())).willReturn(Collections.singletonMap("registry", meterRegistry));
55+
given(ctx.getBeansOfType(any(), anyBoolean(), anyBoolean()))
56+
.willReturn(Collections.singletonMap("registry", meterRegistry));
5257

5358
MicrometerHolder micrometerHolder = new MicrometerHolder(ctx, "holderName",
5459
"timerName", "timerDesc", Collections.emptyMap());
@@ -68,4 +73,70 @@ public void testMicrometerHolderRecordSuccessWorksGracefullyAfterDestroy() {
6873
verifyNoMoreInteractions(ctx, sample);
6974
}
7075

76+
@Test
77+
void multiReg() {
78+
assertThatIllegalStateException().isThrownBy(() -> new MicrometerHolder(
79+
new AnnotationConfigApplicationContext(Config1.class), "", "", "", Collections.emptyMap()));
80+
}
81+
82+
@Test
83+
void twoPrimaries() {
84+
assertThatIllegalStateException().isThrownBy(() -> new MicrometerHolder(
85+
new AnnotationConfigApplicationContext(Config2.class), "", "", "", Collections.emptyMap()));
86+
}
87+
88+
@Test
89+
void primary() {
90+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config3.class);
91+
MicrometerHolder micrometerHolder = new MicrometerHolder(ctx, "holderName",
92+
"timerName", "timerDesc", Collections.emptyMap());
93+
Map<String, Timer> meters = (Map<String, Timer>) ReflectionTestUtils.getField(micrometerHolder, "meters");
94+
assertThat(meters).hasSize(1);
95+
}
96+
97+
static class Config1 {
98+
99+
@Bean
100+
MeterRegistry reg1() {
101+
return new SimpleMeterRegistry();
102+
}
103+
104+
@Bean
105+
MeterRegistry reg2() {
106+
return new SimpleMeterRegistry();
107+
}
108+
109+
}
110+
111+
static class Config2 {
112+
113+
@Bean
114+
@Primary
115+
MeterRegistry reg1() {
116+
return new SimpleMeterRegistry();
117+
}
118+
119+
@Bean
120+
@Primary
121+
MeterRegistry reg2() {
122+
return new SimpleMeterRegistry();
123+
}
124+
125+
}
126+
127+
static class Config3 {
128+
129+
@Bean
130+
@Primary
131+
MeterRegistry reg1() {
132+
return new SimpleMeterRegistry();
133+
}
134+
135+
@Bean
136+
MeterRegistry reg2() {
137+
return new SimpleMeterRegistry();
138+
}
139+
140+
}
141+
71142
}

0 commit comments

Comments
 (0)