diff --git a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts index 589d5c510cbf..080a991c18f2 100644 --- a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts +++ b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/build.gradle.kts @@ -15,6 +15,7 @@ muzzle { dependencies { library("org.springframework.boot:spring-boot-actuator-autoconfigure:2.0.0.RELEASE") library("io.micrometer:micrometer-core:1.5.0") + testLibrary("io.micrometer:micrometer-registry-prometheus:1.0.1") implementation(project(":instrumentation:micrometer:micrometer-1.5:javaagent")) diff --git a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/OpenTelemetryMeterRegistryAutoConfiguration.java b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/OpenTelemetryMeterRegistryAutoConfiguration.java index a1b392f13b35..aa9a003e7e89 100644 --- a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/OpenTelemetryMeterRegistryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/OpenTelemetryMeterRegistryAutoConfiguration.java @@ -7,7 +7,15 @@ import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.composite.CompositeMeterRegistry; import io.opentelemetry.javaagent.instrumentation.micrometer.v1_5.MicrometerSingletons; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -32,4 +40,32 @@ public class OpenTelemetryMeterRegistryAutoConfiguration { public MeterRegistry otelMeterRegistry() { return MicrometerSingletons.meterRegistry(); } + + @Bean + // static to avoid "is not eligible for getting processed by all BeanPostProcessors" warning + static BeanPostProcessor postProcessCompositeMeterRegistry() { + return new BeanPostProcessor() { + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) { + if (bean instanceof CompositeMeterRegistry) { + CompositeMeterRegistry original = (CompositeMeterRegistry) bean; + List list = new ArrayList<>(original.getRegistries()); + // sort otel registry last since it doesn't support reading metric values + // and the actuator endpoint reads metrics from the first registry + list.sort( + Comparator.comparingInt( + value -> value == MicrometerSingletons.meterRegistry() ? 1 : 0)); + Set registries = new LinkedHashSet<>(list); + return new CompositeMeterRegistry( + original.config().clock(), Collections.singletonList(original)) { + @Override + public Set getRegistries() { + return registries; + } + }; + } + return bean; + } + }; + } } diff --git a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/ActuatorTest.java b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/ActuatorTest.java index 5fb933fed247..9be822a780c6 100644 --- a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/ActuatorTest.java +++ b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/ActuatorTest.java @@ -15,6 +15,8 @@ import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.javaagent.instrumentation.spring.actuator.v2_0.SpringApp.TestBean; +import java.util.ArrayList; +import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.boot.SpringApplication; @@ -57,9 +59,12 @@ void shouldInjectOtelMeterRegistry() { "value")))))); MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - assertThat(meterRegistry).isNotNull().isInstanceOf(CompositeMeterRegistry.class); - assertThat(((CompositeMeterRegistry) meterRegistry).getRegistries()) - .anyMatch(r -> r.getClass().getSimpleName().equals("OpenTelemetryMeterRegistry")) - .anyMatch(r -> r.getClass().getSimpleName().equals("SimpleMeterRegistry")); + assertThat(meterRegistry).isInstanceOf(CompositeMeterRegistry.class); + + Set registries = ((CompositeMeterRegistry) meterRegistry).getRegistries(); + ArrayList list = new ArrayList<>(registries); + + String last = list.get(list.size() - 1).getClass().getSimpleName(); + assertThat(last).isEqualTo("OpenTelemetryMeterRegistry"); } } diff --git a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/SpringApp.java b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/SpringApp.java index a6891de29866..e35ccb4ffce7 100644 --- a/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/SpringApp.java +++ b/instrumentation/spring/spring-boot-actuator-autoconfigure-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/actuator/v2_0/SpringApp.java @@ -10,7 +10,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -@SpringBootApplication +@SpringBootApplication( + excludeName = + "org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusSimpleclientMetricsExportAutoConfiguration") public class SpringApp { @Bean