diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetter.java new file mode 100644 index 00000000000..eba1e770c55 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetter.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.propagation; + +import io.opentelemetry.context.propagation.TextMapGetter; +import java.util.Collections; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * A {@link TextMapGetter} that extracts context from a map carrier, intended for use with + * environment variables. + * + *

Standard environment variable names are uppercase (e.g., {@code TRACEPARENT}, {@code + * TRACESTATE}, {@code BAGGAGE}). This getter translates keys to uppercase and replaces characters + * not allowed in environment variables (e.g., {@code .} and {@code -}) with underscores before + * looking them up in the carrier. + + * @see Environment + * Variable Format Restrictions + */ +@Immutable +public final class EnvironmentGetter implements TextMapGetter> { + + private static final EnvironmentGetter INSTANCE = new EnvironmentGetter(); + + private EnvironmentGetter() {} + + /** Returns the singleton instance of {@link EnvironmentGetter}. */ + public static EnvironmentGetter getInstance() { + return INSTANCE; + } + + @Override + public Iterable keys(Map carrier) { + if (carrier == null) { + return Collections.emptyList(); + } + return carrier.keySet(); + } + + @Nullable + @Override + public String get(@Nullable Map carrier, String key) { + if (carrier == null || key == null) { + return null; + } + // Spec recommends using uppercase and underscores for environment variable + // names for maximum + // cross-platform compatibility. + String sanitizedKey = key.replace('.', '_').replace('-', '_').toUpperCase(Locale.ROOT); + return carrier.get(sanitizedKey); + } + + @Override + public String toString() { + return "EnvironmentGetter"; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentSetter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentSetter.java new file mode 100644 index 00000000000..656b9638b1d --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentSetter.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.propagation; + +import io.opentelemetry.context.propagation.TextMapSetter; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +/** + * A {@link TextMapSetter} that injects context into a map carrier, intended for use with + * environment variables. + * + *

Standard environment variable names are uppercase (e.g., {@code TRACEPARENT}, {@code + * TRACESTATE}, {@code BAGGAGE}). This setter translates keys to uppercase and replaces characters + * not allowed in environment variables (e.g., {@code .} and {@code -}) with underscores before + * inserting them into the carrier. + * + * @see Environment + * Variable Format Restrictions + */ +@Immutable +public final class EnvironmentSetter implements TextMapSetter> { + + private static final EnvironmentSetter INSTANCE = new EnvironmentSetter(); + + private EnvironmentSetter() {} + + /** Returns the singleton instance of {@link EnvironmentSetter}. */ + public static EnvironmentSetter getInstance() { + return INSTANCE; + } + + @Override + public void set(@Nullable Map carrier, String key, String value) { + if (carrier == null || key == null || value == null) { + return; + } + // Spec recommends using uppercase and underscores for environment variable + // names for maximum + // cross-platform compatibility. + String sanitizedKey = key.replace('.', '_').replace('-', '_').toUpperCase(Locale.ROOT); + carrier.put(sanitizedKey, value); + } + + @Override + public String toString() { + return "EnvironmentSetter"; + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetterTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetterTest.java new file mode 100644 index 00000000000..71807282823 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetterTest.java @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.propagation; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class EnvironmentGetterTest { + + @Test + void get() { + Map carrier = new HashMap<>(); + carrier.put("TRACEPARENT", "val1"); + carrier.put("TRACESTATE", "val2"); + carrier.put("BAGGAGE", "val3"); + carrier.put("OTHER", "val4"); + + assertThat(EnvironmentGetter.getInstance().get(carrier, "traceparent")).isEqualTo("val1"); + assertThat(EnvironmentGetter.getInstance().get(carrier, "TRACESTATE")).isEqualTo("val2"); + assertThat(EnvironmentGetter.getInstance().get(carrier, "Baggage")).isEqualTo("val3"); + assertThat(EnvironmentGetter.getInstance().get(carrier, "other")).isEqualTo("val4"); + } + + @Test + void get_sanitization() { + Map carrier = new HashMap<>(); + carrier.put("OTEL_TRACE_ID", "val1"); + carrier.put("OTEL_BAGGAGE_KEY", "val2"); + + assertThat(EnvironmentGetter.getInstance().get(carrier, "otel.trace.id")).isEqualTo("val1"); + assertThat(EnvironmentGetter.getInstance().get(carrier, "otel-baggage-key")).isEqualTo("val2"); + } + + @Test + void get_null() { + assertThat(EnvironmentGetter.getInstance().get(null, "key")).isNull(); + assertThat(EnvironmentGetter.getInstance().get(Collections.emptyMap(), null)).isNull(); + } + + @Test + void keys() { + Map carrier = new HashMap<>(); + carrier.put("K1", "V1"); + carrier.put("K2", "V2"); + + assertThat(EnvironmentGetter.getInstance().keys(carrier)).containsExactlyInAnyOrder("K1", "K2"); + assertThat(EnvironmentGetter.getInstance().keys(null)).isEmpty(); + } + + @Test + void testToString() { + assertThat(EnvironmentGetter.getInstance().toString()).isEqualTo("EnvironmentGetter"); + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/propagation/EnvironmentSetterTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/propagation/EnvironmentSetterTest.java new file mode 100644 index 00000000000..ea735eeb304 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/propagation/EnvironmentSetterTest.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.propagation; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class EnvironmentSetterTest { + + @Test + void set() { + Map carrier = new HashMap<>(); + EnvironmentSetter.getInstance().set(carrier, "traceparent", "val1"); + EnvironmentSetter.getInstance().set(carrier, "TRACESTATE", "val2"); + EnvironmentSetter.getInstance().set(carrier, "Baggage", "val3"); + + assertThat(carrier).containsEntry("TRACEPARENT", "val1"); + assertThat(carrier).containsEntry("TRACESTATE", "val2"); + assertThat(carrier).containsEntry("BAGGAGE", "val3"); + } + + @Test + void set_sanitization() { + Map carrier = new HashMap<>(); + EnvironmentSetter.getInstance().set(carrier, "otel.trace.id", "val1"); + EnvironmentSetter.getInstance().set(carrier, "otel-baggage-key", "val2"); + + assertThat(carrier).containsEntry("OTEL_TRACE_ID", "val1"); + assertThat(carrier).containsEntry("OTEL_BAGGAGE_KEY", "val2"); + } + + @Test + void set_null() { + Map carrier = new HashMap<>(); + EnvironmentSetter.getInstance().set(null, "key", "val"); + EnvironmentSetter.getInstance().set(carrier, null, "val"); + EnvironmentSetter.getInstance().set(carrier, "key", null); + assertThat(carrier).isEmpty(); + } + + @Test + void testToString() { + assertThat(EnvironmentSetter.getInstance().toString()).isEqualTo("EnvironmentSetter"); + } +}