diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java index 0238d897907..23ba973f1ca 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracer.java @@ -30,9 +30,8 @@ class SdkTracer implements Tracer { private final TracerSharedState sharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; - - // TODO: add dedicated API for updating scope config. - @SuppressWarnings("FieldCanBeFinal") // For now, allow updating reflectively. + // deliberately not volatile because of performance concerns + // - which means its eventually consistent private boolean tracerEnabled; SdkTracer( @@ -79,4 +78,14 @@ public SpanBuilder spanBuilder(String spanName) { InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + + // Visible for testing + boolean isEnabled() { + return tracerEnabled; + } + + // currently not public as experimental + void updateTracerConfig(TracerConfig tracerConfig) { + this.tracerEnabled = tracerConfig.isEnabled(); + } } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java index 14ccc37c41f..5d70bee0e36 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java @@ -30,7 +30,9 @@ public final class SdkTracerProvider implements TracerProvider, Closeable { static final String DEFAULT_TRACER_NAME = ""; private final TracerSharedState sharedState; private final ComponentRegistry tracerSdkComponentRegistry; - private final ScopeConfigurator tracerConfigurator; + // deliberately not volatile because of performance concerns + // - which means its eventually consistent + private ScopeConfigurator tracerConfigurator; /** * Returns a new {@link SdkTracerProviderBuilder} for {@link SdkTracerProvider}. @@ -100,6 +102,17 @@ public Sampler getSampler() { return sharedState.getSampler(); } + // currently not public as experimental + void setScopeConfigurator(ScopeConfigurator scopeConfigurator) { + this.tracerConfigurator = scopeConfigurator; + this.tracerSdkComponentRegistry + .getComponents() + .forEach( + sdkTracer -> + sdkTracer.updateTracerConfig( + getTracerConfig(sdkTracer.getInstrumentationScopeInfo()))); + } + /** * Attempts to stop all the activity for {@link Tracer}s created by this provider. Calls {@link * SpanProcessor#shutdown()} for all registered {@link SpanProcessor}s. diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerProviderTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerProviderTest.java index 44f75373cb1..53be991c1eb 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerProviderTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerProviderTest.java @@ -18,7 +18,9 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.internal.TracerConfig; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.function.Supplier; import org.junit.jupiter.api.BeforeEach; @@ -184,6 +186,22 @@ void propagatesInstrumentationScopeInfoToTracer() { assertThat(((SdkTracer) tracer).getInstrumentationScopeInfo()).isEqualTo(expected); } + @Test + void propagatesEnablementToTracer() { + SdkTracer tracer = (SdkTracer) tracerFactory.get("test"); + boolean isEnabled = tracer.isEnabled(); + ScopeConfigurator flipConfigurator = + new ScopeConfigurator() { + @Override + public TracerConfig apply(InstrumentationScopeInfo scopeInfo) { + return isEnabled ? TracerConfig.disabled() : TracerConfig.enabled(); + } + }; + // all in the same thread, so should see enablement change immediately + tracerFactory.setScopeConfigurator(flipConfigurator); + assertThat(tracer.isEnabled()).isEqualTo(!isEnabled); + } + @Test void build_SpanLimits() { SpanLimits initialSpanLimits = SpanLimits.builder().build(); diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerTest.java index c17c121a36e..0ca18de5f15 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkTracerTest.java @@ -16,6 +16,7 @@ import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.sdk.trace.internal.TracerConfig; import java.util.Collection; import java.util.concurrent.atomic.AtomicLong; import org.junit.jupiter.api.Test; @@ -50,6 +51,14 @@ void getInstrumentationScopeInfo() { assertThat(tracer.getInstrumentationScopeInfo()).isEqualTo(instrumentationScopeInfo); } + @Test + void updateEnabled() { + tracer.updateTracerConfig(TracerConfig.disabled()); + assertThat(tracer.isEnabled()).isFalse(); + tracer.updateTracerConfig(TracerConfig.enabled()); + assertThat(tracer.isEnabled()).isTrue(); + } + @Test void propagatesInstrumentationScopeInfoToSpan() { ReadableSpan readableSpan = (ReadableSpan) tracer.spanBuilder("spanName").startSpan();