add config support for BaggageSpanProcessor (#1330)
Co-authored-by: Mike Goldsmith <goldsmith.mike@gmail.com>
This commit is contained in:
parent
6f3cfa3c39
commit
d23bc116c0
|
|
@ -21,6 +21,7 @@ components:
|
|||
- srprash
|
||||
baggage-procesor:
|
||||
- mikegoldsmith
|
||||
- zeitlinger
|
||||
compressors:
|
||||
- jack-berg
|
||||
consistent-sampling:
|
||||
|
|
|
|||
|
|
@ -42,8 +42,18 @@ Pattern pattern = Pattern.compile("^key.+");
|
|||
new BaggageSpanProcessor(baggageKey -> pattern.matcher(baggageKey).matches())
|
||||
```
|
||||
|
||||
## Usage with SDK auto-configuration
|
||||
|
||||
If you are using the OpenTelemetry SDK auto-configuration, you can add the span processor this
|
||||
library to configure the span processor.
|
||||
|
||||
| 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. |
|
||||
|
||||
## Component owners
|
||||
|
||||
- [Mike Golsmith](https://github.com/MikeGoldsmith), Honeycomb
|
||||
- [Gregor Zeitlinger](https://github.com/zeitlinger), Grafana
|
||||
|
||||
Learn more about component owners in [component_owners.yml](../.github/component_owners.yml).
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ otelJava.moduleName.set("io.opentelemetry.contrib.baggage.processor")
|
|||
dependencies {
|
||||
api("io.opentelemetry:opentelemetry-api")
|
||||
api("io.opentelemetry:opentelemetry-sdk")
|
||||
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
|
||||
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
|
||||
testImplementation("org.mockito:mockito-inline")
|
||||
testImplementation("com.google.guava:guava")
|
||||
testImplementation("org.awaitility:awaitility")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import java.util.function.Predicate;
|
|||
public class BaggageSpanProcessor implements SpanProcessor {
|
||||
private final Predicate<String> baggageKeyPredicate;
|
||||
|
||||
/** A {@link Predicate} that returns true for all baggage keys. */
|
||||
public static final Predicate<String> allowAllBaggageKeys = baggageKey -> true;
|
||||
/** use {@link #allowAllBaggageKeys()} instead */
|
||||
@Deprecated public static final Predicate<String> allowAllBaggageKeys = baggageKey -> true;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BaggageSpanProcessor} that copies only baggage entries with keys that pass
|
||||
|
|
@ -30,6 +30,14 @@ public class BaggageSpanProcessor implements SpanProcessor {
|
|||
this.baggageKeyPredicate = baggageKeyPredicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BaggageSpanProcessor} that copies all baggage entries into the newly
|
||||
* created {@link io.opentelemetry.api.trace.Span}.
|
||||
*/
|
||||
public static BaggageSpanProcessor allowAllBaggageKeys() {
|
||||
return new BaggageSpanProcessor(baggageKey -> true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Context parentContext, ReadWriteSpan span) {
|
||||
Baggage.fromContext(parentContext)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.baggage.processor;
|
||||
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
|
||||
import java.util.List;
|
||||
|
||||
public class BaggageSpanProcessorCustomizer implements AutoConfigurationCustomizerProvider {
|
||||
@Override
|
||||
public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) {
|
||||
autoConfigurationCustomizer.addTracerProviderCustomizer(
|
||||
(sdkTracerProviderBuilder, config) -> {
|
||||
addSpanProcessor(sdkTracerProviderBuilder, config);
|
||||
return sdkTracerProviderBuilder;
|
||||
});
|
||||
}
|
||||
|
||||
private static void addSpanProcessor(
|
||||
SdkTracerProviderBuilder sdkTracerProviderBuilder, ConfigProperties config) {
|
||||
List<String> keys =
|
||||
config.getList("otel.java.experimental.span-attributes.copy-from-baggage.include");
|
||||
|
||||
if (keys.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sdkTracerProviderBuilder.addSpanProcessor(createProcessor(keys));
|
||||
}
|
||||
|
||||
static BaggageSpanProcessor createProcessor(List<String> keys) {
|
||||
if (keys.size() == 1 && keys.get(0).equals("*")) {
|
||||
return BaggageSpanProcessor.allowAllBaggageKeys();
|
||||
}
|
||||
return new BaggageSpanProcessor(keys::contains);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
io.opentelemetry.contrib.baggage.processor.BaggageSpanProcessorCustomizer
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.contrib.baggage.processor;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.opentelemetry.api.baggage.Baggage;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
|
||||
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||
import io.opentelemetry.sdk.testing.assertj.TracesAssert;
|
||||
import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter;
|
||||
import io.opentelemetry.sdk.trace.ReadWriteSpan;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class BaggageSpanProcessorCustomizerTest {
|
||||
|
||||
private static final String MEMORY_EXPORTER = "memory";
|
||||
|
||||
@Test
|
||||
void test_customizer() {
|
||||
assertCustomizer(Collections.emptyMap(), span -> span.hasTotalAttributeCount(0));
|
||||
assertCustomizer(
|
||||
Collections.singletonMap(
|
||||
"otel.java.experimental.span-attributes.copy-from-baggage.include", "key"),
|
||||
span -> span.hasAttribute(AttributeKey.stringKey("key"), "value"));
|
||||
}
|
||||
|
||||
private static void assertCustomizer(
|
||||
Map<String, String> properties, Consumer<SpanDataAssert> spanDataAssertConsumer) {
|
||||
|
||||
InMemorySpanExporter spanExporter = InMemorySpanExporter.create();
|
||||
|
||||
OpenTelemetrySdk sdk = getOpenTelemetrySdk(properties, spanExporter);
|
||||
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
|
||||
sdk.getTracer("test").spanBuilder("test").startSpan().end();
|
||||
}
|
||||
await()
|
||||
.atMost(Duration.ofSeconds(1))
|
||||
.untilAsserted(
|
||||
() ->
|
||||
TracesAssert.assertThat(spanExporter.getFinishedSpanItems())
|
||||
.hasTracesSatisfyingExactly(
|
||||
trace -> trace.hasSpansSatisfyingExactly(spanDataAssertConsumer)));
|
||||
}
|
||||
|
||||
private static OpenTelemetrySdk getOpenTelemetrySdk(
|
||||
Map<String, String> properties, InMemorySpanExporter spanExporter) {
|
||||
SpiHelper spiHelper =
|
||||
SpiHelper.create(BaggageSpanProcessorCustomizerTest.class.getClassLoader());
|
||||
|
||||
AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder =
|
||||
AutoConfiguredOpenTelemetrySdk.builder()
|
||||
.addPropertiesSupplier(
|
||||
() ->
|
||||
ImmutableMap.of(
|
||||
// We set the export interval of the spans to 100 ms. The default value is 5
|
||||
// seconds.
|
||||
"otel.bsp.schedule.delay",
|
||||
"10",
|
||||
"otel.traces.exporter",
|
||||
MEMORY_EXPORTER,
|
||||
"otel.metrics.exporter",
|
||||
"none",
|
||||
"otel.logs.exporter",
|
||||
"none"))
|
||||
.addPropertiesSupplier(() -> properties);
|
||||
AutoConfigureUtil.setComponentLoader(
|
||||
sdkBuilder,
|
||||
new ComponentLoader() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> List<T> load(Class<T> spiClass) {
|
||||
if (spiClass == ConfigurableSpanExporterProvider.class) {
|
||||
return Collections.singletonList(
|
||||
(T)
|
||||
new ConfigurableSpanExporterProvider() {
|
||||
@Override
|
||||
public SpanExporter createExporter(ConfigProperties configProperties) {
|
||||
return spanExporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MEMORY_EXPORTER;
|
||||
}
|
||||
});
|
||||
}
|
||||
return spiHelper.load(spiClass);
|
||||
}
|
||||
});
|
||||
return sdkBuilder.build().getOpenTelemetrySdk();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) {
|
||||
try (BaggageSpanProcessor processor =
|
||||
BaggageSpanProcessorCustomizer.createProcessor(Collections.singletonList("*"))) {
|
||||
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
|
||||
processor.onStart(Context.current(), span);
|
||||
verify(span).setAttribute("key", "value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_baggageSpanProcessor_adds_attributes_to_spans_when_key_filter_matches(
|
||||
@Mock ReadWriteSpan span) {
|
||||
try (BaggageSpanProcessor processor =
|
||||
BaggageSpanProcessorCustomizer.createProcessor(Collections.singletonList("key"))) {
|
||||
try (Scope ignore =
|
||||
Baggage.current().toBuilder()
|
||||
.put("key", "value")
|
||||
.put("other", "value")
|
||||
.build()
|
||||
.makeCurrent()) {
|
||||
processor.onStart(Context.current(), span);
|
||||
verify(span).setAttribute("key", "value");
|
||||
verify(span, Mockito.never()).setAttribute("other", "value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,8 +21,7 @@ public class BaggageSpanProcessorTest {
|
|||
|
||||
@Test
|
||||
public void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) {
|
||||
try (BaggageSpanProcessor processor =
|
||||
new BaggageSpanProcessor(BaggageSpanProcessor.allowAllBaggageKeys)) {
|
||||
try (BaggageSpanProcessor processor = BaggageSpanProcessor.allowAllBaggageKeys()) {
|
||||
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
|
||||
processor.onStart(Context.current(), span);
|
||||
Mockito.verify(span).setAttribute("key", "value");
|
||||
|
|
|
|||
Loading…
Reference in New Issue