diff --git a/api/src/main/java/io/opentelemetry/api/DefaultOpenTelemetry.java b/api/src/main/java/io/opentelemetry/api/DefaultOpenTelemetry.java index 328c1f41084..b9a7131ba53 100644 --- a/api/src/main/java/io/opentelemetry/api/DefaultOpenTelemetry.java +++ b/api/src/main/java/io/opentelemetry/api/DefaultOpenTelemetry.java @@ -10,7 +10,6 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.DefaultContextPropagators; import io.opentelemetry.spi.OpenTelemetryFactory; import io.opentelemetry.spi.metrics.MeterProviderFactory; import io.opentelemetry.spi.trace.TracerProviderFactory; @@ -124,7 +123,7 @@ public Builder toBuilder() { } protected static class Builder implements OpenTelemetryBuilder { - protected ContextPropagators propagators = DefaultContextPropagators.builder().build(); + protected ContextPropagators propagators = ContextPropagators.noop(); protected TracerProvider tracerProvider; protected MeterProvider meterProvider; diff --git a/api/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java b/api/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java index ded3d3041b1..8a3e8f2d189 100644 --- a/api/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java +++ b/api/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java @@ -27,7 +27,6 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.DefaultContextPropagators; import io.opentelemetry.spi.metrics.MeterProviderFactory; import io.opentelemetry.spi.trace.TracerProviderFactory; import java.io.File; @@ -64,7 +63,6 @@ void testDefault() { .isEqualTo("DefaultMeterProvider"); assertThat(OpenTelemetry.getGlobalMeterProvider()) .isSameAs(OpenTelemetry.getGlobalMeterProvider()); - assertThat(OpenTelemetry.getGlobalPropagators()).isInstanceOf(DefaultContextPropagators.class); assertThat(OpenTelemetry.getGlobalPropagators()).isSameAs(OpenTelemetry.getGlobalPropagators()); } @@ -156,14 +154,14 @@ void testMeterNotFound() { @Test void testGlobalPropagatorsSet() { - ContextPropagators propagators = DefaultContextPropagators.builder().build(); + ContextPropagators propagators = ContextPropagators.noop(); OpenTelemetry.setGlobalPropagators(propagators); assertThat(OpenTelemetry.getGlobalPropagators()).isEqualTo(propagators); } @Test void testPropagatorsSet() { - ContextPropagators propagators = DefaultContextPropagators.builder().build(); + ContextPropagators propagators = ContextPropagators.noop(); OpenTelemetry instance = DefaultOpenTelemetry.builder().build(); instance.setPropagators(propagators); assertThat(instance.getPropagators()).isEqualTo(propagators); diff --git a/context/src/main/java/io/opentelemetry/context/propagation/ContextPropagators.java b/context/src/main/java/io/opentelemetry/context/propagation/ContextPropagators.java index 4a9ed894b16..69b373cc74d 100644 --- a/context/src/main/java/io/opentelemetry/context/propagation/ContextPropagators.java +++ b/context/src/main/java/io/opentelemetry/context/propagation/ContextPropagators.java @@ -5,6 +5,8 @@ package io.opentelemetry.context.propagation; +import static java.util.Objects.requireNonNull; + import javax.annotation.concurrent.ThreadSafe; /** @@ -70,6 +72,32 @@ @ThreadSafe public interface ContextPropagators { + /** + * Returns a {@link ContextPropagators} which can be used to extract and inject context in text + * payloads with the given {@link TextMapPropagator}. Use {@link + * TextMapPropagator#composite(TextMapPropagator...)} to register multiple propagators, which will + * all be executed when extracting or injecting. + * + *
{@code
+   * ContextPropagators propagators = ContextPropagators.create(
+   *   TextMapPropagator.composite(
+   *     HttpTraceContext.getInstance(),
+   *     W3CBaggagePropagator.getInstance(),
+   *     new MyCustomContextPropagator()));
+   * }
+ */ + @SuppressWarnings("deprecation") + static ContextPropagators create(TextMapPropagator textPropagator) { + requireNonNull(textPropagator, "textPropagator"); + return new DefaultContextPropagators(textPropagator); + } + + /** Returns a {@link ContextPropagators} which performs no injection or extraction. */ + @SuppressWarnings("deprecation") + static ContextPropagators noop() { + return DefaultContextPropagators.noop(); + } + /** * Returns a {@link TextMapPropagator} propagator. * diff --git a/context/src/main/java/io/opentelemetry/context/propagation/DefaultContextPropagators.java b/context/src/main/java/io/opentelemetry/context/propagation/DefaultContextPropagators.java index 910fb0d2192..a3da598b668 100644 --- a/context/src/main/java/io/opentelemetry/context/propagation/DefaultContextPropagators.java +++ b/context/src/main/java/io/opentelemetry/context/propagation/DefaultContextPropagators.java @@ -5,13 +5,8 @@ package io.opentelemetry.context.propagation; -import io.opentelemetry.context.Context; import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; -import javax.annotation.Nullable; /** * {@code DefaultContextPropagators} is the default, built-in implementation of {@link @@ -21,8 +16,19 @@ * synchronically upon injection and extraction. * *

The propagation fields retrieved from all registered propagators are de-duplicated. + * + * @deprecated Use {@link ContextPropagators#create(TextMapPropagator)} */ +@Deprecated public final class DefaultContextPropagators implements ContextPropagators { + + private static final ContextPropagators NOOP = + new DefaultContextPropagators(NoopTextMapPropagator.getInstance()); + + static ContextPropagators noop() { + return NOOP; + } + private final TextMapPropagator textMapPropagator; @Override @@ -35,45 +41,32 @@ public TextMapPropagator getTextMapPropagator() { * object. * * @return a {@link DefaultContextPropagators.Builder}. + * @deprecated Use {@link ContextPropagators#create(TextMapPropagator)} */ + @Deprecated public static Builder builder() { return new Builder(); } - private DefaultContextPropagators(TextMapPropagator textMapPropagator) { + DefaultContextPropagators(TextMapPropagator textMapPropagator) { this.textMapPropagator = textMapPropagator; } /** - * {@link Builder} is used to construct a new {@code ContextPropagators} object with the specified - * propagators. + * A builder of {@link DefaultContextPropagators}. * - *

Invocation order of {@code TextMapPropagator#inject()} and {@code - * TextMapPropagator#extract()} for registered trace propagators is undefined. - * - *

This is a example of a {@code ContextPropagators} object being created: - * - *

{@code
-   * ContextPropagators propagators = DefaultContextPropagators.builder()
-   *     .addTextMapPropagator(new HttpTraceContext())
-   *     .addTextMapPropagator(new HttpBaggage())
-   *     .addTextMapPropagator(new MyCustomContextPropagator())
-   *     .build();
-   * }
+ * @deprecated Use {@link ContextPropagators#create(TextMapPropagator)} */ + @Deprecated public static final class Builder { List textPropagators = new ArrayList<>(); /** - * Adds a {@link TextMapPropagator} propagator. + * Add a {@link TextMapPropagator}. * - *

One propagator per concern (traces, correlations, etc) should be added if this format is - * supported. - * - * @param textMapPropagator the propagator to be added. - * @return this. - * @throws NullPointerException if {@code textMapPropagator} is {@code null}. + * @deprecated Use {@link ContextPropagators#create(TextMapPropagator)} */ + @Deprecated public Builder addTextMapPropagator(TextMapPropagator textMapPropagator) { if (textMapPropagator == null) { throw new NullPointerException("textMapPropagator"); @@ -84,73 +77,13 @@ public Builder addTextMapPropagator(TextMapPropagator textMapPropagator) { } /** - * Builds a new {@code ContextPropagators} with the specified propagators. + * Returns a {@link ContextPropagators}. * - * @return the newly created {@code ContextPropagators} instance. + * @deprecated Use {@link ContextPropagators#create(TextMapPropagator)} */ + @Deprecated public ContextPropagators build() { - if (textPropagators.isEmpty()) { - return new DefaultContextPropagators(NoopTextMapPropagator.INSTANCE); - } - - return new DefaultContextPropagators(new MultiTextMapPropagator(textPropagators)); - } - } - - private static final class MultiTextMapPropagator implements TextMapPropagator { - private final TextMapPropagator[] textPropagators; - private final List allFields; - - private MultiTextMapPropagator(List textPropagators) { - this.textPropagators = new TextMapPropagator[textPropagators.size()]; - textPropagators.toArray(this.textPropagators); - this.allFields = Collections.unmodifiableList(getAllFields(this.textPropagators)); - } - - @Override - public List fields() { - return allFields; - } - - private static List getAllFields(TextMapPropagator[] textPropagators) { - Set fields = new LinkedHashSet<>(); - for (int i = 0; i < textPropagators.length; i++) { - fields.addAll(textPropagators[i].fields()); - } - - return new ArrayList<>(fields); - } - - @Override - public void inject(Context context, @Nullable C carrier, Setter setter) { - for (int i = 0; i < textPropagators.length; i++) { - textPropagators[i].inject(context, carrier, setter); - } - } - - @Override - public Context extract(Context context, @Nullable C carrier, Getter getter) { - for (int i = 0; i < textPropagators.length; i++) { - context = textPropagators[i].extract(context, carrier, getter); - } - return context; - } - } - - private static final class NoopTextMapPropagator implements TextMapPropagator { - private static final NoopTextMapPropagator INSTANCE = new NoopTextMapPropagator(); - - @Override - public List fields() { - return Collections.emptyList(); - } - - @Override - public void inject(Context context, @Nullable C carrier, Setter setter) {} - - @Override - public Context extract(Context context, @Nullable C carrier, Getter getter) { - return context; + return ContextPropagators.create(TextMapPropagator.composite(textPropagators)); } } } diff --git a/context/src/main/java/io/opentelemetry/context/propagation/MultiTextMapPropagator.java b/context/src/main/java/io/opentelemetry/context/propagation/MultiTextMapPropagator.java new file mode 100644 index 00000000000..8121d1a3088 --- /dev/null +++ b/context/src/main/java/io/opentelemetry/context/propagation/MultiTextMapPropagator.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.context.propagation; + +import io.opentelemetry.context.Context; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; + +final class MultiTextMapPropagator implements TextMapPropagator { + private final TextMapPropagator[] textPropagators; + private final List allFields; + + MultiTextMapPropagator(List textPropagators) { + this.textPropagators = new TextMapPropagator[textPropagators.size()]; + textPropagators.toArray(this.textPropagators); + this.allFields = Collections.unmodifiableList(getAllFields(this.textPropagators)); + } + + @Override + public List fields() { + return allFields; + } + + private static List getAllFields(TextMapPropagator[] textPropagators) { + Set fields = new LinkedHashSet<>(); + for (int i = 0; i < textPropagators.length; i++) { + fields.addAll(textPropagators[i].fields()); + } + + return new ArrayList<>(fields); + } + + @Override + public void inject(Context context, @Nullable C carrier, Setter setter) { + for (int i = 0; i < textPropagators.length; i++) { + textPropagators[i].inject(context, carrier, setter); + } + } + + @Override + public Context extract(Context context, @Nullable C carrier, Getter getter) { + for (int i = 0; i < textPropagators.length; i++) { + context = textPropagators[i].extract(context, carrier, getter); + } + return context; + } +} diff --git a/context/src/main/java/io/opentelemetry/context/propagation/NoopTextMapPropagator.java b/context/src/main/java/io/opentelemetry/context/propagation/NoopTextMapPropagator.java new file mode 100644 index 00000000000..2b606bf33c8 --- /dev/null +++ b/context/src/main/java/io/opentelemetry/context/propagation/NoopTextMapPropagator.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.context.propagation; + +import io.opentelemetry.context.Context; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +final class NoopTextMapPropagator implements TextMapPropagator { + private static final NoopTextMapPropagator INSTANCE = new NoopTextMapPropagator(); + + static TextMapPropagator getInstance() { + return INSTANCE; + } + + @Override + public List fields() { + return Collections.emptyList(); + } + + @Override + public void inject(Context context, @Nullable C carrier, Setter setter) {} + + @Override + public Context extract(Context context, @Nullable C carrier, Getter getter) { + return context; + } +} diff --git a/context/src/main/java/io/opentelemetry/context/propagation/TextMapPropagator.java b/context/src/main/java/io/opentelemetry/context/propagation/TextMapPropagator.java index dba8bd8f494..5eab8119804 100644 --- a/context/src/main/java/io/opentelemetry/context/propagation/TextMapPropagator.java +++ b/context/src/main/java/io/opentelemetry/context/propagation/TextMapPropagator.java @@ -6,6 +6,8 @@ package io.opentelemetry.context.propagation; import io.opentelemetry.context.Context; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -39,6 +41,39 @@ */ @ThreadSafe public interface TextMapPropagator { + + /** + * Returns a {@link TextMapPropagator} which simply delegates injection and extraction to the + * provided propagators. + * + *

Invocation order of {@code TextMapPropagator#inject()} and {@code + * TextMapPropagator#extract()} for registered trace propagators is undefined. + */ + static TextMapPropagator composite(TextMapPropagator... propagators) { + return composite(Arrays.asList(propagators)); + } + + /** + * Returns a {@link TextMapPropagator} which simply delegates injection and extraction to the + * provided propagators. + * + *

Invocation order of {@code TextMapPropagator#inject()} and {@code + * TextMapPropagator#extract()} for registered trace propagators is undefined. + */ + static TextMapPropagator composite(Iterable propagators) { + List propagatorsList = new ArrayList<>(); + for (TextMapPropagator propagator : propagators) { + propagatorsList.add(propagator); + } + if (propagatorsList.isEmpty()) { + return NoopTextMapPropagator.getInstance(); + } + if (propagatorsList.size() == 1) { + return propagatorsList.get(0); + } + return new MultiTextMapPropagator(propagatorsList); + } + /** * The propagation fields defined. If your carrier is reused, you should delete the fields here * before calling {@link #inject(Context, Object, Setter)} )}. diff --git a/context/src/test/java/io/opentelemetry/context/propagation/DefaultPropagatorsTest.java b/context/src/test/java/io/opentelemetry/context/propagation/DefaultPropagatorsTest.java index 94c8f6ce4d6..f3062a31c1e 100644 --- a/context/src/test/java/io/opentelemetry/context/propagation/DefaultPropagatorsTest.java +++ b/context/src/test/java/io/opentelemetry/context/propagation/DefaultPropagatorsTest.java @@ -21,9 +21,7 @@ class DefaultPropagatorsTest { @Test void addTextMapPropagatorNull() { - assertThrows( - NullPointerException.class, - () -> DefaultContextPropagators.builder().addTextMapPropagator(null)); + assertThrows(NullPointerException.class, () -> ContextPropagators.create(null)); } @Test @@ -31,10 +29,7 @@ void testInject() { CustomTextMapPropagator propagator1 = new CustomTextMapPropagator("prop1"); CustomTextMapPropagator propagator2 = new CustomTextMapPropagator("prop2"); ContextPropagators propagators = - DefaultContextPropagators.builder() - .addTextMapPropagator(propagator1) - .addTextMapPropagator(propagator2) - .build(); + ContextPropagators.create(TextMapPropagator.composite(propagator1, propagator2)); Context context = Context.current(); context = context.with(propagator1.getKey(), "value1"); @@ -52,10 +47,7 @@ void testExtract() { CustomTextMapPropagator propagator2 = new CustomTextMapPropagator("prop2"); CustomTextMapPropagator propagator3 = new CustomTextMapPropagator("prop3"); ContextPropagators propagators = - DefaultContextPropagators.builder() - .addTextMapPropagator(propagator1) - .addTextMapPropagator(propagator2) - .build(); + ContextPropagators.create(TextMapPropagator.composite(propagator1, propagator2)); // Put values for propagators 1 and 2 only. Map map = new HashMap<>(); @@ -76,12 +68,8 @@ public void testDuplicatedFields() { CustomTextMapPropagator propagator3 = new CustomTextMapPropagator("prop1"); CustomTextMapPropagator propagator4 = new CustomTextMapPropagator("prop2"); ContextPropagators propagators = - DefaultContextPropagators.builder() - .addTextMapPropagator(propagator1) - .addTextMapPropagator(propagator2) - .addTextMapPropagator(propagator3) - .addTextMapPropagator(propagator4) - .build(); + ContextPropagators.create( + TextMapPropagator.composite(propagator1, propagator2, propagator3, propagator4)); List fields = propagators.getTextMapPropagator().fields(); assertThat(fields).containsExactly("prop1", "prop2"); @@ -89,7 +77,7 @@ public void testDuplicatedFields() { @Test void noopPropagator() { - ContextPropagators propagators = DefaultContextPropagators.builder().build(); + ContextPropagators propagators = ContextPropagators.noop(); Context context = Context.current(); Map map = new HashMap<>(); diff --git a/integration-tests/tracecontext/src/main/java/io/opentelemetry/Application.java b/integration-tests/tracecontext/src/main/java/io/opentelemetry/Application.java index 3e0ab29e730..4a0898b422a 100644 --- a/integration-tests/tracecontext/src/main/java/io/opentelemetry/Application.java +++ b/integration-tests/tracecontext/src/main/java/io/opentelemetry/Application.java @@ -11,7 +11,6 @@ import io.opentelemetry.api.trace.propagation.HttpTraceContext; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.DefaultContextPropagators; import io.opentelemetry.context.propagation.TextMapPropagator.Getter; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; import java.util.ArrayList; @@ -34,11 +33,7 @@ public class Application { private static final OpenTelemetry openTelemetry; static { - ContextPropagators propagators = - DefaultContextPropagators.builder() - .addTextMapPropagator(HttpTraceContext.getInstance()) - .build(); - OpenTelemetry.setGlobalPropagators(propagators); + OpenTelemetry.setGlobalPropagators(ContextPropagators.create(HttpTraceContext.getInstance())); openTelemetry = OpenTelemetry.get(); } diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java index 57439c2b353..1564bf9bdae 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java @@ -7,7 +7,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.propagation.HttpTraceContext; -import io.opentelemetry.context.propagation.DefaultContextPropagators; +import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.TracerSdkManagement; @@ -55,10 +55,7 @@ public static OpenTelemetryRule create() { OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() - .setPropagators( - DefaultContextPropagators.builder() - .addTextMapPropagator(HttpTraceContext.getInstance()) - .build()) + .setPropagators(ContextPropagators.create(HttpTraceContext.getInstance())) .setTracerProvider(tracerProvider) .build(); diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java index 46c0ecdcc2a..34b6054ee56 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java @@ -9,7 +9,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.propagation.HttpTraceContext; -import io.opentelemetry.context.propagation.DefaultContextPropagators; +import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.testing.assertj.TracesAssert; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; @@ -61,10 +61,7 @@ public static OpenTelemetryExtension create() { OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() - .setPropagators( - DefaultContextPropagators.builder() - .addTextMapPropagator(HttpTraceContext.getInstance()) - .build()) + .setPropagators(ContextPropagators.create(HttpTraceContext.getInstance())) .setTracerProvider(tracerProvider) .build();