diff --git a/baggage-processor/README.md b/baggage-processor/README.md index 5934c28e43..0ef984c4a4 100644 --- a/baggage-processor/README.md +++ b/baggage-processor/README.md @@ -22,10 +22,12 @@ Do not put sensitive information in Baggage. If you are using the OpenTelemetry SDK auto-configuration, you can add the span and log baggage processors through configuration. -| Property | Description | -| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | -| `otel.java.experimental.span-attributes.copy-from-baggage.include` | Add baggage entries as span attributes, e.g. `key1,key2` or `*` to add all baggage items as keys. | -| `otel.java.experimental.log-attributes.copy-from-baggage.include` | Add baggage entries as log attributes, e.g. `key1,key2` or `*` to add all baggage items as keys. | +| Property | Description | +| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | +| `otel.java.experimental.span-attributes.copy-from-baggage.include` | Add baggage entries as span attributes, e.g. `key1,key*`, wildcard pattern mathinc is supported. | +| `otel.java.experimental.log-attributes.copy-from-baggage.include` | Add baggage entries as log attributes, e.g. `key1,key*`, wildcard pattern mathinc is supported. | + +[Wildcard pattern matching]([wildcard pattern matching](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/CONTRIBUTING.md#properties-requiring-pattern-matching)) is supported for both properties. ### Usage with declarative configuration @@ -58,6 +60,11 @@ This will configure the respective processor to include baggage keys listed in ` exclude those in `excluded` as explained in [Properties requiring pattern matching](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/CONTRIBUTING.md#properties-requiring-pattern-matching). +When both `included` and `excluded` are empty or not set, all the baggage entries will be copied. +When only `included` is set, only the baggage entries matching the patterns in `included` will be copied (opt-in). +When only `excluded` is set, all baggage entries except those matching the patterns in `excluded` will be copied (opt-out). +When a value matches both `included` and `excluded`, then it is excluded. + ### Usage through programmatic activation Add the span and log processor when configuring the tracer and logger providers. @@ -65,7 +72,9 @@ Add the span and log processor when configuring the tracer and logger providers. To configure the span and log processors to copy all baggage entries during configuration: ```java -import io.opentelemetry.contrib.baggage.processor; +import io.opentelemetry.contrib.baggage.processor.BaggageSpanProcessor; +import io.opentelemetry.contrib.baggage.processor.BaggageLogProcessor; + // ... TracerProvider tracerProvider = SdkTracerProvider.builder() @@ -73,25 +82,18 @@ TracerProvider tracerProvider = SdkTracerProvider.builder() .build(); LoggerProvider loggerProvider = SdkLoggerProvider.builder() - .addLogRecordProcessor(BaggageLogRecordProcessor.allowAllBaggageKeys()) + .addLogProcessor(BaggageLogRecordProcessor.allowAllBaggageKeys()) .build(); ``` -Alternatively, you can provide a custom baggage key predicate to select which baggage keys you want to copy. - -For example, to only copy baggage entries that start with `my-key`: - -```java -new BaggageSpanProcessor(baggageKey -> baggageKey.startsWith("my-key")); -new BaggageLogRecordProcessor(baggageKey -> baggageKey.startsWith("my-key")); -``` +Alternatively, you can provide a custom baggage key wildcards to select which baggage keys you want to include/exclude + for copy. -For example, to only copy baggage entries that match the regex `^key.+`: +For example, to only copy baggage entries that start with `my-key` and ignore keys that end with `*-ignored` ```java -Pattern pattern = Pattern.compile("^key.+"); -new BaggageSpanProcessor(baggageKey -> pattern.matcher(baggageKey).matches()); -new BaggageLogRecordProcessor(baggageKey -> pattern.matcher(baggageKey).matches()); +new BaggageSpanProcessor(Collections.singletonList("my-key*"), Collections.singletonList("*-ignored")); +new BaggageLogRecordProcessor(Collections.singletonList("my-key*"), Collections.singletonList("*-ignored")); ``` ## Component owners diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java index 34930eb6b6..693e6a7fee 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordComponentProvider.java @@ -8,7 +8,6 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; import io.opentelemetry.sdk.logs.LogRecordProcessor; @AutoService(ComponentProvider.class) @@ -21,9 +20,8 @@ public String getName() { @Override public LogRecordProcessor create(DeclarativeConfigProperties config) { return new BaggageLogRecordProcessor( - IncludeExcludePredicate.createPatternMatching( - config.getScalarList("included", String.class), - config.getScalarList("excluded", String.class))); + config.getScalarList("included", String.class), + config.getScalarList("excluded", String.class)); } @Override diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java index b075488052..d0ac2f3c29 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageLogRecordProcessor.java @@ -8,9 +8,12 @@ import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; import io.opentelemetry.sdk.logs.LogRecordProcessor; import io.opentelemetry.sdk.logs.ReadWriteLogRecord; +import java.util.Collection; import java.util.function.Predicate; +import javax.annotation.Nullable; /** * This log record processor copies attributes stored in {@link Baggage} into each newly created log @@ -21,19 +24,36 @@ public final class BaggageLogRecordProcessor implements LogRecordProcessor { private final Predicate baggageKeyPredicate; /** - * Creates a new {@link BaggageLogRecordProcessor} that copies only baggage entries with keys that - * pass the provided filter into the newly created log record. + * @deprecated Use {@link #BaggageLogRecordProcessor(Collection, Collection)} instead. Most usages + * of this method should be replaceable with glob patterns, but not all thus this method is + * kept to preserve compatibility. */ + @Deprecated public BaggageLogRecordProcessor(Predicate baggageKeyPredicate) { this.baggageKeyPredicate = baggageKeyPredicate; } + /** + * Creates a new {@link BaggageLogRecordProcessor} that copies baggage entries with keys that pass + * the provided include/exclude filtering into the newly created log record, when both arguments + * are null or empty all baggage are included. + * + * @param included list of included baggage key patterns to include + * @param excluded list of excluded baggage key patterns to exclude + */ + public BaggageLogRecordProcessor( + @Nullable Collection included, @Nullable Collection excluded) { + this.baggageKeyPredicate = IncludeExcludePredicate.createPatternMatching(included, excluded); + } + /** * Creates a new {@link BaggageLogRecordProcessor} that copies all baggage entries into the newly * created log record. + * + * @return baggage log processor including all attributes */ public static BaggageLogRecordProcessor allowAllBaggageKeys() { - return new BaggageLogRecordProcessor(baggageKey -> true); + return new BaggageLogRecordProcessor(null, null); } @Override diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java index 2e07722e6b..069adfc42b 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizer.java @@ -40,14 +40,7 @@ private static void addSpanProcessor( } // need to add before the batch span processor - sdkTracerProviderBuilder.addSpanProcessorFirst(createBaggageSpanProcessor(keys)); - } - - static BaggageSpanProcessor createBaggageSpanProcessor(List keys) { - if (keys.size() == 1 && keys.get(0).equals("*")) { - return BaggageSpanProcessor.allowAllBaggageKeys(); - } - return new BaggageSpanProcessor(keys::contains); + sdkTracerProviderBuilder.addSpanProcessorFirst(new BaggageSpanProcessor(keys, null)); } private static void addLogRecordProcessor( @@ -60,13 +53,6 @@ private static void addLogRecordProcessor( } // need to add before the batch log processor - sdkLoggerProviderBuilder.addLogRecordProcessorFirst(createBaggageLogRecordProcessor(keys)); - } - - static BaggageLogRecordProcessor createBaggageLogRecordProcessor(List keys) { - if (keys.size() == 1 && keys.get(0).equals("*")) { - return BaggageLogRecordProcessor.allowAllBaggageKeys(); - } - return new BaggageLogRecordProcessor(keys::contains); + sdkLoggerProviderBuilder.addLogRecordProcessorFirst(new BaggageLogRecordProcessor(keys, null)); } } diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java index dc294a925e..5786d8b9c4 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanComponentProvider.java @@ -8,7 +8,6 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; import io.opentelemetry.sdk.trace.SpanProcessor; @AutoService(ComponentProvider.class) @@ -21,9 +20,8 @@ public String getName() { @Override public SpanProcessor create(DeclarativeConfigProperties config) { return new BaggageSpanProcessor( - IncludeExcludePredicate.createPatternMatching( - config.getScalarList("included", String.class), - config.getScalarList("excluded", String.class))); + config.getScalarList("included", String.class), + config.getScalarList("excluded", String.class)); } @Override diff --git a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java index 8a996f53a2..dd3a390332 100644 --- a/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java +++ b/baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java @@ -7,10 +7,13 @@ import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; import io.opentelemetry.sdk.trace.ReadWriteSpan; import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.SpanProcessor; +import java.util.Collection; import java.util.function.Predicate; +import javax.annotation.Nullable; /** * This span processor copies attributes stored in {@link Baggage} into each newly created {@link @@ -20,19 +23,37 @@ public final class BaggageSpanProcessor implements SpanProcessor { private final Predicate baggageKeyPredicate; /** - * Creates a new {@link BaggageSpanProcessor} that copies only baggage entries with keys that pass - * the provided filter into the newly created {@link io.opentelemetry.api.trace.Span}. + * @deprecated Use {@link #BaggageSpanProcessor(Collection, Collection)} instead. Most usages of + * this method should be replaceable with glob patterns, but not all thus this method is kept + * to preserve compatibility. */ + @Deprecated public BaggageSpanProcessor(Predicate baggageKeyPredicate) { this.baggageKeyPredicate = baggageKeyPredicate; } + /** + * Creates a new {@link BaggageSpanProcessor} that copies baggage entries with keys that pass the + * provided include/exclude filtering into the newly created {@link + * io.opentelemetry.api.trace.Span}, when both arguments are null or empty all baggage are + * included. + * + * @param included list of included baggage key patterns to include + * @param excluded list of excluded baggage key patterns to exclude + */ + public BaggageSpanProcessor( + @Nullable Collection included, @Nullable Collection excluded) { + this.baggageKeyPredicate = IncludeExcludePredicate.createPatternMatching(included, excluded); + } + /** * Creates a new {@link BaggageSpanProcessor} that copies all baggage entries into the newly - * created {@link io.opentelemetry.api.trace.Span}. + * created span. + * + * @return baggage span processor including all attributes */ public static BaggageSpanProcessor allowAllBaggageKeys() { - return new BaggageSpanProcessor(baggageKey -> true); + return new BaggageSpanProcessor(null, null); } @Override diff --git a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java index 645ff53343..23762b787d 100644 --- a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java +++ b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageProcessorCustomizerTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.contrib.baggage.processor; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static java.util.Collections.singletonList; import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.verify; @@ -122,7 +123,7 @@ private static OpenTelemetrySdk getOpenTelemetrySdk( @Override public List load(Class spiClass) { if (spiClass.equals(ConfigurableSpanExporterProvider.class)) { - return Collections.singletonList( + return singletonList( spiClass.cast( new ConfigurableSpanExporterProvider() { @Override @@ -137,7 +138,7 @@ public String getName() { } })); } else if (spiClass.equals(ConfigurableLogRecordExporterProvider.class)) { - return Collections.singletonList( + return singletonList( spiClass.cast( new ConfigurableLogRecordExporterProvider() { @Override @@ -160,8 +161,7 @@ public String getName() { @Test void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) { - try (BaggageSpanProcessor processor = - BaggageProcessorCustomizer.createBaggageSpanProcessor(Collections.singletonList("*"))) { + try (BaggageSpanProcessor processor = BaggageSpanProcessor.allowAllBaggageKeys()) { try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) { processor.onStart(Context.current(), span); verify(span).setAttribute("key", "value"); @@ -172,8 +172,7 @@ void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span @Test void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches( @Mock ReadWriteSpan span) { - try (BaggageSpanProcessor processor = - BaggageProcessorCustomizer.createBaggageSpanProcessor(Collections.singletonList("key"))) { + try (BaggageSpanProcessor processor = new BaggageSpanProcessor(singletonList("key"), null)) { try (Scope ignore = Baggage.current().toBuilder() .put("key", "value") @@ -191,8 +190,7 @@ void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches( void test_baggageLogRecordProcessor_adds_attributes_to_logRecord( @Mock ReadWriteLogRecord logRecord) { try (BaggageLogRecordProcessor processor = - BaggageProcessorCustomizer.createBaggageLogRecordProcessor( - Collections.singletonList("*"))) { + new BaggageLogRecordProcessor(singletonList("*"), null)) { try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) { processor.onEmit(Context.current(), logRecord); verify(logRecord).setAttribute(AttributeKey.stringKey("key"), "value"); @@ -204,8 +202,7 @@ void test_baggageLogRecordProcessor_adds_attributes_to_logRecord( void test_baggageLogRecordProcessor_adds_attributes_to_spans_when_key_filter_matches( @Mock ReadWriteLogRecord logRecord) { try (BaggageLogRecordProcessor processor = - BaggageProcessorCustomizer.createBaggageLogRecordProcessor( - Collections.singletonList("key"))) { + new BaggageLogRecordProcessor(singletonList("k*"), null)) { try (Scope ignore = Baggage.current().toBuilder() .put("key", "value") @@ -218,4 +215,23 @@ void test_baggageLogRecordProcessor_adds_attributes_to_spans_when_key_filter_mat } } } + + @Test + void test_baggageLogRecordProcessor_adds_attributes_to_spans_include_exclude( + @Mock ReadWriteLogRecord logRecord) { + try (BaggageLogRecordProcessor processor = + new BaggageLogRecordProcessor(singletonList("key*"), singletonList("*excluded"))) { + try (Scope ignore = + Baggage.current().toBuilder() + .put("key", "value") + .put("key_is_excluded", "value") + .build() + .makeCurrent()) { + processor.onEmit(Context.current(), logRecord); + verify(logRecord).setAttribute(AttributeKey.stringKey("key"), "value"); + verify(logRecord, Mockito.never()) + .setAttribute(AttributeKey.stringKey("key_is_excluded"), "value"); + } + } + } } diff --git a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessorTest.java b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessorTest.java index dd7ea38269..8de35e5866 100644 --- a/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessorTest.java +++ b/baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessorTest.java @@ -5,11 +5,12 @@ package io.opentelemetry.contrib.baggage.processor; +import static java.util.Collections.singletonList; + import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.trace.ReadWriteSpan; -import java.util.regex.Pattern; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -32,7 +33,7 @@ void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span @Test void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches( @Mock ReadWriteSpan span) { - try (BaggageSpanProcessor processor = new BaggageSpanProcessor(key -> key.startsWith("k"))) { + try (BaggageSpanProcessor processor = new BaggageSpanProcessor(singletonList("k*"), null)) { try (Scope ignore = Baggage.current().toBuilder() .put("key", "value") @@ -47,20 +48,19 @@ void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches( } @Test - void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches_regex( + void test_baggageSpanProcessor_adds_attributes_to_spans_include_exclude( @Mock ReadWriteSpan span) { - Pattern pattern = Pattern.compile("k.*"); try (BaggageSpanProcessor processor = - new BaggageSpanProcessor(key -> pattern.matcher(key).matches())) { + new BaggageSpanProcessor(singletonList("k*"), singletonList("*ignored"))) { try (Scope ignore = Baggage.current().toBuilder() .put("key", "value") - .put("other", "value") + .put("key_is_ignored", "value") .build() .makeCurrent()) { processor.onStart(Context.current(), span); Mockito.verify(span).setAttribute("key", "value"); - Mockito.verify(span, Mockito.never()).setAttribute("other", "value"); + Mockito.verify(span, Mockito.never()).setAttribute("key_is_ignored", "value"); } } }