diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index 4b4ddd521383..176f180aff97 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -69,6 +69,8 @@ dependencies { optional("io.micrometer:micrometer-registry-statsd") optional("io.micrometer:micrometer-registry-wavefront") optional("io.zipkin.reporter2:zipkin-sender-urlconnection") + optional("io.opentelemetry.instrumentation:opentelemetry-micrometer-1.5") + optional("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") optional("io.opentelemetry:opentelemetry-exporter-zipkin") optional("io.projectreactor.netty:reactor-netty-http") optional("io.r2dbc:r2dbc-pool") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OpenTelemetryMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OpenTelemetryMetricsExportAutoConfiguration.java new file mode 100644 index 000000000000..1c69a8c8ccc0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OpenTelemetryMetricsExportAutoConfiguration.java @@ -0,0 +1,56 @@ +/* + * 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.export.otlp; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.MeterRegistry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.micrometer.v1_5.OpenTelemetryMeterRegistry; +import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +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.context.annotation.Import; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics using {@link OpenTelemetry}. + * + * @author EddĂș MelĂ©ndez + * @since 3.0.0 + */ +@AutoConfiguration( + before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }, + after = MetricsAutoConfiguration.class) +@ConditionalOnBean({Clock.class}) +@ConditionalOnClass(OpenTelemetryMeterRegistry.class) +@ConditionalOnEnabledMetricsExport("otlp") +@Import(org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class) +public class OpenTelemetryMetricsExportAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public MeterRegistry openTelemetryMeterRegistry(OpenTelemetry openTelemetry, Clock clock) { + return OpenTelemetryMeterRegistry.builder(openTelemetry).setClock(clock).build(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryAutoConfiguration.java new file mode 100644 index 000000000000..64bb04d0bb29 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryAutoConfiguration.java @@ -0,0 +1,147 @@ +/* + * 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.opentelemetry; + +import io.micrometer.tracing.exporter.SpanExportingPredicate; +import io.micrometer.tracing.exporter.SpanFilter; +import io.micrometer.tracing.exporter.SpanReporter; +import io.micrometer.tracing.otel.bridge.CompositeSpanExporter; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.actuate.autoconfigure.tracing.TracingProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@ConditionalOnClass(AutoConfiguredOpenTelemetrySdk.class) +@EnableConfigurationProperties(TracingProperties.class) +public class OpenTelemetryAutoConfiguration { + + /** + * Default value for application name if {@code spring.application.name} is not set. + */ + private static final String DEFAULT_APPLICATION_NAME = "application"; + + private final TracingProperties tracingProperties; + + OpenTelemetryAutoConfiguration(TracingProperties tracingProperties) { + this.tracingProperties = tracingProperties; + } + + + @Bean + @ConditionalOnMissingBean + public OpenTelemetry openTelemetry( + Environment environment, + Optional sampler, + Optional contextPropagators, + ObjectProvider textMapPropagators, + ObjectProvider spanProcessors, + ObjectProvider spanExporters, + ObjectProvider spanExportingPredicates, + ObjectProvider spanReporters, + ObjectProvider spanFilters) { + AutoConfiguredOpenTelemetrySdkBuilder builder = AutoConfiguredOpenTelemetrySdk.builder(); + builder.addPropertiesSupplier(() -> readPropertiesStartingWith("otel", environment)); + + // user can use otel config, which will be used with the lowest priority: + // https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure + + builder.addResourceCustomizer((resource, configProperties) -> customizeResource(environment, resource)); + + builder.addPropagatorCustomizer( + (otelPropagator, configProperties) -> + contextPropagators.map(ContextPropagators::getTextMapPropagator) + .or(() -> textMapPropagator(textMapPropagators)) + .orElse(otelPropagator)); + + builder.addSamplerCustomizer( + (otelSampler, configProperties) -> sampler + .or(this::configSampler) + .orElse(otelSampler)); + + builder.addTracerProviderCustomizer((sdkTracerProviderBuilder, configProperties) -> { + spanProcessors.orderedStream().forEach(sdkTracerProviderBuilder::addSpanProcessor); + + return sdkTracerProviderBuilder; + }); + + builder.addSpanExporterCustomizer((spanExporter, configProperties) -> { + ArrayList exporters = spanExporters.orderedStream().collect(Collectors.toCollection(ArrayList::new)); + exporters.add(spanExporter); + List predicates = spanExportingPredicates.orderedStream().toList(); + List reporters = spanReporters.orderedStream().toList(); + List filters = spanFilters.orderedStream().toList(); + + return exporters.size() == 1 && predicates.isEmpty() && reporters.isEmpty() && filters.isEmpty() ? + spanExporter : + new CompositeSpanExporter(exporters, predicates, reporters, filters); + + }); + + return builder.build().getOpenTelemetrySdk(); + } + + private Map readPropertiesStartingWith(String prefix, Environment environment) { + //todo not possible unless you use some workarounds - see https://stackoverflow.com/questions/23506471/access-all-environment-properties-as-a-map-or-properties-object + return Collections.emptyMap(); + } + + private static Resource customizeResource(Environment environment, Resource resource) { + if (resource.getAttribute(ResourceAttributes.SERVICE_NAME) == null) { + //todo is there already a default service name - and if not, why should we set it to "application"? + String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME); + return resource.toBuilder().put(ResourceAttributes.SERVICE_NAME, applicationName).build(); + } + + return resource; + } + + private static Optional textMapPropagator( + ObjectProvider textMapPropagators) { + List propagators = textMapPropagators.orderedStream().toList(); + + return propagators.isEmpty() ? Optional.empty() : Optional.of(TextMapPropagator.composite(propagators)); + } + + private Optional configSampler() { + float probability = this.tracingProperties.getSampling().getProbability(); + + return probability != TracingProperties.Sampling.DEFAULT_PROBABILITY ? + Optional.of(Sampler.parentBased(Sampler.traceIdRatioBased(probability))) : + Optional.empty(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryAutoConfiguration.java index b2000c496d22..afb0a3092243 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/OpenTelemetryAutoConfiguration.java @@ -16,14 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.tracing; -import java.util.Collections; -import java.util.List; - import io.micrometer.tracing.SpanCustomizer; -import io.micrometer.tracing.exporter.SpanExportingPredicate; -import io.micrometer.tracing.exporter.SpanFilter; -import io.micrometer.tracing.exporter.SpanReporter; -import io.micrometer.tracing.otel.bridge.CompositeSpanExporter; import io.micrometer.tracing.otel.bridge.EventListener; import io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper; import io.micrometer.tracing.otel.bridge.OtelBaggageManager; @@ -37,34 +30,25 @@ import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.ContextStorage; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.extension.trace.propagation.B3Propagator; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; -import io.opentelemetry.sdk.trace.SpanProcessor; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; - -import org.springframework.beans.factory.ObjectProvider; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import org.springframework.boot.SpringBootVersion; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; +import org.springframework.context.annotation.Import; + +import java.util.Collections; +import java.util.List; /** * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry. @@ -74,187 +58,135 @@ */ @AutoConfiguration(before = MicrometerTracingAutoConfiguration.class) @ConditionalOnEnabledTracing -@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class }) -@EnableConfigurationProperties(TracingProperties.class) +@ConditionalOnClass({ OtelTracer.class, AutoConfiguredOpenTelemetrySdk.class }) +@Import(org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration.class) public class OpenTelemetryAutoConfiguration { - /** - * Default value for application name if {@code spring.application.name} is not set. - */ - private static final String DEFAULT_APPLICATION_NAME = "application"; - - private final TracingProperties tracingProperties; - - OpenTelemetryAutoConfiguration(TracingProperties tracingProperties) { - this.tracingProperties = tracingProperties; - } - - @Bean - @ConditionalOnMissingBean - OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) { - return OpenTelemetrySdk.builder() - .setTracerProvider(sdkTracerProvider) - .setPropagators(contextPropagators) - .build(); - } - - @Bean - @ConditionalOnMissingBean - SdkTracerProvider otelSdkTracerProvider(Environment environment, ObjectProvider spanProcessors, - Sampler sampler) { - String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME); - SdkTracerProviderBuilder builder = SdkTracerProvider.builder() - .setSampler(sampler) - .setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))); - spanProcessors.orderedStream().forEach(builder::addSpanProcessor); - return builder.build(); - } - - @Bean - @ConditionalOnMissingBean - ContextPropagators otelContextPropagators(ObjectProvider textMapPropagators) { - return ContextPropagators.create(TextMapPropagator.composite(textMapPropagators.orderedStream().toList())); - } - - @Bean - @ConditionalOnMissingBean - Sampler otelSampler() { - Sampler rootSampler = Sampler.traceIdRatioBased(this.tracingProperties.getSampling().getProbability()); - return Sampler.parentBased(rootSampler); - } - - @Bean - SpanProcessor otelSpanProcessor(ObjectProvider spanExporters, - ObjectProvider spanExportingPredicates, ObjectProvider spanReporters, - ObjectProvider spanFilters) { - return BatchSpanProcessor - .builder(new CompositeSpanExporter(spanExporters.orderedStream().toList(), - spanExportingPredicates.orderedStream().toList(), spanReporters.orderedStream().toList(), - spanFilters.orderedStream().toList())) - .build(); - } - - @Bean - @ConditionalOnMissingBean - Tracer otelTracer(OpenTelemetry openTelemetry) { - return openTelemetry.getTracer("org.springframework.boot", SpringBootVersion.getVersion()); - } - - @Bean - @ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class) - OtelTracer micrometerOtelTracer(Tracer tracer, EventPublisher eventPublisher, - OtelCurrentTraceContext otelCurrentTraceContext) { - return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher, - new OtelBaggageManager(otelCurrentTraceContext, this.tracingProperties.getBaggage().getRemoteFields(), - Collections.emptyList())); - } - - @Bean - @ConditionalOnMissingBean - OtelPropagator otelPropagator(ContextPropagators contextPropagators, Tracer tracer) { - return new OtelPropagator(contextPropagators, tracer); - } - - @Bean - @ConditionalOnMissingBean - EventPublisher otelTracerEventPublisher(List eventListeners) { - return new OTelEventPublisher(eventListeners); - } - - @Bean - @ConditionalOnMissingBean - OtelCurrentTraceContext otelCurrentTraceContext(EventPublisher publisher) { - ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher)); - return new OtelCurrentTraceContext(); - } - - @Bean - @ConditionalOnMissingBean - Slf4JEventListener otelSlf4JEventListener() { - return new Slf4JEventListener(); - } - - @Bean - @ConditionalOnMissingBean(SpanCustomizer.class) - OtelSpanCustomizer otelSpanCustomizer() { - return new OtelSpanCustomizer(); - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", matchIfMissing = true) - static class BaggageConfiguration { - - private final TracingProperties tracingProperties; - - BaggageConfiguration(TracingProperties tracingProperties) { - this.tracingProperties = tracingProperties; - } - - @Bean - @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C", - matchIfMissing = true) - TextMapPropagator w3cTextMapPropagatorWithBaggage(OtelCurrentTraceContext otelCurrentTraceContext) { - List remoteFields = this.tracingProperties.getBaggage().getRemoteFields(); - return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), new BaggageTextMapPropagator(remoteFields, - new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList()))); - } - - @Bean - @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3") - TextMapPropagator b3BaggageTextMapPropagator(OtelCurrentTraceContext otelCurrentTraceContext) { - List remoteFields = this.tracingProperties.getBaggage().getRemoteFields(); - return TextMapPropagator.composite(B3Propagator.injectingSingleHeader(), - new BaggageTextMapPropagator(remoteFields, - new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList()))); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "management.tracing.baggage.correlation", name = "enabled", - matchIfMissing = true) - Slf4JBaggageEventListener otelSlf4JBaggageEventListener() { - return new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields()); - } - - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", havingValue = "false") - static class NoBaggageConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3") - B3Propagator b3TextMapPropagator() { - return B3Propagator.injectingSingleHeader(); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C", - matchIfMissing = true) - W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() { - return W3CTraceContextPropagator.getInstance(); - } - - } - - static class OTelEventPublisher implements EventPublisher { - - private final List listeners; - - OTelEventPublisher(List listeners) { - this.listeners = listeners; - } - - @Override - public void publishEvent(Object event) { - for (EventListener listener : this.listeners) { - listener.onEvent(event); - } - } - - } + private final TracingProperties tracingProperties; + + OpenTelemetryAutoConfiguration(TracingProperties tracingProperties) { + this.tracingProperties = tracingProperties; + } + + @Bean + @ConditionalOnMissingBean + Tracer otelTracer(OpenTelemetry openTelemetry) { + return openTelemetry.getTracer("org.springframework.boot", SpringBootVersion.getVersion()); + } + + @Bean + @ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class) + OtelTracer micrometerOtelTracer(Tracer tracer, EventPublisher eventPublisher, + OtelCurrentTraceContext otelCurrentTraceContext) { + return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher, + new OtelBaggageManager(otelCurrentTraceContext, this.tracingProperties.getBaggage().getRemoteFields(), + Collections.emptyList())); + } + + @Bean + @ConditionalOnMissingBean + OtelPropagator otelPropagator(ContextPropagators contextPropagators, Tracer tracer) { + return new OtelPropagator(contextPropagators, tracer); + } + + @Bean + @ConditionalOnMissingBean + EventPublisher otelTracerEventPublisher(List eventListeners) { + return new OTelEventPublisher(eventListeners); + } + + @Bean + @ConditionalOnMissingBean + OtelCurrentTraceContext otelCurrentTraceContext(EventPublisher publisher) { + ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher)); + return new OtelCurrentTraceContext(); + } + + @Bean + @ConditionalOnMissingBean + Slf4JEventListener otelSlf4JEventListener() { + return new Slf4JEventListener(); + } + + @Bean + @ConditionalOnMissingBean(SpanCustomizer.class) + OtelSpanCustomizer otelSpanCustomizer() { + return new OtelSpanCustomizer(); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", matchIfMissing = true) + static class BaggageConfiguration { + + private final TracingProperties tracingProperties; + + BaggageConfiguration(TracingProperties tracingProperties) { + this.tracingProperties = tracingProperties; + } + + @Bean + @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C") + TextMapPropagator w3cTextMapPropagatorWithBaggage(OtelCurrentTraceContext otelCurrentTraceContext) { + List remoteFields = this.tracingProperties.getBaggage().getRemoteFields(); + return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), + W3CBaggagePropagator.getInstance(), new BaggageTextMapPropagator(remoteFields, + new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList()))); + } + + @Bean + @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3") + TextMapPropagator b3BaggageTextMapPropagator(OtelCurrentTraceContext otelCurrentTraceContext) { + List remoteFields = this.tracingProperties.getBaggage().getRemoteFields(); + return TextMapPropagator.composite(B3Propagator.injectingSingleHeader(), + new BaggageTextMapPropagator(remoteFields, + new OtelBaggageManager(otelCurrentTraceContext, remoteFields, Collections.emptyList()))); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "management.tracing.baggage.correlation", name = "enabled", + matchIfMissing = true) + Slf4JBaggageEventListener otelSlf4JBaggageEventListener() { + return new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields()); + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", havingValue = "false") + static class NoBaggageConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3") + B3Propagator b3TextMapPropagator() { + return B3Propagator.injectingSingleHeader(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C") + W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() { + return W3CTraceContextPropagator.getInstance(); + } + + } + + static class OTelEventPublisher implements EventPublisher { + + private final List listeners; + + OTelEventPublisher(List listeners) { + this.listeners = listeners; + } + + @Override + public void publishEvent(Object event) { + for (EventListener listener : this.listeners) { + listener.onEvent(event); + } + } + + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java index 88fedf97334b..040c67aa3061 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java @@ -16,11 +16,11 @@ package org.springframework.boot.actuate.autoconfigure.tracing; +import org.springframework.boot.context.properties.ConfigurationProperties; + import java.util.ArrayList; import java.util.List; -import org.springframework.boot.context.properties.ConfigurationProperties; - /** * Configuration properties for tracing. * @@ -72,10 +72,12 @@ public Propagation getPropagation() { public static class Sampling { + public static final float DEFAULT_PROBABILITY = 0.10f; + /** * Probability in the range from 0.0 to 1.0 that a trace will be sampled. */ - private float probability = 0.10f; + private float probability = DEFAULT_PROBABILITY; public float getProbability() { return this.probability; @@ -165,10 +167,12 @@ public void setFields(List fields) { public static class Propagation { + public static final PropagationType DEFAULT_TYPE = PropagationType.W3C; + /** * Tracing context propagation type. */ - private PropagationType type = PropagationType.W3C; + private PropagationType type = DEFAULT_TYPE; public PropagationType getType() { return this.type; diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 308020026d96..fa717b8c0b0e 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1025,10 +1025,10 @@ bom { ] } } - library("OpenTelemetry", "1.19.0") { + library("OpenTelemetry", "1.23.1-alpha") { group("io.opentelemetry") { imports = [ - "opentelemetry-bom" + "opentelemetry-bom-alpha" ] } }