diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracer.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracer.java index 948f17e9996..45346099a5d 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracer.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracer.java @@ -10,7 +10,6 @@ import io.opentelemetry.api.incubator.propagation.ExtendedContextPropagators; import io.opentelemetry.api.internal.ApiUsageLogger; import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.Tracer; @@ -33,7 +32,7 @@ static Tracer getNoop() { } @Override - public SpanBuilder spanBuilder(String spanName) { + public ExtendedSpanBuilder spanBuilder(String spanName) { return NoopSpanBuilder.create(); } 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 index cb2cae27c24..c37ba913eb1 100644 --- 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 @@ -20,4 +20,7 @@ public interface ExtendedTracer extends Tracer { default boolean isEnabled() { return true; } + + @Override + ExtendedSpanBuilder spanBuilder(String spanName); } 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 40bf10454de..752cd279650 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 @@ -166,6 +166,7 @@ void startAndCallOrRun() { // Get a Tracer for a scope Tracer tracer = tracerProvider.get("org.foo.my-scope"); + ExtendedTracer extendedTracer = (ExtendedTracer) tracer; // Wrap the resetCheckout method in a span String cartId = @@ -173,20 +174,24 @@ void startAndCallOrRun() { .setAttribute("key123", "val456") .startAndCall(() -> resetCheckoutAndReturn("abc123", /* throwException= */ false)); assertThat(cartId).isEqualTo("abc123"); + // ...or use ExtendedTracer instance // ...or runnable variation - ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout")) + extendedTracer + .spanBuilder("reset_checkout") .startAndRun(() -> resetCheckout("abc123", /* throwException= */ false)); // Wrap the resetCheckout method in a span; resetCheckout throws an exception try { - ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout_and_return")) + extendedTracer + .spanBuilder("reset_checkout_and_return") .startAndCall(() -> resetCheckoutAndReturn("def456", /* throwException= */ true)); } catch (Throwable e) { // Ignore expected exception } // ...or runnable variation try { - ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout")) + extendedTracer + .spanBuilder("reset_checkout") .startAndRun(() -> resetCheckout("def456", /* throwException= */ true)); } catch (Throwable e) { // Ignore expected exception @@ -195,7 +200,8 @@ void startAndCallOrRun() { // Wrap the resetCheckout method in a span; resetCheckout throws an exception; use custom error // handler try { - ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout_and_return")) + extendedTracer + .spanBuilder("reset_checkout_and_return") .startAndCall( () -> resetCheckoutAndReturn("ghi789", /* throwException= */ true), (span, throwable) -> span.setAttribute("my-attribute", "error")); @@ -204,7 +210,8 @@ void startAndCallOrRun() { } // ...or runnable variation try { - ((ExtendedSpanBuilder) tracer.spanBuilder("reset_checkout")) + extendedTracer + .spanBuilder("reset_checkout") .startAndRun( () -> resetCheckout("ghi789", /* throwException= */ true), (span, throwable) -> span.setAttribute("my-attribute", "error")); diff --git a/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java b/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java index 06ddcd006e1..fd3d0162dab 100644 --- a/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java +++ b/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java @@ -7,7 +7,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.incubator.logs.ExtendedLogger; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleCounter; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGauge; @@ -18,7 +17,6 @@ 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.incubator.trace.ExtendedSpanBuilder; import io.opentelemetry.api.incubator.trace.ExtendedTracer; import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.metrics.Meter; @@ -53,7 +51,7 @@ void incubatingLogSdk() { ExtendedLogger logger = (ExtendedLogger) loggerProvider.get("logger"); logger.isEnabled(); - ((ExtendedLogRecordBuilder) logger.logRecordBuilder()).setBody("message").emit(); + logger.logRecordBuilder().setBody("message").emit(); } @Test @@ -64,7 +62,7 @@ void incubatingTraceSdk() { ExtendedTracer tracer = (ExtendedTracer) tracerProvider.get("tracer"); tracer.isEnabled(); - ((ExtendedSpanBuilder) tracer.spanBuilder("span")).startAndRun(() -> {}); + tracer.spanBuilder("span").startAndRun(() -> {}); } @Test diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/ExtendedSdkTracer.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/ExtendedSdkTracer.java index 7e339fd9a19..25de43faf88 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/ExtendedSdkTracer.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/ExtendedSdkTracer.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.trace; +import io.opentelemetry.api.incubator.trace.ExtendedSpanBuilder; import io.opentelemetry.api.incubator.trace.ExtendedTracer; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.trace.internal.TracerConfig; @@ -27,4 +28,9 @@ final class ExtendedSdkTracer extends SdkTracer implements ExtendedTracer { public boolean isEnabled() { return tracerEnabled; } + + @Override + public ExtendedSpanBuilder spanBuilder(String spanName) { + return (ExtendedSpanBuilder) super.spanBuilder(spanName); + } } 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 42210e56b28..0238d897907 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 @@ -53,6 +53,10 @@ static SdkTracer create( : new SdkTracer(sharedState, instrumentationScopeInfo, tracerConfig); } + /** + * Note that {@link ExtendedSdkTracer#spanBuilder(String)} calls this and depends on it returning + * {@link ExtendedSdkTracer} in all cases when the incubator is present. + */ @Override public SpanBuilder spanBuilder(String spanName) { if (!tracerEnabled) { @@ -62,8 +66,7 @@ public SpanBuilder spanBuilder(String spanName) { spanName = FALLBACK_SPAN_NAME; } if (sharedState.hasBeenShutdown()) { - Tracer tracer = TracerProvider.noop().get(instrumentationScopeInfo.getName()); - return tracer.spanBuilder(spanName); + return NOOP_TRACER.spanBuilder(spanName); } return INCUBATOR_AVAILABLE ? IncubatingUtil.createExtendedSpanBuilder( diff --git a/sdk/trace/src/testIncubating/java/io/opentelemetry/sdk/trace/ExtendedTracerTest.java b/sdk/trace/src/testIncubating/java/io/opentelemetry/sdk/trace/ExtendedTracerTest.java new file mode 100644 index 00000000000..c093b6da245 --- /dev/null +++ b/sdk/trace/src/testIncubating/java/io/opentelemetry/sdk/trace/ExtendedTracerTest.java @@ -0,0 +1,71 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.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.incubator.trace.ExtendedSpanBuilder; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.util.function.Supplier; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ExtendedTracerTest { + + /** + * {@link ExtendedTracer#spanBuilder(String)} delegates to {@link SdkTracer#spanBuilder(String)} + * and casts the result to {@link ExtendedSpanBuilder}. Therefore, we need to confirm that {@link + * SdkTracer#spanBuilder(String)} correctly returns {@link ExtendedSpanBuilder} and not {@link + * io.opentelemetry.api.trace.SpanBuilder} in all cases, else the user will get {@link + * ClassCastException}. + */ + @ParameterizedTest + @MethodSource("spanBuilderArgs") + void spanBuilder(Supplier spanBuilderSupplier) { + ExtendedSpanBuilder spanBuilder = spanBuilderSupplier.get(); + assertThat(spanBuilder).isInstanceOf(ExtendedSpanBuilder.class); + } + + private static Stream spanBuilderArgs() { + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(InMemorySpanExporter.create())) + .addTracerConfiguratorCondition(nameEquals("tracerB"), disabled()) + .build(); + + ExtendedTracer tracerA = (ExtendedTracer) tracerProvider.get("tracerA"); + ExtendedTracer tracerB = (ExtendedTracer) tracerProvider.get("tracerB"); + + SdkTracerProvider tracerProvider2 = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(InMemorySpanExporter.create())) + .build(); + ExtendedTracer tracerC = (ExtendedTracer) tracerProvider.get("tracerC"); + tracerProvider2.shutdown(); + + return Stream.of( + // Simple case + Arguments.of(spanBuilderSupplier(() -> tracerA.spanBuilder("span"))), + // Disabled tracer + Arguments.of(spanBuilderSupplier(() -> tracerB.spanBuilder("span"))), + // Invalid span name + Arguments.of(spanBuilderSupplier(() -> tracerB.spanBuilder(null))), + Arguments.of(spanBuilderSupplier(() -> tracerB.spanBuilder(" "))), + // Shutdown tracer provider + Arguments.of(spanBuilderSupplier(() -> tracerC.spanBuilder("span")))); + } + + private static Supplier spanBuilderSupplier( + Supplier spanBuilderSupplier) { + return spanBuilderSupplier; + } +}