diff --git a/api/incubator/README.md b/api/incubator/README.md index 84e10a2a78b..ccd4678df43 100644 --- a/api/incubator/README.md +++ b/api/incubator/README.md @@ -14,6 +14,7 @@ See [EventApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/events/Ev Features: +* Check if logger is enabled before emitting logs to avoid uneccessary computation * Set AnyValue log record body with arbitrarily complex data See [ExtendedLogsBridgeApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java). @@ -30,6 +31,7 @@ See [ExtendedMetricsApiUsageTest](./src/test/java/io/opentelemetry/api/incubator Features: +* Check if instrument is enabled before recording measurements to avoid uneccessary computation * Simplified injection / extraction of context See [ExtendedContextPropagatorsUsageTest](./src/test/java/io/opentelemetry/api/incubator/propagation/ExtendedContextPropagatorsUsageTest.java). @@ -38,6 +40,7 @@ See [ExtendedContextPropagatorsUsageTest](./src/test/java/io/opentelemetry/api/i Features: +* Check if tracer is enabled before starting spans to avoid uneccessary computation * Utility methods to reduce boilerplace using span API, including extracting context, and wrapping runnables / callables with spans See [ExtendedTraceApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java). diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java new file mode 100644 index 00000000000..db5e2a3b029 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogger.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.logs; + +import io.opentelemetry.api.logs.Logger; + +/** Extended {@link Logger} with experimental APIs. */ +public interface ExtendedLogger extends Logger { + + /** + * Returns {@code true} if the logger is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #logRecordBuilder()}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java new file mode 100644 index 00000000000..4345661ebe5 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleCounter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleCounter} with experimental APIs. */ +public interface ExtendedDoubleCounter extends DoubleCounter { + + /** + * Returns {@code true} if the counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(double)}, {@link #add(double, Attributes)}, or {@link #add(double, + * Attributes, Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java new file mode 100644 index 00000000000..d9a56f7a391 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGauge.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleGauge; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleGauge} with experimental APIs. */ +public interface ExtendedDoubleGauge extends DoubleGauge { + + /** + * Returns {@code true} if the gauge is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #set(double)}, {@link #set(double, Attributes)}, or {@link #set(double, + * Attributes, Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java new file mode 100644 index 00000000000..0a481afef2b --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleHistogram.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleHistogram} with experimental APIs. */ +public interface ExtendedDoubleHistogram extends DoubleHistogram { + + /** + * Returns {@code true} if the histogram is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #record(double)}, {@link #record(double, Attributes)}, or {@link #record(double, + * Attributes, Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java new file mode 100644 index 00000000000..6dbb91f1d6f --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleUpDownCounter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleUpDownCounter} with experimental APIs. */ +public interface ExtendedDoubleUpDownCounter extends DoubleUpDownCounter { + + /** + * Returns {@code true} if the up down counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(double)}, {@link #add(double, Attributes)}, or {@link #add(double, + * Attributes, Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java new file mode 100644 index 00000000000..0ff67a38fb9 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongCounter.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link DoubleCounter} with experimental APIs. */ +public interface ExtendedLongCounter extends LongCounter { + + /** + * Returns {@code true} if the counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(long)}, {@link #add(long, Attributes)}, or {@link #add(long, Attributes, + * Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java new file mode 100644 index 00000000000..7a660d0e007 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGauge.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.context.Context; + +/** Extended {@link LongGauge} with experimental APIs. */ +public interface ExtendedLongGauge extends LongGauge { + + /** + * Returns {@code true} if the gauge is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #set(long)}, {@link #set(long, Attributes)}, or {@link #set(long, Attributes, + * Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java new file mode 100644 index 00000000000..d1cd303fb7d --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongHistogram.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.context.Context; + +/** Extended {@link LongHistogram} with experimental APIs. */ +public interface ExtendedLongHistogram extends LongHistogram { + + /** + * Returns {@code true} if the histogram is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #record(long)}, {@link #record(long, Attributes)}, or {@link #record(long, + * Attributes, Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java new file mode 100644 index 00000000000..7327ed43842 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongUpDownCounter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.context.Context; + +/** Extended {@link LongUpDownCounter} with experimental APIs. */ +public interface ExtendedLongUpDownCounter extends LongUpDownCounter { + + /** + * Returns {@code true} if the up down counter is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #add(long)}, {@link #add(long, Attributes)}, or {@link #add(long, Attributes, + * Context)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java new file mode 100644 index 00000000000..cb2cae27c24 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedTracer.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import io.opentelemetry.api.trace.Tracer; + +/** Extended {@link Tracer} with experimental APIs. */ +public interface ExtendedTracer extends Tracer { + + /** + * Returns {@code true} if the tracer is enabled. + * + *

This allows callers to avoid unnecessary compute when nothing is consuming the data. Because + * the response is subject to change over the application, callers should call this before each + * call to {@link #spanBuilder(String)}. + */ + default boolean isEnabled() { + return true; + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java index 7a1f82e64d0..7a3d7c82e17 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java @@ -5,21 +5,82 @@ package io.opentelemetry.api.incubator.logs; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.logs.internal.LoggerConfig.disabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import com.google.common.collect.ImmutableMap; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; import io.opentelemetry.sdk.logs.internal.AnyValueBody; +import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import java.util.Random; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Logs Bridge API. */ class ExtendedLogsBridgeApiUsageTest { + @Test + void loggerEnabled() { + // Setup SdkLoggerProvider + InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); + SdkLoggerProviderBuilder loggerProviderBuilder = + SdkLoggerProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // In-memory exporter used for demonstration purposes + .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)); + // Disable loggerB + SdkLoggerProviderUtil.addLoggerConfiguratorCondition( + loggerProviderBuilder, nameEquals("loggerB"), disabled()); + SdkLoggerProvider loggerProvider = loggerProviderBuilder.build(); + + // Create loggerA and loggerB + ExtendedLogger loggerA = (ExtendedLogger) loggerProvider.get("loggerA"); + ExtendedLogger loggerB = (ExtendedLogger) loggerProvider.get("loggerB"); + + // Check if logger is enabled before emitting log and avoid unnecessary computation + if (loggerA.isEnabled()) { + loggerA + .logRecordBuilder() + .setBody("hello world!") + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .emit(); + } + if (loggerB.isEnabled()) { + loggerB + .logRecordBuilder() + .setBody("hello world!") + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .emit(); + } + + // loggerA is enabled, loggerB is disabled + assertThat(loggerA.isEnabled()).isTrue(); + assertThat(loggerB.isEnabled()).isFalse(); + + // Collected data only consists of logs from loggerA. Note, loggerB's logs would be + // omitted from the results even if logs were emitted. The check if enabled simply avoids + // unnecessary computation. + assertThat(exporter.getFinishedLogRecordItems()) + .allSatisfy( + logRecordData -> + assertThat(logRecordData.getInstrumentationScopeInfo().getName()) + .isEqualTo("loggerA")); + } + + private static final Random random = new Random(); + + private static String flipCoin() { + return random.nextBoolean() ? "heads" : "tails"; + } + @Test void extendedLogRecordBuilderUsage() { // Setup SdkLoggerProvider diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java index 5ae6297a2c7..09cda254e18 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java @@ -5,6 +5,8 @@ package io.opentelemetry.api.incubator.metrics; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; +import static io.opentelemetry.sdk.metrics.internal.MeterConfig.disabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import com.google.common.collect.ImmutableList; @@ -15,14 +17,68 @@ import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.metrics.InstrumentSelector; import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.View; +import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import java.util.Random; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Metrics API. */ class ExtendedMetricsApiUsageTest { + @Test + void meterEnabled() { + // Setup SdkMeterProvider + InMemoryMetricReader reader = InMemoryMetricReader.create(); + SdkMeterProviderBuilder meterProviderBuilder = + SdkMeterProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // In-memory reader used for demonstration purposes + .registerMetricReader(reader); + // Disable meterB + SdkMeterProviderUtil.addMeterConfiguratorCondition( + meterProviderBuilder, nameEquals("meterB"), disabled()); + SdkMeterProvider meterProvider = meterProviderBuilder.build(); + + // Create meterA and meterB, and corresponding instruments + Meter meterA = meterProvider.get("meterA"); + Meter meterB = meterProvider.get("meterB"); + ExtendedDoubleHistogram histogramA = + (ExtendedDoubleHistogram) meterA.histogramBuilder("histogramA").build(); + ExtendedDoubleHistogram histogramB = + (ExtendedDoubleHistogram) meterB.histogramBuilder("histogramB").build(); + + // Check if instrument is enabled before recording measurement and avoid unnecessary computation + if (histogramA.isEnabled()) { + histogramA.record(1.0, Attributes.builder().put("result", flipCoin()).build()); + } + if (histogramB.isEnabled()) { + histogramA.record(1.0, Attributes.builder().put("result", flipCoin()).build()); + } + + // histogramA is enabled since meterA is enabled, histogramB is disabled since meterB is + // disabled + assertThat(histogramA.isEnabled()).isTrue(); + assertThat(histogramB.isEnabled()).isFalse(); + + // Collected data only consists of metrics from meterA. Note, meterB's histogramB would be + // omitted from the results even if values were recorded. The check if enabled simply avoids + // unnecessary computation. + assertThat(reader.collectAllMetrics()) + .allSatisfy( + metric -> + assertThat(metric.getInstrumentationScopeInfo().getName()).isEqualTo("meterA")); + } + + private static final Random random = new Random(); + + private static String flipCoin() { + return random.nextBoolean() ? "heads" : "tails"; + } + @Test void attributesAdvice() { // Setup SdkMeterProvider diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java index 3922cba7f8b..40bf10454de 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java @@ -5,9 +5,12 @@ package io.opentelemetry.api.incubator.trace; +import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.trace.internal.TracerConfig.disabled; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.TraceFlags; @@ -21,16 +24,73 @@ import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.IdGenerator; import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import io.opentelemetry.sdk.trace.internal.SdkTracerProviderUtil; import java.util.HashMap; import java.util.Map; +import java.util.Random; import java.util.function.BiConsumer; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Trace API. */ class ExtendedTraceApiUsageTest { + @Test + void tracerEnabled() { + // Setup SdkTracerProvider + InMemorySpanExporter exporter = InMemorySpanExporter.create(); + SdkTracerProviderBuilder tracerProviderBuilder = + SdkTracerProvider.builder() + // Default resource used for demonstration purposes + .setResource(Resource.getDefault()) + // In-memory exporter used for demonstration purposes + .addSpanProcessor(SimpleSpanProcessor.create(exporter)); + // Disable tracerB + SdkTracerProviderUtil.addTracerConfiguratorCondition( + tracerProviderBuilder, nameEquals("tracerB"), disabled()); + SdkTracerProvider tracerProvider = tracerProviderBuilder.build(); + + // Create tracerA and tracerB + ExtendedTracer tracerA = (ExtendedTracer) tracerProvider.get("tracerA"); + ExtendedTracer tracerB = (ExtendedTracer) tracerProvider.get("tracerB"); + + // Check if tracer is enabled before recording span and avoid unnecessary computation + if (tracerA.isEnabled()) { + tracerA + .spanBuilder("span name") + .startSpan() + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .end(); + } + if (tracerB.isEnabled()) { + tracerB + .spanBuilder("span name") + .startSpan() + .setAllAttributes(Attributes.builder().put("result", flipCoin()).build()) + .end(); + } + + // tracerA is enabled, tracerB is disabled + assertThat(tracerA.isEnabled()).isTrue(); + assertThat(tracerB.isEnabled()).isFalse(); + + // Collected data only consists of spans from tracerA. Note, tracerB's spans would be + // omitted from the results even if spans were recorded. The check if enabled simply avoids + // unnecessary computation. + assertThat(exporter.getFinishedSpanItems()) + .allSatisfy( + spanData -> + assertThat(spanData.getInstrumentationScopeInfo().getName()).isEqualTo("tracerA")); + } + + private static final Random random = new Random(); + + private static String flipCoin() { + return random.nextBoolean() ? "heads" : "tails"; + } + /** Demonstrates {@link ExtendedSpanBuilder#setParentFrom(ContextPropagators, Map)}. */ @Test void setParentFrom() { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index 74bad693bfa..72fb9f0b356 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.logs; +import io.opentelemetry.api.incubator.logs.ExtendedLogger; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; @@ -12,13 +13,13 @@ import io.opentelemetry.sdk.logs.internal.LoggerConfig; /** SDK implementation of {@link Logger}. */ -final class SdkLogger implements Logger { +final class SdkLogger implements ExtendedLogger { private static final Logger NOOP_LOGGER = LoggerProvider.noop().get("noop"); private final LoggerSharedState loggerSharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; - private final LoggerConfig loggerConfig; + private final boolean loggerEnabled; SdkLogger( LoggerSharedState loggerSharedState, @@ -26,12 +27,12 @@ final class SdkLogger implements Logger { LoggerConfig loggerConfig) { this.loggerSharedState = loggerSharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; - this.loggerConfig = loggerConfig; + this.loggerEnabled = loggerConfig.isEnabled(); } @Override public LogRecordBuilder logRecordBuilder() { - if (loggerConfig.isEnabled()) { + if (loggerEnabled) { return new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); } return NOOP_LOGGER.logRecordBuilder(); @@ -41,4 +42,9 @@ public LogRecordBuilder logRecordBuilder() { InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + + @Override + public boolean isEnabled() { + return loggerEnabled; + } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 371098267eb..f94b97388b4 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -11,6 +11,7 @@ import static io.opentelemetry.sdk.logs.internal.LoggerConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import io.opentelemetry.api.incubator.logs.ExtendedLogger; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ScopeConfigurator; @@ -59,6 +60,10 @@ void disableScopes() { assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerB"))).isNull(); assertThat(logsByScope.get(InstrumentationScopeInfo.create("loggerC"))).hasSize(1); }); + // loggerA and loggerC are enabled, loggerB is disabled. + assertThat(((ExtendedLogger) loggerA).isEnabled()).isTrue(); + assertThat(((ExtendedLogger) loggerB).isEnabled()).isFalse(); + assertThat(((ExtendedLogger) loggerC).isEnabled()).isTrue(); } @ParameterizedTest diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java index f1da522e15b..afed0778796 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentBuilder.java @@ -17,7 +17,6 @@ import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage; import java.util.Collections; import java.util.List; -import java.util.function.BiFunction; import java.util.function.Consumer; /** Helper to make implementing builders easier. */ @@ -65,12 +64,21 @@ T swapBuilder(SwapBuilder swapper) { meterProviderSharedState, meterSharedState, name, description, unit, adviceBuilder); } + @FunctionalInterface + interface SynchronousInstrumentConstructor { + + I createInstrument( + InstrumentDescriptor instrumentDescriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage); + } + I buildSynchronousInstrument( - BiFunction instrumentFactory) { + SynchronousInstrumentConstructor instrumentFactory) { InstrumentDescriptor descriptor = newDescriptor(); WriteableMetricStorage storage = meterSharedState.registerSynchronousMetricStorage(descriptor, meterProviderSharedState); - return instrumentFactory.apply(descriptor, storage); + return instrumentFactory.createInstrument(descriptor, meterSharedState, storage); } SdkObservableInstrument buildDoubleAsynchronousInstrument( diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java index d7aa5f47cad..5e4eb4a7ef5 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounter; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounterBuilder; -import io.opentelemetry.api.metrics.DoubleCounter; import io.opentelemetry.api.metrics.DoubleCounterBuilder; import io.opentelemetry.api.metrics.ObservableDoubleCounter; import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; @@ -24,14 +24,19 @@ import java.util.logging.Level; import java.util.logging.Logger; -final class SdkDoubleCounter extends AbstractInstrument implements DoubleCounter { +final class SdkDoubleCounter extends AbstractInstrument implements ExtendedDoubleCounter { private static final Logger logger = Logger.getLogger(SdkDoubleCounter.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -58,6 +63,11 @@ public void add(double increment) { add(increment, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleCounterBuilder implements ExtendedDoubleCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java index 1c834b18e10..8cc9d468257 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGauge; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGaugeBuilder; -import io.opentelemetry.api.metrics.DoubleGauge; import io.opentelemetry.api.metrics.DoubleGaugeBuilder; import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableDoubleGauge; @@ -21,12 +21,17 @@ import java.util.List; import java.util.function.Consumer; -final class SdkDoubleGauge extends AbstractInstrument implements DoubleGauge { +final class SdkDoubleGauge extends AbstractInstrument implements ExtendedDoubleGauge { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleGauge(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleGauge( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +50,11 @@ public void set(double increment) { set(increment, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleGaugeBuilder implements ExtendedDoubleGaugeBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java index 15dd7d2f8c7..4861a631ab7 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogram; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogramBuilder; -import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.DoubleHistogramBuilder; import io.opentelemetry.api.metrics.LongHistogramBuilder; import io.opentelemetry.context.Context; @@ -23,14 +23,19 @@ import java.util.logging.Level; import java.util.logging.Logger; -final class SdkDoubleHistogram extends AbstractInstrument implements DoubleHistogram { +final class SdkDoubleHistogram extends AbstractInstrument implements ExtendedDoubleHistogram { private static final Logger logger = Logger.getLogger(SdkDoubleHistogram.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleHistogram(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleHistogram( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -57,6 +62,11 @@ public void record(double value) { record(value, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleHistogramBuilder implements ExtendedDoubleHistogramBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java index 57188aa6a23..da6316d6b77 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleUpDownCounter; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleUpDownCounterBuilder; import io.opentelemetry.api.metrics.DoubleUpDownCounter; import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder; @@ -21,12 +22,18 @@ import java.util.List; import java.util.function.Consumer; -final class SdkDoubleUpDownCounter extends AbstractInstrument implements DoubleUpDownCounter { +final class SdkDoubleUpDownCounter extends AbstractInstrument + implements ExtendedDoubleUpDownCounter { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkDoubleUpDownCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkDoubleUpDownCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +52,11 @@ public void add(double increment) { add(increment, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkDoubleUpDownCounterBuilder implements ExtendedDoubleUpDownCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java index 3847bf716f3..91b52fee7fd 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongCounter.java @@ -7,9 +7,9 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongCounter; import io.opentelemetry.api.incubator.metrics.ExtendedLongCounterBuilder; import io.opentelemetry.api.metrics.DoubleCounterBuilder; -import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongCounterBuilder; import io.opentelemetry.api.metrics.ObservableLongCounter; import io.opentelemetry.api.metrics.ObservableLongMeasurement; @@ -24,15 +24,20 @@ import java.util.logging.Level; import java.util.logging.Logger; -final class SdkLongCounter extends AbstractInstrument implements LongCounter { +final class SdkLongCounter extends AbstractInstrument implements ExtendedLongCounter { private static final Logger logger = Logger.getLogger(SdkLongCounter.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -59,6 +64,11 @@ public void add(long increment) { add(increment, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongCounterBuilder implements ExtendedLongCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java index ad7db428bdf..62ab826df87 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongGauge; import io.opentelemetry.api.incubator.metrics.ExtendedLongGaugeBuilder; -import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableLongGauge; import io.opentelemetry.api.metrics.ObservableLongMeasurement; @@ -21,12 +21,17 @@ import java.util.List; import java.util.function.Consumer; -final class SdkLongGauge extends AbstractInstrument implements LongGauge { +final class SdkLongGauge extends AbstractInstrument implements ExtendedLongGauge { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongGauge(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongGauge( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +50,11 @@ public void set(long increment) { set(increment, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongGaugeBuilder implements ExtendedLongGaugeBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java index b2975886565..ef8ee31e707 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongHistogram.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogram; import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogramBuilder; -import io.opentelemetry.api.metrics.LongHistogram; import io.opentelemetry.api.metrics.LongHistogramBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.internal.ThrottlingLogger; @@ -24,14 +24,19 @@ import java.util.logging.Logger; import java.util.stream.Collectors; -final class SdkLongHistogram extends AbstractInstrument implements LongHistogram { +final class SdkLongHistogram extends AbstractInstrument implements ExtendedLongHistogram { private static final Logger logger = Logger.getLogger(SdkLongHistogram.class.getName()); private final ThrottlingLogger throttlingLogger = new ThrottlingLogger(logger); + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongHistogram(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongHistogram( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -58,6 +63,11 @@ public void record(long value) { record(value, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongHistogramBuilder implements ExtendedLongHistogramBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java index 4530f3b8405..a74ac786d1a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongUpDownCounter.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.metrics.ExtendedLongUpDownCounter; import io.opentelemetry.api.incubator.metrics.ExtendedLongUpDownCounterBuilder; import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder; import io.opentelemetry.api.metrics.LongUpDownCounter; @@ -21,12 +22,17 @@ import java.util.List; import java.util.function.Consumer; -final class SdkLongUpDownCounter extends AbstractInstrument implements LongUpDownCounter { +final class SdkLongUpDownCounter extends AbstractInstrument implements ExtendedLongUpDownCounter { + private final MeterSharedState meterSharedState; private final WriteableMetricStorage storage; - private SdkLongUpDownCounter(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + private SdkLongUpDownCounter( + InstrumentDescriptor descriptor, + MeterSharedState meterSharedState, + WriteableMetricStorage storage) { super(descriptor); + this.meterSharedState = meterSharedState; this.storage = storage; } @@ -45,6 +51,11 @@ public void add(long increment) { add(increment, Attributes.empty()); } + @Override + public boolean isEnabled() { + return meterSharedState.isMeterEnabled() && storage.isEnabled(); + } + static final class SdkLongUpDownCounterBuilder implements ExtendedLongUpDownCounterBuilder { private final InstrumentBuilder builder; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java index bb76fe6701a..da57ef3506c 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java @@ -56,7 +56,6 @@ final class SdkMeter implements Meter { private final InstrumentationScopeInfo instrumentationScopeInfo; private final MeterProviderSharedState meterProviderSharedState; private final MeterSharedState meterSharedState; - private final MeterConfig meterConfig; SdkMeter( MeterProviderSharedState meterProviderSharedState, @@ -65,8 +64,8 @@ final class SdkMeter implements Meter { MeterConfig meterConfig) { this.instrumentationScopeInfo = instrumentationScopeInfo; this.meterProviderSharedState = meterProviderSharedState; - this.meterSharedState = MeterSharedState.create(instrumentationScopeInfo, registeredReaders); - this.meterConfig = meterConfig; + this.meterSharedState = + MeterSharedState.create(instrumentationScopeInfo, registeredReaders, meterConfig); } // Visible for testing @@ -86,14 +85,14 @@ void resetForTest() { @Override public LongCounterBuilder counterBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkLongCounter.SdkLongCounterBuilder(meterProviderSharedState, meterSharedState, name) : NOOP_METER.counterBuilder(NOOP_INSTRUMENT_NAME); } @Override public LongUpDownCounterBuilder upDownCounterBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkLongUpDownCounter.SdkLongUpDownCounterBuilder( meterProviderSharedState, meterSharedState, name) : NOOP_METER.upDownCounterBuilder(NOOP_INSTRUMENT_NAME); @@ -101,7 +100,7 @@ public LongUpDownCounterBuilder upDownCounterBuilder(String name) { @Override public DoubleHistogramBuilder histogramBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkDoubleHistogram.SdkDoubleHistogramBuilder( meterProviderSharedState, meterSharedState, name) : NOOP_METER.histogramBuilder(NOOP_INSTRUMENT_NAME); @@ -109,7 +108,7 @@ public DoubleHistogramBuilder histogramBuilder(String name) { @Override public DoubleGaugeBuilder gaugeBuilder(String name) { - return meterConfig.isEnabled() && checkValidInstrumentName(name) + return checkValidInstrumentName(name) ? new SdkDoubleGauge.SdkDoubleGaugeBuilder(meterProviderSharedState, meterSharedState, name) : NOOP_METER.gaugeBuilder(NOOP_INSTRUMENT_NAME); } @@ -119,9 +118,6 @@ public BatchCallback batchCallback( Runnable callback, ObservableMeasurement observableMeasurement, ObservableMeasurement... additionalMeasurements) { - if (!meterConfig.isEnabled()) { - return NOOP_METER.batchCallback(callback, observableMeasurement, additionalMeasurements); - } Set measurements = new HashSet<>(); measurements.add(observableMeasurement); Collections.addAll(measurements, additionalMeasurements); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java index 191223bfeac..c0deda9d068 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java @@ -131,6 +131,11 @@ public void recordDouble(double value, Attributes attributes, Context context) { } } + @Override + public boolean isEnabled() { + return true; + } + /** * Obtain the AggregatorHolder for recording measurements, re-reading the volatile * this.aggregatorHolder until we access one where recordsInProgress is even. Collect sets diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java index d076178d193..faaa7087c76 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/EmptyMetricStorage.java @@ -39,4 +39,9 @@ public void recordLong(long value, Attributes attributes, Context context) {} @Override public void recordDouble(double value, Attributes attributes, Context context) {} + + @Override + public boolean isEnabled() { + return false; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java index 64ecefd5385..30a3a838c45 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java @@ -11,11 +11,13 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -36,20 +38,25 @@ public class MeterSharedState { private final List callbackRegistrations = new ArrayList<>(); private final Map readerStorageRegistries; - private final InstrumentationScopeInfo instrumentationScopeInfo; + private final boolean meterEnabled; private MeterSharedState( - InstrumentationScopeInfo instrumentationScopeInfo, List registeredReaders) { + InstrumentationScopeInfo instrumentationScopeInfo, + List registeredReaders, + MeterConfig meterConfig) { this.instrumentationScopeInfo = instrumentationScopeInfo; this.readerStorageRegistries = registeredReaders.stream() .collect(toMap(Function.identity(), unused -> new MetricStorageRegistry())); + this.meterEnabled = meterConfig.isEnabled(); } public static MeterSharedState create( - InstrumentationScopeInfo instrumentationScopeInfo, List registeredReaders) { - return new MeterSharedState(instrumentationScopeInfo, registeredReaders); + InstrumentationScopeInfo instrumentationScopeInfo, + List registeredReaders, + MeterConfig meterConfig) { + return new MeterSharedState(instrumentationScopeInfo, registeredReaders, meterConfig); } /** @@ -81,11 +88,20 @@ public InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + /** Returns {@code true} if the {@link MeterConfig#enabled()} of the meter is {@code true}. */ + public boolean isMeterEnabled() { + return meterEnabled; + } + /** Collects all metrics. */ public List collectAll( RegisteredReader registeredReader, MeterProviderSharedState meterProviderSharedState, long epochNanos) { + // Short circuit collection process if meter is disabled + if (!meterEnabled) { + return Collections.emptyList(); + } List currentRegisteredCallbacks; synchronized (callbackLock) { currentRegisteredCallbacks = new ArrayList<>(callbackRegistrations); @@ -113,7 +129,7 @@ public List collectAll( result.add(current); } } - return result; + return Collections.unmodifiableList(result); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java index 59632a9cc4a..700fee4c3fb 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MultiWritableMetricStorage.java @@ -29,4 +29,14 @@ public void recordDouble(double value, Attributes attributes, Context context) { storage.recordDouble(value, attributes, context); } } + + @Override + public boolean isEnabled() { + for (WriteableMetricStorage storage : storages) { + if (storage.isEnabled()) { + return true; + } + } + return false; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java index 77e2dd510b8..7191a63f1e0 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java @@ -22,4 +22,10 @@ public interface WriteableMetricStorage { /** Records a measurement. */ void recordDouble(double value, Attributes attributes, Context context); + + /** + * Returns {@code true} if the storage is actively recording measurements, and {@code false} + * otherwise (i.e. noop / empty metric storage is installed). + */ + boolean isEnabled(); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java index a351c95d0e6..c6ef1957428 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; @@ -24,7 +25,7 @@ class InstrumentBuilderTest { TestClock.create(), Resource.getDefault(), ExemplarFilter.alwaysOff(), 0); static final InstrumentationScopeInfo SCOPE = InstrumentationScopeInfo.create("scope-name"); public static final MeterSharedState METER_SHARED_STATE = - MeterSharedState.create(SCOPE, Collections.emptyList()); + MeterSharedState.create(SCOPE, Collections.emptyList(), MeterConfig.defaultConfig()); @Test void stringRepresentation() { diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java index 3b78f2abd0d..aaaeaf5f85d 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/MeterConfigTest.java @@ -11,7 +11,16 @@ import static io.opentelemetry.sdk.metrics.internal.MeterConfig.disabled; import static io.opentelemetry.sdk.metrics.internal.MeterConfig.enabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static java.util.stream.Collectors.groupingBy; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounter; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGauge; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleHistogram; +import io.opentelemetry.api.incubator.metrics.ExtendedDoubleUpDownCounter; +import io.opentelemetry.api.incubator.metrics.ExtendedLongCounter; +import io.opentelemetry.api.incubator.metrics.ExtendedLongGauge; +import io.opentelemetry.api.incubator.metrics.ExtendedLongHistogram; +import io.opentelemetry.api.incubator.metrics.ExtendedLongUpDownCounter; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ScopeConfigurator; @@ -20,7 +29,7 @@ import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -37,50 +46,136 @@ void disableScopes() { // Disable meterB. Since meters are enabled by default, meterA and meterC are enabled. .addMeterConfiguratorCondition(nameEquals("meterB"), disabled()) .registerMetricReader(reader) + // Register drop aggregation for all instruments of meterD. Instruments are disabled if + // their relevant MeterConfig is disabled, or if there are no resolved views which + // consume the measurements. + .registerView( + InstrumentSelector.builder().setMeterName("meterD").build(), + View.builder().setAggregation(Aggregation.drop()).build()) .build(); Meter meterA = meterProvider.get("meterA"); Meter meterB = meterProvider.get("meterB"); Meter meterC = meterProvider.get("meterC"); + Meter meterD = meterProvider.get("meterD"); + AtomicLong meterAInvocations = new AtomicLong(); + AtomicLong meterBInvocations = new AtomicLong(); + AtomicLong meterCInvocations = new AtomicLong(); + AtomicLong meterDInvocations = new AtomicLong(); - meterA.counterBuilder("counterA").build().add(1); - meterA.counterBuilder("asyncCounterA").buildWithCallback(observable -> observable.record(1)); - meterA.upDownCounterBuilder("upDownCounterA").build().add(1); - meterA - .upDownCounterBuilder("asyncUpDownCounterA") - .buildWithCallback(observable -> observable.record(1)); - meterA.histogramBuilder("histogramA").build().record(1.0); - meterA.gaugeBuilder("gaugeA").buildWithCallback(observable -> observable.record(1.0)); - - meterB.counterBuilder("counterB").build().add(1); - meterB.counterBuilder("asyncCounterB").buildWithCallback(observable -> observable.record(1)); - meterB.upDownCounterBuilder("upDownCounterB").build().add(1); - meterB - .upDownCounterBuilder("asyncUpDownCounterB") - .buildWithCallback(observable -> observable.record(1)); - meterB.histogramBuilder("histogramB").build().record(1.0); - meterB.gaugeBuilder("gaugeB").buildWithCallback(observable -> observable.record(1.0)); - - meterC.counterBuilder("counterC").build().add(1); - meterC.counterBuilder("asyncCounterC").buildWithCallback(observable -> observable.record(1)); - meterC.upDownCounterBuilder("upDownCounterC").build().add(1); - meterC - .upDownCounterBuilder("asyncUpDownCounterC") - .buildWithCallback(observable -> observable.record(1)); - meterC.histogramBuilder("histogramC").build().record(1.0); - meterC.gaugeBuilder("gaugeC").buildWithCallback(observable -> observable.record(1.0)); + // Record measurements to each instrument type + recordToMeterInstruments(meterA, meterAInvocations); + recordToMeterInstruments(meterB, meterBInvocations); + recordToMeterInstruments(meterC, meterCInvocations); + recordToMeterInstruments(meterD, meterDInvocations); // Only metrics from meterA and meterC should be seen assertThat(reader.collectAllMetrics()) .satisfies( metrics -> { Map> metricsByScope = - metrics.stream() - .collect(Collectors.groupingBy(MetricData::getInstrumentationScopeInfo)); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterA"))).hasSize(6); + metrics.stream().collect(groupingBy(MetricData::getInstrumentationScopeInfo)); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterA"))).hasSize(14); assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterB"))).isNull(); - assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterC"))).hasSize(6); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterC"))).hasSize(14); + assertThat(metricsByScope.get(InstrumentationScopeInfo.create("meterD"))).isNull(); + }); + // Only async callbacks from meterA and meterC should be invoked + assertThat(meterAInvocations.get()).isPositive(); + assertThat(meterBInvocations.get()).isZero(); + assertThat(meterCInvocations.get()).isPositive(); + assertThat(meterDInvocations.get()).isZero(); + // Instruments from meterA and meterC are enabled, meterC is not enabled + assertMeterInstrumentsEnabled(meterA, /* expectedEnabled= */ true); + assertMeterInstrumentsEnabled(meterB, /* expectedEnabled= */ false); + assertMeterInstrumentsEnabled(meterC, /* expectedEnabled= */ true); + assertMeterInstrumentsEnabled(meterD, /* expectedEnabled= */ false); + } + + private static void recordToMeterInstruments(Meter meter, AtomicLong asyncInvocationsCount) { + meter.counterBuilder("longCounter").build().add(1); + meter.counterBuilder("doubleCounter").ofDoubles().build().add(1); + meter + .counterBuilder("asyncLongCounter") + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + meter + .counterBuilder("asyncDoubleCounter") + .ofDoubles() + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); }); + meter.upDownCounterBuilder("longUpDownCounter").build().add(1); + meter.upDownCounterBuilder("doubleUpDownCounter").ofDoubles().build().add(1); + meter + .upDownCounterBuilder("asyncLongUpDownCounter") + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + meter + .upDownCounterBuilder("asyncDoubleUpDownCounter") + .ofDoubles() + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + meter.histogramBuilder("doubleHistogram").build().record(1.0); + meter.histogramBuilder("longHistogram").ofLongs().build().record(1); + meter.gaugeBuilder("doubleGauge").build().set(1); + meter.gaugeBuilder("longGauge").ofLongs().build().set(1); + meter + .gaugeBuilder("asyncDoubleGauge") + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1.0); + }); + meter + .gaugeBuilder("asyncLongGauge") + .ofLongs() + .buildWithCallback( + observable -> { + asyncInvocationsCount.incrementAndGet(); + observable.record(1); + }); + } + + private static void assertMeterInstrumentsEnabled(Meter meter, boolean expectedEnabled) { + assertThat( + ((ExtendedDoubleCounter) meter.counterBuilder("doubleCounter").ofDoubles().build()) + .isEnabled()) + .isEqualTo(expectedEnabled); + assertThat(((ExtendedLongCounter) meter.counterBuilder("longCounter").build()).isEnabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedDoubleUpDownCounter) + meter.upDownCounterBuilder("doubleUpDownCounter").ofDoubles().build()) + .isEnabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedLongUpDownCounter) meter.upDownCounterBuilder("longUpDownCounter").build()) + .isEnabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedDoubleHistogram) meter.histogramBuilder("doubleHistogram").build()) + .isEnabled()) + .isEqualTo(expectedEnabled); + assertThat( + ((ExtendedLongHistogram) meter.histogramBuilder("longHistogram").ofLongs().build()) + .isEnabled()) + .isEqualTo(expectedEnabled); + assertThat(((ExtendedDoubleGauge) meter.gaugeBuilder("doubleGauge").build()).isEnabled()) + .isEqualTo(expectedEnabled); + assertThat(((ExtendedLongGauge) meter.gaugeBuilder("longGauge").ofLongs().build()).isEnabled()) + .isEqualTo(expectedEnabled); } @ParameterizedTest diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java index a2b9e60a60f..03e52331dc7 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java @@ -13,6 +13,7 @@ import io.github.netmikey.logunit.api.LogCapturer; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.CallbackRegistration; @@ -36,7 +37,11 @@ class SdkObservableInstrumentTest { @BeforeEach void setup() { meterSharedState = - spy(MeterSharedState.create(InstrumentationScopeInfo.empty(), Collections.emptyList())); + spy( + MeterSharedState.create( + InstrumentationScopeInfo.empty(), + Collections.emptyList(), + MeterConfig.defaultConfig())); callbackRegistration = CallbackRegistration.create( Collections.singletonList( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java index 8b664ad5d3e..99a26106a78 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java @@ -114,5 +114,10 @@ public void recordLong(long value, Attributes attributes, Context context) {} @Override public void recordDouble(double value, Attributes attributes, Context context) {} + + @Override + public boolean isEnabled() { + return true; + } } } 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 a0b2704fc72..cd8c7ca2471 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 @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.trace; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.TracerProvider; @@ -12,13 +13,13 @@ import io.opentelemetry.sdk.trace.internal.TracerConfig; /** {@link SdkTracer} is SDK implementation of {@link Tracer}. */ -final class SdkTracer implements Tracer { +final class SdkTracer implements ExtendedTracer { static final String FALLBACK_SPAN_NAME = ""; private static final Tracer NOOP_TRACER = TracerProvider.noop().get("noop"); private final TracerSharedState sharedState; private final InstrumentationScopeInfo instrumentationScopeInfo; - private final TracerConfig tracerConfig; + private final boolean tracerEnabled; SdkTracer( TracerSharedState sharedState, @@ -26,12 +27,12 @@ final class SdkTracer implements Tracer { TracerConfig tracerConfig) { this.sharedState = sharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; - this.tracerConfig = tracerConfig; + this.tracerEnabled = tracerConfig.isEnabled(); } @Override public SpanBuilder spanBuilder(String spanName) { - if (!tracerConfig.isEnabled()) { + if (!tracerEnabled) { return NOOP_TRACER.spanBuilder(spanName); } if (spanName == null || spanName.trim().isEmpty()) { @@ -49,4 +50,9 @@ public SpanBuilder spanBuilder(String spanName) { InstrumentationScopeInfo getInstrumentationScopeInfo() { return instrumentationScopeInfo; } + + @Override + public boolean isEnabled() { + return tracerEnabled; + } } diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java index 4df99b4c999..4421185aeea 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/TracerConfigTest.java @@ -13,6 +13,7 @@ import static io.opentelemetry.sdk.trace.internal.TracerConfig.enabled; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanId; import io.opentelemetry.api.trace.Tracer; @@ -90,6 +91,10 @@ void disableScopes() throws InterruptedException { .hasSpanId(grandchild.getSpanContext().getSpanId()) .hasParentSpanId(parent.getSpanContext().getSpanId()) .hasAttributes(Attributes.builder().put("c", "1").build())); + // tracerA and tracerC are enabled, tracerB is disabled. + assertThat(((ExtendedTracer) tracerA).isEnabled()).isTrue(); + assertThat(((ExtendedTracer) tracerB).isEnabled()).isFalse(); + assertThat(((ExtendedTracer) tracerA).isEnabled()).isTrue(); } @ParameterizedTest