diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java index e084680152..5599bd3b13 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java @@ -22,6 +22,13 @@ import brave.Tracing; import brave.Tracing.Builder; import brave.TracingCustomizer; import brave.handler.SpanHandler; +import brave.http.HttpClientHandler; +import brave.http.HttpClientRequest; +import brave.http.HttpClientResponse; +import brave.http.HttpServerHandler; +import brave.http.HttpServerRequest; +import brave.http.HttpServerResponse; +import brave.http.HttpTracing; import brave.propagation.B3Propagation; import brave.propagation.CurrentTraceContext; import brave.propagation.CurrentTraceContext.ScopeDecorator; @@ -31,6 +38,8 @@ import brave.propagation.ThreadLocalCurrentTraceContext; import brave.sampler.Sampler; import io.micrometer.tracing.brave.bridge.BraveBaggageManager; import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext; +import io.micrometer.tracing.brave.bridge.BraveHttpClientHandler; +import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler; import io.micrometer.tracing.brave.bridge.BraveTracer; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -107,6 +116,24 @@ public class BraveAutoConfiguration { return Sampler.create(properties.getSampling().getProbability()); } + @Bean + @ConditionalOnMissingBean + public HttpTracing httpTracing(Tracing tracing) { + return HttpTracing.newBuilder(tracing).build(); + } + + @Bean + @ConditionalOnMissingBean + public HttpServerHandler httpServerHandler(HttpTracing httpTracing) { + return HttpServerHandler.create(httpTracing); + } + + @Bean + @ConditionalOnMissingBean + public HttpClientHandler httpClientHandler(HttpTracing httpTracing) { + return HttpClientHandler.create(httpTracing); + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(BraveTracer.class) static class BraveMicrometer { @@ -124,6 +151,20 @@ public class BraveAutoConfiguration { return new BraveBaggageManager(); } + @Bean + @ConditionalOnMissingBean + BraveHttpServerHandler braveHttpServerHandler( + HttpServerHandler httpServerHandler) { + return new BraveHttpServerHandler(httpServerHandler); + } + + @Bean + @ConditionalOnMissingBean + BraveHttpClientHandler braveHttpClientHandler( + HttpClientHandler httpClientHandler) { + return new BraveHttpClientHandler(httpClientHandler); + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java index 5d279b54c2..7f0be23dac 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfiguration.java @@ -18,6 +18,10 @@ package org.springframework.boot.actuate.autoconfigure.tracing; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.handler.DefaultTracingObservationHandler; +import io.micrometer.tracing.handler.HttpClientTracingObservationHandler; +import io.micrometer.tracing.handler.HttpServerTracingObservationHandler; +import io.micrometer.tracing.http.HttpClientHandler; +import io.micrometer.tracing.http.HttpServerHandler; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -25,6 +29,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; /** * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API. @@ -36,11 +42,47 @@ import org.springframework.context.annotation.Bean; @ConditionalOnClass(Tracer.class) public class MicrometerTracingAutoConfiguration { + /** + * {@code @Order} value of {@link #defaultTracingObservationHandler(Tracer)}. + */ + public static final int DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER = Ordered.LOWEST_PRECEDENCE - 1000; + + /** + * {@code @Order} value of + * {@link #httpServerTracingObservationHandler(Tracer, HttpServerHandler)}. + */ + public static final int HTTP_SERVER_TRACING_OBSERVATION_HANDLER_ORDER = 1000; + + /** + * {@code @Order} value of + * {@link #httpClientTracingObservationHandler(Tracer, HttpClientHandler)}. + */ + public static final int HTTP_CLIENT_TRACING_OBSERVATION_HANDLER_ORDER = 2000; + @Bean @ConditionalOnMissingBean @ConditionalOnBean(Tracer.class) + @Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER) public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) { return new DefaultTracingObservationHandler(tracer); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean({ Tracer.class, HttpServerHandler.class }) + @Order(HTTP_SERVER_TRACING_OBSERVATION_HANDLER_ORDER) + public HttpServerTracingObservationHandler httpServerTracingObservationHandler(Tracer tracer, + HttpServerHandler httpServerHandler) { + return new HttpServerTracingObservationHandler(tracer, httpServerHandler); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean({ Tracer.class, HttpClientHandler.class }) + @Order(HTTP_CLIENT_TRACING_OBSERVATION_HANDLER_ORDER) + public HttpClientTracingObservationHandler httpClientTracingObservationHandler(Tracer tracer, + HttpClientHandler httpClientHandler) { + return new HttpClientTracingObservationHandler(tracer, httpClientHandler); + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurations.java index fe95f30916..7893be6740 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurations.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurations.java @@ -17,10 +17,16 @@ package org.springframework.boot.actuate.autoconfigure.tracing; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import io.micrometer.tracing.SamplerFunction; +import io.micrometer.tracing.otel.bridge.DefaultHttpClientAttributesGetter; +import io.micrometer.tracing.otel.bridge.DefaultHttpServerAttributesExtractor; import io.micrometer.tracing.otel.bridge.OtelBaggageManager; import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext; +import io.micrometer.tracing.otel.bridge.OtelHttpClientHandler; +import io.micrometer.tracing.otel.bridge.OtelHttpServerHandler; import io.micrometer.tracing.otel.bridge.OtelTracer; import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher; import io.opentelemetry.api.OpenTelemetry; @@ -146,6 +152,22 @@ class OpenTelemetryConfigurations { return new OtelCurrentTraceContext(); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(OpenTelemetry.class) + OtelHttpClientHandler otelHttpClientHandler(OpenTelemetry openTelemetry) { + return new OtelHttpClientHandler(openTelemetry, null, null, SamplerFunction.deferDecision(), + new DefaultHttpClientAttributesGetter()); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(OpenTelemetry.class) + OtelHttpServerHandler otelHttpServerHandler(OpenTelemetry openTelemetry) { + return new OtelHttpServerHandler(openTelemetry, null, null, Pattern.compile(""), + new DefaultHttpServerAttributesExtractor()); + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java index e0cd2e1470..2578a3490c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java @@ -18,12 +18,22 @@ package org.springframework.boot.actuate.autoconfigure.tracing; import brave.Tracer; import brave.Tracing; +import brave.http.HttpClientHandler; +import brave.http.HttpClientRequest; +import brave.http.HttpClientResponse; +import brave.http.HttpServerHandler; +import brave.http.HttpServerRequest; +import brave.http.HttpServerResponse; +import brave.http.HttpTracing; import brave.propagation.CurrentTraceContext; import brave.propagation.Propagation.Factory; import brave.sampler.Sampler; import io.micrometer.tracing.brave.bridge.BraveBaggageManager; +import io.micrometer.tracing.brave.bridge.BraveHttpClientHandler; +import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler; import io.micrometer.tracing.brave.bridge.BraveTracer; import org.junit.jupiter.api.Test; +import org.mockito.Answers; import org.mockito.Mockito; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -52,6 +62,9 @@ class BraveAutoConfigurationTests { assertThat(context).hasSingleBean(CurrentTraceContext.class); assertThat(context).hasSingleBean(Factory.class); assertThat(context).hasSingleBean(Sampler.class); + assertThat(context).hasSingleBean(HttpTracing.class); + assertThat(context).hasSingleBean(HttpServerHandler.class); + assertThat(context).hasSingleBean(HttpClientHandler.class); }); } @@ -68,6 +81,12 @@ class BraveAutoConfigurationTests { assertThat(context).hasSingleBean(Factory.class); assertThat(context).hasBean("customSampler"); assertThat(context).hasSingleBean(Sampler.class); + assertThat(context).hasBean("customHttpTracing"); + assertThat(context).hasSingleBean(HttpTracing.class); + assertThat(context).hasBean("customHttpServerHandler"); + assertThat(context).hasSingleBean(HttpServerHandler.class); + assertThat(context).hasBean("customHttpClientHandler"); + assertThat(context).hasSingleBean(HttpClientHandler.class); }); } @@ -76,6 +95,8 @@ class BraveAutoConfigurationTests { this.contextRunner.run((context) -> { assertThat(context).hasSingleBean(BraveTracer.class); assertThat(context).hasSingleBean(BraveBaggageManager.class); + assertThat(context).hasSingleBean(BraveHttpServerHandler.class); + assertThat(context).hasSingleBean(BraveHttpClientHandler.class); }); } @@ -86,6 +107,10 @@ class BraveAutoConfigurationTests { assertThat(context).hasSingleBean(BraveTracer.class); assertThat(context).hasBean("customBraveBaggageManager"); assertThat(context).hasSingleBean(BraveBaggageManager.class); + assertThat(context).hasBean("customBraveHttpServerHandler"); + assertThat(context).hasSingleBean(BraveHttpServerHandler.class); + assertThat(context).hasBean("customBraveHttpClientHandler"); + assertThat(context).hasSingleBean(BraveHttpClientHandler.class); }); } @@ -97,6 +122,9 @@ class BraveAutoConfigurationTests { assertThat(context).doesNotHaveBean(CurrentTraceContext.class); assertThat(context).doesNotHaveBean(Factory.class); assertThat(context).doesNotHaveBean(Sampler.class); + assertThat(context).doesNotHaveBean(HttpTracing.class); + assertThat(context).doesNotHaveBean(HttpServerHandler.class); + assertThat(context).doesNotHaveBean(HttpClientHandler.class); }); } @@ -105,6 +133,8 @@ class BraveAutoConfigurationTests { this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer")).run((context) -> { assertThat(context).doesNotHaveBean(BraveTracer.class); assertThat(context).doesNotHaveBean(BraveBaggageManager.class); + assertThat(context).doesNotHaveBean(BraveHttpServerHandler.class); + assertThat(context).doesNotHaveBean(BraveHttpClientHandler.class); }); } @@ -136,6 +166,23 @@ class BraveAutoConfigurationTests { return Mockito.mock(Sampler.class); } + @Bean + HttpTracing customHttpTracing() { + return Mockito.mock(HttpTracing.class); + } + + @Bean + HttpServerHandler customHttpServerHandler() { + HttpTracing httpTracing = Mockito.mock(HttpTracing.class, Answers.RETURNS_MOCKS); + return HttpServerHandler.create(httpTracing); + } + + @Bean + HttpClientHandler customHttpClientHandler() { + HttpTracing httpTracing = Mockito.mock(HttpTracing.class, Answers.RETURNS_MOCKS); + return HttpClientHandler.create(httpTracing); + } + } @Configuration(proxyBeanMethods = false) @@ -151,6 +198,16 @@ class BraveAutoConfigurationTests { return Mockito.mock(BraveBaggageManager.class); } + @Bean + BraveHttpServerHandler customBraveHttpServerHandler() { + return Mockito.mock(BraveHttpServerHandler.class); + } + + @Bean + BraveHttpClientHandler customBraveHttpClientHandler() { + return Mockito.mock(BraveHttpClientHandler.class); + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java index 97e602e6bf..544a4d1f81 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/MicrometerTracingAutoConfigurationTests.java @@ -16,8 +16,15 @@ package org.springframework.boot.actuate.autoconfigure.tracing; +import java.util.List; + import io.micrometer.tracing.Tracer; import io.micrometer.tracing.handler.DefaultTracingObservationHandler; +import io.micrometer.tracing.handler.HttpClientTracingObservationHandler; +import io.micrometer.tracing.handler.HttpServerTracingObservationHandler; +import io.micrometer.tracing.handler.TracingObservationHandler; +import io.micrometer.tracing.http.HttpClientHandler; +import io.micrometer.tracing.http.HttpServerHandler; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -41,8 +48,28 @@ class MicrometerTracingAutoConfigurationTests { @Test void shouldSupplyBeans() { - this.contextRunner.withUserConfiguration(TracerConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class)); + this.contextRunner.withUserConfiguration(TracerConfiguration.class, HttpClientHandlerConfiguration.class, + HttpServerHandlerConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class); + assertThat(context).hasSingleBean(HttpServerTracingObservationHandler.class); + assertThat(context).hasSingleBean(HttpClientTracingObservationHandler.class); + }); + } + + @Test + @SuppressWarnings("rawtypes") + void shouldSupplyBeansInCorrectOrder() { + this.contextRunner.withUserConfiguration(TracerConfiguration.class, HttpClientHandlerConfiguration.class, + HttpServerHandlerConfiguration.class).run((context) -> { + List tracingObservationHandlers = context + .getBeanProvider(TracingObservationHandler.class).orderedStream().toList(); + assertThat(tracingObservationHandlers).hasSize(3); + assertThat(tracingObservationHandlers.get(0)) + .isInstanceOf(HttpServerTracingObservationHandler.class); + assertThat(tracingObservationHandlers.get(1)) + .isInstanceOf(HttpClientTracingObservationHandler.class); + assertThat(tracingObservationHandlers.get(2)).isInstanceOf(DefaultTracingObservationHandler.class); + }); } @Test @@ -50,19 +77,43 @@ class MicrometerTracingAutoConfigurationTests { this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> { assertThat(context).hasBean("customDefaultTracingObservationHandler"); assertThat(context).hasSingleBean(DefaultTracingObservationHandler.class); + assertThat(context).hasBean("customHttpServerTracingObservationHandler"); + assertThat(context).hasSingleBean(HttpServerTracingObservationHandler.class); + assertThat(context).hasBean("customHttpClientTracingObservationHandler"); + assertThat(context).hasSingleBean(HttpClientTracingObservationHandler.class); }); } @Test void shouldNotSupplyBeansIfMicrometerIsMissing() { - this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer")) - .run((context) -> assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class)); + this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer")).run((context) -> { + assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class); + assertThat(context).doesNotHaveBean(HttpServerTracingObservationHandler.class); + assertThat(context).doesNotHaveBean(HttpClientTracingObservationHandler.class); + }); } @Test - void shouldNotSupplyDefaultTracingObservationHandlerIfTracerIsMissing() { + void shouldNotSupplyBeansIfTracerIsMissing() { this.contextRunner - .run((context) -> assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class)); + .withUserConfiguration(HttpServerHandlerConfiguration.class, HttpClientHandlerConfiguration.class) + .run((context) -> { + assertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class); + assertThat(context).doesNotHaveBean(HttpServerTracingObservationHandler.class); + assertThat(context).doesNotHaveBean(HttpClientTracingObservationHandler.class); + }); + } + + @Test + void shouldNotSupplyBeansIfHttpClientHandlerIsMissing() { + this.contextRunner.withUserConfiguration(TracerConfiguration.class, HttpServerHandlerConfiguration.class) + .run((context) -> assertThat(context).doesNotHaveBean(HttpClientTracingObservationHandler.class)); + } + + @Test + void shouldNotSupplyBeansIfHttpServerHandlerIsMissing() { + this.contextRunner.withUserConfiguration(TracerConfiguration.class, HttpClientHandlerConfiguration.class) + .run((context) -> assertThat(context).doesNotHaveBean(HttpServerTracingObservationHandler.class)); } @Configuration(proxyBeanMethods = false) @@ -75,6 +126,26 @@ class MicrometerTracingAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + private static class HttpClientHandlerConfiguration { + + @Bean + HttpClientHandler httpClientHandler() { + return Mockito.mock(HttpClientHandler.class); + } + + } + + @Configuration(proxyBeanMethods = false) + private static class HttpServerHandlerConfiguration { + + @Bean + HttpServerHandler httpServerHandler() { + return Mockito.mock(HttpServerHandler.class); + } + + } + @Configuration(proxyBeanMethods = false) private static class CustomConfiguration { @@ -83,6 +154,16 @@ class MicrometerTracingAutoConfigurationTests { return Mockito.mock(DefaultTracingObservationHandler.class); } + @Bean + HttpServerTracingObservationHandler customHttpServerTracingObservationHandler() { + return Mockito.mock(HttpServerTracingObservationHandler.class); + } + + @Bean + HttpClientTracingObservationHandler customHttpClientTracingObservationHandler() { + return Mockito.mock(HttpClientTracingObservationHandler.class); + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurationsMicrometerConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurationsMicrometerConfigurationTests.java index 6204e462d7..24a18a5902 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurationsMicrometerConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryConfigurationsMicrometerConfigurationTests.java @@ -17,10 +17,14 @@ package org.springframework.boot.actuate.autoconfigure.tracing; import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext; +import io.micrometer.tracing.otel.bridge.OtelHttpClientHandler; +import io.micrometer.tracing.otel.bridge.OtelHttpServerHandler; import io.micrometer.tracing.otel.bridge.OtelTracer; import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Tracer; import org.junit.jupiter.api.Test; +import org.mockito.Answers; import org.mockito.Mockito; import org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryConfigurations.MicrometerConfiguration; @@ -44,28 +48,41 @@ class OpenTelemetryConfigurationsMicrometerConfigurationTests { @Test void shouldSupplyBeans() { - this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> { - assertThat(context).hasSingleBean(OtelTracer.class); - assertThat(context).hasSingleBean(EventPublisher.class); - assertThat(context).hasSingleBean(OtelCurrentTraceContext.class); - }); + this.contextRunner.withUserConfiguration(TracerConfiguration.class, OpenTelemetryConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(OtelTracer.class); + assertThat(context).hasSingleBean(EventPublisher.class); + assertThat(context).hasSingleBean(OtelCurrentTraceContext.class); + assertThat(context).hasSingleBean(OtelHttpClientHandler.class); + assertThat(context).hasSingleBean(OtelHttpServerHandler.class); + }); } @Test void shouldNotSupplyBeansIfMicrometerTracingBridgeOtelIsMissing() { this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer.tracing.otel")) - .withUserConfiguration(TracerConfiguration.class).run((context) -> { + .withUserConfiguration(TracerConfiguration.class, OpenTelemetryConfiguration.class).run((context) -> { assertThat(context).doesNotHaveBean(OtelTracer.class); assertThat(context).doesNotHaveBean(EventPublisher.class); assertThat(context).doesNotHaveBean(OtelCurrentTraceContext.class); + assertThat(context).doesNotHaveBean(OtelHttpClientHandler.class); + assertThat(context).doesNotHaveBean(OtelHttpServerHandler.class); }); } @Test - void shouldNotSupplyOtelTracerIfTracerIsMissing() { + void shouldNotSupplyBeansIfTracerIsMissing() { this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(OtelTracer.class)); } + @Test + void shouldNotSupplyBeansIfOpenTelemetryIsMissing() { + this.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> { + assertThat(context).doesNotHaveBean(OtelHttpClientHandler.class); + assertThat(context).doesNotHaveBean(OtelHttpServerHandler.class); + }); + } + @Test void shouldBackOffOnCustomBeans() { this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> { @@ -75,6 +92,10 @@ class OpenTelemetryConfigurationsMicrometerConfigurationTests { assertThat(context).hasSingleBean(EventPublisher.class); assertThat(context).hasBean("customOtelCurrentTraceContext"); assertThat(context).hasSingleBean(OtelCurrentTraceContext.class); + assertThat(context).hasBean("customOtelHttpClientHandler"); + assertThat(context).hasSingleBean(OtelHttpClientHandler.class); + assertThat(context).hasBean("customOtelHttpServerHandler"); + assertThat(context).hasSingleBean(OtelHttpServerHandler.class); }); } @@ -96,6 +117,16 @@ class OpenTelemetryConfigurationsMicrometerConfigurationTests { return Mockito.mock(OtelCurrentTraceContext.class); } + @Bean + OtelHttpClientHandler customOtelHttpClientHandler() { + return Mockito.mock(OtelHttpClientHandler.class); + } + + @Bean + OtelHttpServerHandler customOtelHttpServerHandler() { + return Mockito.mock(OtelHttpServerHandler.class); + } + } @Configuration(proxyBeanMethods = false) @@ -108,4 +139,14 @@ class OpenTelemetryConfigurationsMicrometerConfigurationTests { } + @Configuration(proxyBeanMethods = false) + private static class OpenTelemetryConfiguration { + + @Bean + OpenTelemetry openTelemetry() { + return Mockito.mock(OpenTelemetry.class, Answers.RETURNS_MOCKS); + } + + } + }