add baggage propagator to default propagators
MODIFY
README.md
README.md
@@ -148,16 +148,12 @@ attributes to stdout. It's mainly used for testing and debugging.
#### Propagator
-The propagator controls which distributed tracing header format is used.
+The propagators determine which distributed tracing header formats are used, and which baggage propagation header formats are used.
-If set to a comma-separated list of the values, the multi-propagator is used. The multi-propagator attempts
-to extract the context from incoming requests using each of the configured propagator formats (in order),
-stopping after the first successful context extraction. The multi-propagator injects the context into
-outgoing requests using all the configured propagator formats.
| System property | Environment variable | Description |
|------------------|----------------------|-----------------------------------------------------------------------------------------------------------------|
-| otel.propagators | OTEL_PROPAGATORS | Default is `tracecontext` (W3C). Other supported values are `b3`, `b3multi`, `jaeger`, `ottracer`, and `xray`. |
+| otel.propagators | OTEL_PROPAGATORS | The propagators to be used. Use a comma-separated list for multiple propagators. Supported propagators are `tracecontext`, `baggage`, `b3`, `b3multi`, `jaeger`, `ottracer`, and `xray`. Default is `tracecontext,baggage` (W3C). |
#### OpenTelemetry Resource

MODIFY
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/PropagatorsInitializer.java
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/PropagatorsInitializer.java
@@ -7,17 +7,21 @@ package io.opentelemetry.javaagent.tooling;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
+import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.propagation.HttpTraceContext;
+import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.DefaultContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.extension.trace.propagation.JaegerPropagator;
import io.opentelemetry.extension.trace.propagation.OtTracerPropagator;
-import io.opentelemetry.extension.trace.propagation.TraceMultiPropagator;
import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,58 +29,156 @@ public class PropagatorsInitializer {
private static final Logger log = LoggerFactory.getLogger(PropagatorsInitializer.class);
- private static final String TRACE_CONTEXT = "tracecontext";
- private static final String B3 = "b3";
- private static final String B3_MULTI = "b3multi";
- private static final String JAEGER = "jaeger";
- private static final String OT_TRACER = "ottracer";
- private static final String XRAY = "xray";
-
- private static final Map<String, TextMapPropagator> TEXTMAP_PROPAGATORS =
- ImmutableMap.<String, TextMapPropagator>builder()
- .put(TRACE_CONTEXT, HttpTraceContext.getInstance())
- .put(B3, B3Propagator.getInstance())
- .put(B3_MULTI, B3Propagator.builder().injectMultipleHeaders().build())
- .put(JAEGER, JaegerPropagator.getInstance())
- .put(OT_TRACER, OtTracerPropagator.getInstance())
- .put(XRAY, AwsXRayPropagator.getInstance())
- .build();
-
- /** Initialize OpenTelemetry global Propagators with propagator list, if any. */
- public static void initializePropagators(List<String> propagators) {
+ private static final Map<String, Propagator> TEXTMAP_PROPAGATORS;
+
+ static {
+ ImmutableMap.Builder<String, Propagator> propagators = ImmutableMap.builder();
+ for (Propagator propagator : Propagator.values()) {
+ propagators.put(propagator.id(), propagator);
+ }
+ TEXTMAP_PROPAGATORS = propagators.build();
+ }
+
+ /**
+ * Initialize OpenTelemetry global Propagators with propagator list, if any.
+ *
+ * <p>Because TraceMultiPropagator returns first successful extracted Context and stops further
+ * extraction, these rules are applied:
+ *
+ * <ul>
+ * <li>W3CBaggagePropagator and JaegerPropagator are added outside of the multi-propagator so
+ * that they will always runs and extract baggage (note: JaegerPropagator extracts both
+ * baggage and context).
+ * <li>W3CBaggagePropagator comes after JaegerPropagator, as it can have more complex/complete
+ * values that Jaeger baggage lacks, e.g. metadata. Baggage extraction can enrich the
+ * previous one.
+ * </ul>
+ */
+ public static void initializePropagators(List<String> propagatorIds) {
/* Only override the default propagators *if* the user specified any. */
- if (propagators.size() == 0) {
+ if (propagatorIds.size() == 0) {
// TODO this is probably temporary until default propagators are supplied by SDK
// https://github.com/open-telemetry/opentelemetry-java/issues/1742
OpenTelemetry.setGlobalPropagators(
DefaultContextPropagators.builder()
.addTextMapPropagator(HttpTraceContext.getInstance())
+ .addTextMapPropagator(W3CBaggagePropagator.getInstance())
.build());
return;
}
DefaultContextPropagators.Builder propagatorsBuilder = DefaultContextPropagators.builder();
- List<TextMapPropagator> textPropagators = new ArrayList<>(propagators.size());
- for (String propagatorId : propagators) {
- TextMapPropagator textPropagator = TEXTMAP_PROPAGATORS.get(propagatorId.trim().toLowerCase());
- if (textPropagator != null) {
- textPropagators.add(textPropagator);
- log.info("Added " + textPropagator + " propagator");
+ List<Propagator> propagators = new ArrayList<>(propagatorIds.size());
+
+ for (String propagatorId : propagatorIds) {
+ Propagator propagator = TEXTMAP_PROPAGATORS.get(propagatorId);
+ if (propagator != null) {
+ propagators.add(propagator);
+ log.info("Added " + propagatorId + " propagator");
} else {
log.warn("No matching propagator for " + propagatorId);
}
}
- if (textPropagators.size() > 1) {
- TraceMultiPropagator.Builder traceMultiPropagatorBuilder = TraceMultiPropagator.builder();
- for (TextMapPropagator textPropagator : textPropagators) {
- traceMultiPropagatorBuilder.addPropagator(textPropagator);
- }
- propagatorsBuilder.addTextMapPropagator(traceMultiPropagatorBuilder.build());
- } else if (textPropagators.size() == 1) {
- propagatorsBuilder.addTextMapPropagator(textPropagators.get(0));
+ if (propagators.size() > 1) {
+ propagatorsBuilder.addTextMapPropagator(new MultiPropagator(propagators));
+ } else if (propagators.size() == 1) {
+ propagatorsBuilder.addTextMapPropagator(propagators.get(0));
}
// Register it in the global propagators:
OpenTelemetry.setGlobalPropagators(propagatorsBuilder.build());
}
+
+ static class MultiPropagator implements TextMapPropagator {
+ private final List<Propagator> propagators;
+ private final List<String> fields;
+
+ private MultiPropagator(List<Propagator> propagators) {
+ this.propagators = propagators;
+
+ Set<String> fields = new LinkedHashSet<>();
+ for (Propagator propagator : propagators) {
+ fields.addAll(propagator.delegate.fields());
+ }
+ this.fields = new ArrayList<>(fields);
+ }
+
+ @Override
+ public List<String> fields() {
+ return fields;
+ }
+
+ @Override
+ public <C> void inject(Context context, C carrier, Setter<C> setter) {
+ for (Propagator propagator : propagators) {
+ propagator.inject(context, carrier, setter);
+ }
+ }
+
+ @Override
+ public <C> Context extract(Context context, C carrier, Getter<C> getter) {
+ boolean spanContextExtracted = false;
+ for (int i = propagators.size() - 1; i >= 0; i--) {
+ Propagator propagator = propagators.get(i);
+ if (!propagator.alwaysRun() && spanContextExtracted) {
+ continue;
+ }
+ context = propagator.extract(context, carrier, getter);
+ if (!spanContextExtracted) {
+ spanContextExtracted = isSpanContextExtracted(context);
+ }
+ }
+ return context;
+ }
+
+ private static boolean isSpanContextExtracted(Context context) {
+ return Span.fromContextOrNull(context) != null;
+ }
+ }
+
+ enum Propagator implements TextMapPropagator {
+ // propagators that should always run:
+ BAGGAGE("baggage", W3CBaggagePropagator.getInstance(), true),
+ JAEGER("jaeger", JaegerPropagator.getInstance(), true),
+
+ // propagators that can be skipped if context was already extracted:
+ B3("b3", B3Propagator.getInstance(), false),
+ B3_MULTI("b3multi", B3Propagator.builder().injectMultipleHeaders().build(), false),
+ OT_TRACER("ottracer", OtTracerPropagator.getInstance(), false),
+ TRACE_CONTEXT("tracecontext", HttpTraceContext.getInstance(), false),
+ XRAY("xray", AwsXRayPropagator.getInstance(), false);
+
+ private final String id;
+ private final TextMapPropagator delegate;
+ private final boolean alwaysRun;
+
+ Propagator(String id, TextMapPropagator delegate, boolean alwaysRun) {
+ this.id = id;
+ this.delegate = delegate;
+ this.alwaysRun = alwaysRun;
+ }
+
+ String id() {
+ return id;
+ }
+
+ boolean alwaysRun() {
+ return alwaysRun;
+ }
+
+ @Override
+ public List<String> fields() {
+ return delegate.fields();
+ }
+
+ @Override
+ public <C> void inject(Context context, C carrier, Setter<C> setter) {
+ delegate.inject(context, carrier, setter);
+ }
+
+ @Override
+ public <C> Context extract(Context context, C carrier, Getter<C> getter) {
+ return delegate.extract(context, carrier, getter);
+ }
+ }
}

add baggage propagator to default propagators (#1545)