mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Merge pull request #51656 from o-shevchenko
Closes gh-51656 * gh-51656: Add baggage tag fields to spans with OpenTelemetry
This commit is contained in:
+3
@@ -236,6 +236,9 @@ Baggage is propagated wherever Micrometer Observation instruments the transport,
|
||||
If you want to propagate the baggage to the MDC, use the configprop:management.tracing.baggage.correlation.fields[] configuration property.
|
||||
For the example above, setting this property to `baggage1` results in an MDC entry named `baggage1`.
|
||||
|
||||
If you want baggage values to be added as tags on spans, use the configprop:management.tracing.baggage.tag-fields[] configuration property.
|
||||
For the example above, setting this property to `baggage1` results in spans that are tagged with `baggage1=value1`.
|
||||
|
||||
|
||||
|
||||
[[actuator.micrometer-tracing.tests]]
|
||||
|
||||
+25
@@ -18,18 +18,22 @@ package org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.tracing.otel.bridge.BaggageTaggingSpanProcessor;
|
||||
import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
|
||||
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
|
||||
import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
|
||||
import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.OnPropertyListCondition;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;
|
||||
import org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
@@ -37,6 +41,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
* {@link OpenTelemetryTracingAutoConfiguration}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Oleksandr Shevchenko
|
||||
*/
|
||||
class OpenTelemetryPropagationConfigurations {
|
||||
|
||||
@@ -87,6 +92,26 @@ class OpenTelemetryPropagationConfigurations {
|
||||
return new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(OnBaggageTagFieldsCondition.class)
|
||||
BaggageTaggingSpanProcessor otelBaggageTaggingSpanProcessor() {
|
||||
return new BaggageTaggingSpanProcessor(this.tracingProperties.getBaggage().getTagFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition that matches when {@code management.tracing.baggage.tag-fields} has
|
||||
* at least one entry.
|
||||
*/
|
||||
static class OnBaggageTagFieldsCondition extends OnPropertyListCondition {
|
||||
|
||||
OnBaggageTagFieldsCondition() {
|
||||
super("management.tracing.baggage.tag-fields",
|
||||
() -> ConditionMessage.forCondition("Baggage tag fields"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+63
@@ -30,6 +30,7 @@ import io.micrometer.tracing.SpanCustomizer;
|
||||
import io.micrometer.tracing.Tracer.SpanInScope;
|
||||
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
|
||||
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
|
||||
import io.micrometer.tracing.otel.bridge.BaggageTaggingSpanProcessor;
|
||||
import io.micrometer.tracing.otel.bridge.EventListener;
|
||||
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
|
||||
import io.micrometer.tracing.otel.bridge.OtelPropagator;
|
||||
@@ -40,18 +41,21 @@ import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
|
||||
import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
|
||||
import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
|
||||
import io.micrometer.tracing.propagation.Propagator;
|
||||
import io.opentelemetry.api.baggage.Baggage;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.MeterProvider;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.context.propagation.ContextPropagators;
|
||||
import io.opentelemetry.context.propagation.TextMapPropagator;
|
||||
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
|
||||
import io.opentelemetry.extension.trace.propagation.B3Propagator;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.opentelemetry.sdk.trace.ReadableSpan;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProvider;
|
||||
import io.opentelemetry.sdk.trace.SpanLimits;
|
||||
import io.opentelemetry.sdk.trace.SpanProcessor;
|
||||
@@ -91,6 +95,7 @@ import static org.mockito.Mockito.mock;
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Yanming Zhou
|
||||
* @author Oleksandr Shevchenko
|
||||
*/
|
||||
class OpenTelemetryTracingAutoConfigurationTests {
|
||||
|
||||
@@ -390,6 +395,54 @@ class OpenTelemetryTracingAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupplyBaggageTaggingSpanProcessorWhenTagFieldsAreConfigured() {
|
||||
this.contextRunner.withPropertyValues("management.tracing.baggage.tag-fields=t1,t2").run((context) -> {
|
||||
assertThat(context).hasSingleBean(BaggageTaggingSpanProcessor.class);
|
||||
SpanProcessors spanProcessors = context.getBean(SpanProcessors.class);
|
||||
assertThat(spanProcessors).anyMatch(BaggageTaggingSpanProcessor.class::isInstance);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSupplyBaggageTaggingSpanProcessorWhenTagFieldsAreNotConfigured() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(BaggageTaggingSpanProcessor.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSupplyBaggageTaggingSpanProcessorWhenBaggageDisabled() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.tracing.baggage.enabled=false", "management.tracing.baggage.tag-fields=t1")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(BaggageTaggingSpanProcessor.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBackOffOnCustomBaggageTaggingSpanProcessor() {
|
||||
this.contextRunner.withPropertyValues("management.tracing.baggage.tag-fields=t1")
|
||||
.withUserConfiguration(CustomBaggageTaggingSpanProcessorConfiguration.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasBean("customBaggageTaggingSpanProcessor");
|
||||
assertThat(context).hasSingleBean(BaggageTaggingSpanProcessor.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void baggageTaggingSpanProcessorShouldTagSpansWithBaggageFromParentContext() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.tracing.baggage.tag-fields=t1",
|
||||
"management.tracing.sampling.probability=1.0")
|
||||
.run((context) -> {
|
||||
Tracer tracer = context.getBean(Tracer.class);
|
||||
try (Scope scope = Baggage.builder().put("t1", "v1").put("other", "v2").build().makeCurrent()) {
|
||||
Span span = tracer.spanBuilder("test").startSpan();
|
||||
span.end();
|
||||
assertThat(span).isInstanceOf(ReadableSpan.class);
|
||||
assertThat(((ReadableSpan) span).getAttribute(AttributeKey.stringKey("t1"))).isEqualTo("v1");
|
||||
assertThat(((ReadableSpan) span).getAttribute(AttributeKey.stringKey("other"))).isNull();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void spanLimitsShouldBeConfiguredWithCustomProperties() {
|
||||
this.contextRunner
|
||||
@@ -608,6 +661,16 @@ class OpenTelemetryTracingAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class CustomBaggageTaggingSpanProcessorConfiguration {
|
||||
|
||||
@Bean
|
||||
BaggageTaggingSpanProcessor customBaggageTaggingSpanProcessor() {
|
||||
return new BaggageTaggingSpanProcessor(List.of("custom"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
private static final class AdditionalSpanProcessorConfiguration {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user