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
|
- srprash
|
||||||
baggage-procesor:
|
baggage-procesor:
|
||||||
- mikegoldsmith
|
- mikegoldsmith
|
||||||
|
- zeitlinger
|
||||||
compressors:
|
compressors:
|
||||||
- jack-berg
|
- jack-berg
|
||||||
consistent-sampling:
|
consistent-sampling:
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,18 @@ Pattern pattern = Pattern.compile("^key.+");
|
||||||
new BaggageSpanProcessor(baggageKey -> pattern.matcher(baggageKey).matches())
|
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
|
## Component owners
|
||||||
|
|
||||||
- [Mike Golsmith](https://github.com/MikeGoldsmith), Honeycomb
|
- [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).
|
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 {
|
dependencies {
|
||||||
api("io.opentelemetry:opentelemetry-api")
|
api("io.opentelemetry:opentelemetry-api")
|
||||||
api("io.opentelemetry:opentelemetry-sdk")
|
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-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 {
|
public class BaggageSpanProcessor implements SpanProcessor {
|
||||||
private final Predicate<String> baggageKeyPredicate;
|
private final Predicate<String> baggageKeyPredicate;
|
||||||
|
|
||||||
/** A {@link Predicate} that returns true for all baggage keys. */
|
/** use {@link #allowAllBaggageKeys()} instead */
|
||||||
public static final Predicate<String> allowAllBaggageKeys = baggageKey -> true;
|
@Deprecated public static final Predicate<String> allowAllBaggageKeys = baggageKey -> true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link BaggageSpanProcessor} that copies only baggage entries with keys that pass
|
* 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;
|
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
|
@Override
|
||||||
public void onStart(Context parentContext, ReadWriteSpan span) {
|
public void onStart(Context parentContext, ReadWriteSpan span) {
|
||||||
Baggage.fromContext(parentContext)
|
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
|
@Test
|
||||||
public void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) {
|
public void test_baggageSpanProcessor_adds_attributes_to_spans(@Mock ReadWriteSpan span) {
|
||||||
try (BaggageSpanProcessor processor =
|
try (BaggageSpanProcessor processor = BaggageSpanProcessor.allowAllBaggageKeys()) {
|
||||||
new BaggageSpanProcessor(BaggageSpanProcessor.allowAllBaggageKeys)) {
|
|
||||||
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
|
try (Scope ignore = Baggage.current().toBuilder().put("key", "value").build().makeCurrent()) {
|
||||||
processor.onStart(Context.current(), span);
|
processor.onStart(Context.current(), span);
|
||||||
Mockito.verify(span).setAttribute("key", "value");
|
Mockito.verify(span).setAttribute("key", "value");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue