Skip to content

Commit d23bc11

Browse files
add config support for BaggageSpanProcessor (#1330)
Co-authored-by: Mike Goldsmith <[email protected]>
1 parent 6f3cfa3 commit d23bc11

File tree

8 files changed

+218
-4
lines changed

8 files changed

+218
-4
lines changed

.github/component_owners.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ components:
2121
- srprash
2222
baggage-procesor:
2323
- mikegoldsmith
24+
- zeitlinger
2425
compressors:
2526
- jack-berg
2627
consistent-sampling:

baggage-processor/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,18 @@ Pattern pattern = Pattern.compile("^key.+");
4242
new BaggageSpanProcessor(baggageKey -> pattern.matcher(baggageKey).matches())
4343
```
4444

45+
## Usage with SDK auto-configuration
46+
47+
If you are using the OpenTelemetry SDK auto-configuration, you can add the span processor this
48+
library to configure the span processor.
49+
50+
| Property | Description |
51+
|------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
52+
| 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. |
53+
4554
## Component owners
4655

4756
- [Mike Golsmith](https://github.com/MikeGoldsmith), Honeycomb
57+
- [Gregor Zeitlinger](https://github.com/zeitlinger), Grafana
4858

4959
Learn more about component owners in [component_owners.yml](../.github/component_owners.yml).

baggage-processor/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ otelJava.moduleName.set("io.opentelemetry.contrib.baggage.processor")
1010
dependencies {
1111
api("io.opentelemetry:opentelemetry-api")
1212
api("io.opentelemetry:opentelemetry-sdk")
13+
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
1314

1415
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
16+
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
17+
testImplementation("org.mockito:mockito-inline")
18+
testImplementation("com.google.guava:guava")
19+
testImplementation("org.awaitility:awaitility")
1520
}

baggage-processor/src/main/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessor.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
public class BaggageSpanProcessor implements SpanProcessor {
2020
private final Predicate<String> baggageKeyPredicate;
2121

22-
/** A {@link Predicate} that returns true for all baggage keys. */
23-
public static final Predicate<String> allowAllBaggageKeys = baggageKey -> true;
22+
/** use {@link #allowAllBaggageKeys()} instead */
23+
@Deprecated public static final Predicate<String> allowAllBaggageKeys = baggageKey -> true;
2424

2525
/**
2626
* Creates a new {@link BaggageSpanProcessor} that copies only baggage entries with keys that pass
@@ -30,6 +30,14 @@ public BaggageSpanProcessor(Predicate<String> baggageKeyPredicate) {
3030
this.baggageKeyPredicate = baggageKeyPredicate;
3131
}
3232

33+
/**
34+
* Creates a new {@link BaggageSpanProcessor} that copies all baggage entries into the newly
35+
* created {@link io.opentelemetry.api.trace.Span}.
36+
*/
37+
public static BaggageSpanProcessor allowAllBaggageKeys() {
38+
return new BaggageSpanProcessor(baggageKey -> true);
39+
}
40+
3341
@Override
3442
public void onStart(Context parentContext, ReadWriteSpan span) {
3543
Baggage.fromContext(parentContext)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.baggage.processor;
7+
8+
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
9+
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
10+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11+
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
12+
import java.util.List;
13+
14+
public class BaggageSpanProcessorCustomizer implements AutoConfigurationCustomizerProvider {
15+
@Override
16+
public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) {
17+
autoConfigurationCustomizer.addTracerProviderCustomizer(
18+
(sdkTracerProviderBuilder, config) -> {
19+
addSpanProcessor(sdkTracerProviderBuilder, config);
20+
return sdkTracerProviderBuilder;
21+
});
22+
}
23+
24+
private static void addSpanProcessor(
25+
SdkTracerProviderBuilder sdkTracerProviderBuilder, ConfigProperties config) {
26+
List<String> keys =
27+
config.getList("otel.java.experimental.span-attributes.copy-from-baggage.include");
28+
29+
if (keys.isEmpty()) {
30+
return;
31+
}
32+
33+
sdkTracerProviderBuilder.addSpanProcessor(createProcessor(keys));
34+
}
35+
36+
static BaggageSpanProcessor createProcessor(List<String> keys) {
37+
if (keys.size() == 1 && keys.get(0).equals("*")) {
38+
return BaggageSpanProcessor.allowAllBaggageKeys();
39+
}
40+
return new BaggageSpanProcessor(keys::contains);
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.opentelemetry.contrib.baggage.processor.BaggageSpanProcessorCustomizer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.baggage.processor;
7+
8+
import static org.awaitility.Awaitility.await;
9+
import static org.mockito.Mockito.verify;
10+
11+
import com.google.common.collect.ImmutableMap;
12+
import io.opentelemetry.api.baggage.Baggage;
13+
import io.opentelemetry.api.common.AttributeKey;
14+
import io.opentelemetry.context.Context;
15+
import io.opentelemetry.context.Scope;
16+
import io.opentelemetry.sdk.OpenTelemetrySdk;
17+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
18+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
19+
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
20+
import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader;
21+
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
22+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
23+
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
24+
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
25+
import io.opentelemetry.sdk.testing.assertj.TracesAssert;
26+
import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter;
27+
import io.opentelemetry.sdk.trace.ReadWriteSpan;
28+
import io.opentelemetry.sdk.trace.export.SpanExporter;
29+
import java.time.Duration;
30+
import java.util.Collections;
31+
import java.util.List;
32+
import java.util.Map;
33+
import java.util.function.Consumer;
34+
import org.junit.jupiter.api.Test;
35+
import org.junit.jupiter.api.extension.ExtendWith;
36+
import org.mockito.Mock;
37+
import org.mockito.Mockito;
38+
import org.mockito.junit.jupiter.MockitoExtension;
39+
40+
@ExtendWith(MockitoExtension.class)
41+
class BaggageSpanProcessorCustomizerTest {
42+
43+
private static final String MEMORY_EXPORTER = "memory";
44+
45+
@Test
46+
void test_customizer() {
47+
assertCustomizer(Collections.emptyMap(), span -> span.hasTotalAttributeCount(0));
48+
assertCustomizer(
49+
Collections.singletonMap(
50+
"otel.java.experimental.span-attributes.copy-from-baggage.include", "key"),
51+
span -> span.hasAttribute(AttributeKey.stringKey("key"), "value"));
52+
}
53+
54+
private static void assertCustomizer(
55+
Map<String, String> properties, Consumer<SpanDataAssert> spanDataAssertConsumer) {
56+
57+
InMemorySpanExporter spanExporter = InMemorySpanExporter.create();
58+
59+
OpenTelemetrySdk sdk = getOpenTelemetrySdk(properties, spanExporter);
60+
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
61+
sdk.getTracer("test").spanBuilder("test").startSpan().end();
62+
}
63+
await()
64+
.atMost(Duration.ofSeconds(1))
65+
.untilAsserted(
66+
() ->
67+
TracesAssert.assertThat(spanExporter.getFinishedSpanItems())
68+
.hasTracesSatisfyingExactly(
69+
trace -> trace.hasSpansSatisfyingExactly(spanDataAssertConsumer)));
70+
}
71+
72+
private static OpenTelemetrySdk getOpenTelemetrySdk(
73+
Map<String, String> properties, InMemorySpanExporter spanExporter) {
74+
SpiHelper spiHelper =
75+
SpiHelper.create(BaggageSpanProcessorCustomizerTest.class.getClassLoader());
76+
77+
AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder =
78+
AutoConfiguredOpenTelemetrySdk.builder()
79+
.addPropertiesSupplier(
80+
() ->
81+
ImmutableMap.of(
82+
// We set the export interval of the spans to 100 ms. The default value is 5
83+
// seconds.
84+
"otel.bsp.schedule.delay",
85+
"10",
86+
"otel.traces.exporter",
87+
MEMORY_EXPORTER,
88+
"otel.metrics.exporter",
89+
"none",
90+
"otel.logs.exporter",
91+
"none"))
92+
.addPropertiesSupplier(() -> properties);
93+
AutoConfigureUtil.setComponentLoader(
94+
sdkBuilder,
95+
new ComponentLoader() {
96+
@SuppressWarnings("unchecked")
97+
@Override
98+
public <T> List<T> load(Class<T> spiClass) {
99+
if (spiClass == ConfigurableSpanExporterProvider.class) {
100+
return Collections.singletonList(
101+
(T)
102+
new ConfigurableSpanExporterProvider() {
103+
@Override
104+
public SpanExporter createExporter(ConfigProperties configProperties) {
105+
return spanExporter;
106+
}
107+
108+
@Override
109+
public String getName() {
110+
return MEMORY_EXPORTER;
111+
}
112+
});
113+
}
114+
return spiHelper.load(spiClass);
115+
}
116+
});
117+
return sdkBuilder.build().getOpenTelemetrySdk();
118+
}
119+
120+
@Test
121+
public void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) {
122+
try (BaggageSpanProcessor processor =
123+
BaggageSpanProcessorCustomizer.createProcessor(Collections.singletonList("*"))) {
124+
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
125+
processor.onStart(Context.current(), span);
126+
verify(span).setAttribute("key", "value");
127+
}
128+
}
129+
}
130+
131+
@Test
132+
public void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches(
133+
@Mock ReadWriteSpan span) {
134+
try (BaggageSpanProcessor processor =
135+
BaggageSpanProcessorCustomizer.createProcessor(Collections.singletonList("key"))) {
136+
try (Scope ignore =
137+
Baggage.current().toBuilder()
138+
.put("key", "value")
139+
.put("other", "value")
140+
.build()
141+
.makeCurrent()) {
142+
processor.onStart(Context.current(), span);
143+
verify(span).setAttribute("key", "value");
144+
verify(span, Mockito.never()).setAttribute("other", "value");
145+
}
146+
}
147+
}
148+
}

baggage-processor/src/test/java/io/opentelemetry/contrib/baggage/processor/BaggageSpanProcessorTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ public class BaggageSpanProcessorTest {
2121

2222
@Test
2323
public void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) {
24-
try (BaggageSpanProcessor processor =
25-
new BaggageSpanProcessor(BaggageSpanProcessor.allowAllBaggageKeys)) {
24+
try (BaggageSpanProcessor processor = BaggageSpanProcessor.allowAllBaggageKeys()) {
2625
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
2726
processor.onStart(Context.current(), span);
2827
Mockito.verify(span).setAttribute("key", "value");

0 commit comments

Comments
 (0)