diff --git a/api/all/build.gradle.kts b/api/all/build.gradle.kts index 4998fd9ddd3..6ade72dfd88 100644 --- a/api/all/build.gradle.kts +++ b/api/all/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("otel.java-conventions") id("otel.publish-conventions") + id("java-test-fixtures") id("otel.jmh-conventions") id("otel.animalsniffer-conventions") @@ -17,6 +18,10 @@ dependencies { testImplementation("edu.berkeley.cs.jqf:jqf-fuzz") testImplementation("com.google.guava:guava-testlib") + testFixturesApi(project(":testing-internal")) + testFixturesApi("junit:junit") + testFixturesApi("org.assertj:assertj-core") + testFixturesApi("org.mockito:mockito-core") } tasks.test { diff --git a/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java b/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java new file mode 100644 index 00000000000..1ef82d373f2 --- /dev/null +++ b/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.internal; + +import java.lang.reflect.Method; + +/** + * Incubating utilities. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class IncubatingUtil { + private IncubatingUtil() {} + + @SuppressWarnings("unchecked") + public static T incubatingApiIfAvailable(T stableApi, String incubatingClassName) { + try { + Class incubatingClass = Class.forName(incubatingClassName); + Method getInstance = incubatingClass.getDeclaredMethod("getNoop"); + return (T) getInstance.invoke(null); + } catch (Exception e) { + return stableApi; + } + } +} diff --git a/api/all/src/main/java/io/opentelemetry/api/logs/LoggerProvider.java b/api/all/src/main/java/io/opentelemetry/api/logs/LoggerProvider.java index d00cb310ffc..5bad7eeee51 100644 --- a/api/all/src/main/java/io/opentelemetry/api/logs/LoggerProvider.java +++ b/api/all/src/main/java/io/opentelemetry/api/logs/LoggerProvider.java @@ -5,6 +5,7 @@ package io.opentelemetry.api.logs; +import io.opentelemetry.api.internal.IncubatingUtil; import javax.annotation.concurrent.ThreadSafe; /** @@ -43,6 +44,8 @@ default Logger get(String instrumentationScopeName) { /** Returns a no-op {@link LoggerProvider} which provides Loggers which do not record or emit. */ static LoggerProvider noop() { - return DefaultLoggerProvider.getInstance(); + return IncubatingUtil.incubatingApiIfAvailable( + DefaultLoggerProvider.getInstance(), + "io.opentelemetry.api.incubator.logs.ExtendedDefaultLoggerProvider"); } } diff --git a/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeterProvider.java b/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeterProvider.java index 6d1a6de3d48..3ea78ec2d34 100644 --- a/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeterProvider.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeterProvider.java @@ -5,6 +5,8 @@ package io.opentelemetry.api.metrics; +import io.opentelemetry.api.internal.IncubatingUtil; + /** A {@link MeterProvider} that does nothing. */ class DefaultMeterProvider implements MeterProvider { @Override @@ -12,7 +14,10 @@ public MeterBuilder meterBuilder(String instrumentationScopeName) { return BUILDER_INSTANCE; } - private static final DefaultMeterProvider INSTANCE = new DefaultMeterProvider(); + private static final MeterProvider INSTANCE = + IncubatingUtil.incubatingApiIfAvailable( + new DefaultMeterProvider(), + "io.opentelemetry.api.incubator.metrics.ExtendedDefaultMeterProvider"); private static final MeterBuilder BUILDER_INSTANCE = new NoopMeterBuilder(); static MeterProvider getInstance() { diff --git a/api/all/src/main/java/io/opentelemetry/api/trace/DefaultTracerProvider.java b/api/all/src/main/java/io/opentelemetry/api/trace/DefaultTracerProvider.java index 97ddbe0c7b8..9bef6cf9928 100644 --- a/api/all/src/main/java/io/opentelemetry/api/trace/DefaultTracerProvider.java +++ b/api/all/src/main/java/io/opentelemetry/api/trace/DefaultTracerProvider.java @@ -5,12 +5,16 @@ package io.opentelemetry.api.trace; +import io.opentelemetry.api.internal.IncubatingUtil; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe class DefaultTracerProvider implements TracerProvider { - private static final TracerProvider INSTANCE = new DefaultTracerProvider(); + private static final TracerProvider INSTANCE = + IncubatingUtil.incubatingApiIfAvailable( + new DefaultTracerProvider(), + "io.opentelemetry.api.incubator.trace.ExtendedDefaultTracerProvider"); static TracerProvider getInstance() { return INSTANCE; diff --git a/api/all/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java b/api/all/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java index 42a4cd31476..c3754a6df3b 100644 --- a/api/all/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java @@ -5,100 +5,24 @@ package io.opentelemetry.api; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; - import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.api.trace.TracerProvider; -import io.opentelemetry.context.propagation.ContextPropagators; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -class OpenTelemetryTest { - - @BeforeAll - static void beforeClass() { - GlobalOpenTelemetry.resetForTest(); - } - - @AfterEach - void after() { - GlobalOpenTelemetry.resetForTest(); - } - - @Test - void testDefault() { - assertThat(OpenTelemetry.noop().getTracerProvider()).isSameAs(TracerProvider.noop()); - assertThat(OpenTelemetry.noop().getPropagators()).isSameAs(ContextPropagators.noop()); - assertThat(OpenTelemetry.noop().getMeterProvider()).isSameAs(MeterProvider.noop()); - assertThat(OpenTelemetry.noop().getLogsBridge()).isSameAs(LoggerProvider.noop()); - } - @Test - void propagating() { - ContextPropagators contextPropagators = mock(ContextPropagators.class); - OpenTelemetry openTelemetry = OpenTelemetry.propagating(contextPropagators); - - assertThat(openTelemetry.getTracerProvider()).isSameAs(TracerProvider.noop()); - assertThat(openTelemetry.getMeterProvider()).isSameAs(MeterProvider.noop()); - assertThat(openTelemetry.getLogsBridge()).isSameAs(LoggerProvider.noop()); - assertThat(openTelemetry.getPropagators()).isSameAs(contextPropagators); - } - - @Test - void testGlobalBeforeSet() { - assertThat(GlobalOpenTelemetry.getTracerProvider()).isSameAs(TracerProvider.noop()); - assertThat(GlobalOpenTelemetry.getTracerProvider()) - .isSameAs(GlobalOpenTelemetry.getTracerProvider()); - assertThat(GlobalOpenTelemetry.getPropagators()).isSameAs(GlobalOpenTelemetry.getPropagators()); - } - - @Test - void independentNonGlobalPropagators() { - ContextPropagators propagators1 = mock(ContextPropagators.class); - OpenTelemetry otel1 = OpenTelemetry.propagating(propagators1); - ContextPropagators propagators2 = mock(ContextPropagators.class); - OpenTelemetry otel2 = OpenTelemetry.propagating(propagators2); - - assertThat(otel1.getPropagators()).isSameAs(propagators1); - assertThat(otel2.getPropagators()).isSameAs(propagators2); - } - - @Test - void setThenSet() { - setOpenTelemetry(); - assertThatThrownBy(() -> GlobalOpenTelemetry.set(OpenTelemetry.noop())) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("GlobalOpenTelemetry.set has already been called") - .hasStackTraceContaining("setOpenTelemetry"); - } - - @Test - void getThenSet() { - assertThat(getOpenTelemetry()).isInstanceOf(DefaultOpenTelemetry.class); - assertThatThrownBy(() -> GlobalOpenTelemetry.set(OpenTelemetry.noop())) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("GlobalOpenTelemetry.set has already been called") - .hasStackTraceContaining("getOpenTelemetry"); - } +class OpenTelemetryTest extends AbstractOpenTelemetryTest { - @Test - void toString_noop_Valid() { - assertThat(OpenTelemetry.noop().toString()) - .isEqualTo( - "DefaultOpenTelemetry{" - + "propagators=DefaultContextPropagators{textMapPropagator=NoopTextMapPropagator}" - + "}"); + @Override + protected TracerProvider getTracerProvider() { + return TracerProvider.noop(); } - private static void setOpenTelemetry() { - GlobalOpenTelemetry.set(OpenTelemetry.noop()); + @Override + protected MeterProvider getMeterProvider() { + return MeterProvider.noop(); } - private static OpenTelemetry getOpenTelemetry() { - return GlobalOpenTelemetry.get(); + @Override + protected LoggerProvider getLoggerProvider() { + return LoggerProvider.noop(); } } diff --git a/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerProviderTest.java b/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerProviderTest.java deleted file mode 100644 index 81a8bec1f84..00000000000 --- a/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerProviderTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.logs; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -import org.junit.jupiter.api.Test; - -class DefaultLoggerProviderTest { - - @Test - void noopLoggerProvider_doesNotThrow() { - LoggerProvider provider = LoggerProvider.noop(); - - assertThat(provider).isSameAs(DefaultLoggerProvider.getInstance()); - assertThatCode(() -> provider.get("scope-name")).doesNotThrowAnyException(); - assertThatCode( - () -> - provider - .loggerBuilder("scope-name") - .setInstrumentationVersion("1.0") - .setSchemaUrl("http://schema.com") - .build()) - .doesNotThrowAnyException(); - - assertThatCode(() -> provider.loggerBuilder("scope-name").build().logRecordBuilder()) - .doesNotThrowAnyException(); - } -} diff --git a/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java b/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java index ffe68f37e95..436baee524c 100644 --- a/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java @@ -5,36 +5,15 @@ package io.opentelemetry.api.logs; -import static org.assertj.core.api.Assertions.assertThatCode; +class DefaultLoggerTest extends AbstractDefaultLoggerTest { -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.Value; -import io.opentelemetry.context.Context; -import java.time.Instant; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.Test; - -class DefaultLoggerTest { + @Override + protected LoggerProvider getLoggerProvider() { + return DefaultLoggerProvider.getInstance(); + } - @Test - void buildAndEmit() { - assertThatCode( - () -> - DefaultLogger.getInstance() - .logRecordBuilder() - .setTimestamp(100, TimeUnit.SECONDS) - .setTimestamp(Instant.now()) - .setObservedTimestamp(100, TimeUnit.SECONDS) - .setObservedTimestamp(Instant.now()) - .setContext(Context.root()) - .setSeverity(Severity.DEBUG) - .setSeverityText("debug") - .setBody("body") - .setBody(Value.of("body")) - .setAttribute(AttributeKey.stringKey("key1"), "value1") - .setAllAttributes(Attributes.builder().put("key2", "value2").build()) - .emit()) - .doesNotThrowAnyException(); + @Override + protected Logger getLogger() { + return DefaultLogger.getInstance(); } } diff --git a/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterProviderTest.java b/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterProviderTest.java deleted file mode 100644 index 786d0a68a6e..00000000000 --- a/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterProviderTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.metrics; - -import org.junit.jupiter.api.Test; - -public class DefaultMeterProviderTest { - @Test - void noopMeterProvider_getDoesNotThrow() { - MeterProvider provider = MeterProvider.noop(); - provider.get("user-instrumentation"); - } - - @Test - void noopMeterProvider_builderDoesNotThrow() { - MeterProvider provider = MeterProvider.noop(); - provider.meterBuilder("user-instrumentation").build(); - provider.meterBuilder("advanced-instrumetnation").setInstrumentationVersion("1.0").build(); - provider.meterBuilder("schema-instrumentation").setSchemaUrl("myschema://url").build(); - provider - .meterBuilder("schema-instrumentation") - .setInstrumentationVersion("1.0") - .setSchemaUrl("myschema://url") - .build(); - } -} diff --git a/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java b/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java index fd9884bdad7..1b012be1d55 100644 --- a/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java @@ -5,199 +5,15 @@ package io.opentelemetry.api.metrics; -import static io.opentelemetry.api.common.AttributeKey.stringKey; +public class DefaultMeterTest extends AbstractDefaultMeterTest { -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.context.Context; -import io.opentelemetry.internal.testing.slf4j.SuppressLogger; -import org.junit.jupiter.api.Test; - -@SuppressLogger() -public class DefaultMeterTest { - private static final Meter METER = DefaultMeter.getInstance(); - - @Test - void noopLongCounter_doesNotThrow() { - LongCounter counter = - METER.counterBuilder("size").setDescription("The size I'm measuring").setUnit("1").build(); - counter.add(1); - counter.add(1, Attributes.of(stringKey("thing"), "car")); - counter.add(1, Attributes.of(stringKey("thing"), "car"), Context.current()); - } - - @Test - void noopDoubleCounter_doesNotThrow() { - DoubleCounter counter = - METER - .counterBuilder("size") - .ofDoubles() - .setDescription("The size I'm measuring") - .setUnit("1") - .build(); - counter.add(1.2); - counter.add(2.5, Attributes.of(stringKey("thing"), "car")); - counter.add(2.5, Attributes.of(stringKey("thing"), "car"), Context.current()); - } - - @Test - void noopLongUpDownCounter_doesNotThrow() { - LongUpDownCounter counter = - METER - .upDownCounterBuilder("size") - .setDescription("The size I'm measuring") - .setUnit("1") - .build(); - counter.add(-1); - counter.add(1, Attributes.of(stringKey("thing"), "car")); - counter.add(1, Attributes.of(stringKey("thing"), "car"), Context.current()); - } - - @Test - void noopDoubleUpDownCounter_doesNotThrow() { - DoubleUpDownCounter counter = - METER - .upDownCounterBuilder("size") - .ofDoubles() - .setDescription("The size I'm measuring") - .setUnit("1") - .build(); - counter.add(-2e4); - counter.add(1.0e-1, Attributes.of(stringKey("thing"), "car")); - counter.add(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current()); - } - - @Test - void noopLongHistogram_doesNotThrow() { - LongHistogram histogram = - METER - .histogramBuilder("size") - .ofLongs() - .setDescription("The size I'm measuring") - .setUnit("1") - .build(); - histogram.record(-1); - histogram.record(1, Attributes.of(stringKey("thing"), "car")); - histogram.record(1, Attributes.of(stringKey("thing"), "car"), Context.current()); - } - - @Test - void noopDoubleHistogram_doesNotThrow() { - DoubleHistogram histogram = - METER - .histogramBuilder("size") - .setDescription("The size I'm measuring") - .setUnit("1") - .build(); - histogram.record(-2e4); - histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car")); - histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current()); - } - - @Test - void noopLongGauage_doesNotThrow() { - LongGauge gauge = - METER - .gaugeBuilder("temperature") - .ofLongs() - .setDescription("The current temperature") - .setUnit("C") - .build(); - gauge.set(1); - gauge.set(2, Attributes.of(stringKey("thing"), "engine")); - gauge.set(2, Attributes.of(stringKey("thing"), "engine"), Context.current()); - } - - @Test - void noopObservableLongGauage_doesNotThrow() { - METER - .gaugeBuilder("temperature") - .ofLongs() - .setDescription("The current temperature") - .setUnit("C") - .buildWithCallback( - m -> { - m.record(1); - m.record(2, Attributes.of(stringKey("thing"), "engine")); - }); - } - - @Test - void noopDoubleGauage_doesNotThrow() { - DoubleGauge gauge = - METER - .gaugeBuilder("temperature") - .setDescription("The current temperature") - .setUnit("C") - .build(); - gauge.set(1); - gauge.set(2, Attributes.of(stringKey("thing"), "engine")); - gauge.set(2, Attributes.of(stringKey("thing"), "engine"), Context.current()); - } - - @Test - void noopObservableDoubleGauage_doesNotThrow() { - METER - .gaugeBuilder("temperature") - .setDescription("The current temperature") - .setUnit("C") - .buildWithCallback( - m -> { - m.record(1.0e1); - m.record(-27.4, Attributes.of(stringKey("thing"), "engine")); - }); - } - - @Test - void noopObservableLongCounter_doesNotThrow() { - METER - .counterBuilder("temperature") - .setDescription("The current temperature") - .setUnit("C") - .buildWithCallback( - m -> { - m.record(1); - m.record(2, Attributes.of(stringKey("thing"), "engine")); - }); - } - - @Test - void noopObservableDoubleCounter_doesNotThrow() { - METER - .counterBuilder("temperature") - .ofDoubles() - .setDescription("The current temperature") - .setUnit("C") - .buildWithCallback( - m -> { - m.record(1.0e1); - m.record(-27.4, Attributes.of(stringKey("thing"), "engine")); - }); - } - - @Test - void noopObservableLongUpDownCounter_doesNotThrow() { - METER - .upDownCounterBuilder("temperature") - .setDescription("The current temperature") - .setUnit("C") - .buildWithCallback( - m -> { - m.record(1); - m.record(2, Attributes.of(stringKey("thing"), "engine")); - }); + @Override + protected Meter getMeter() { + return DefaultMeter.getInstance(); } - @Test - void noopObservableDoubleUpDownCounter_doesNotThrow() { - METER - .upDownCounterBuilder("temperature") - .ofDoubles() - .setDescription("The current temperature") - .setUnit("C") - .buildWithCallback( - m -> { - m.record(1.0e1); - m.record(-27.4, Attributes.of(stringKey("thing"), "engine")); - }); + @Override + protected MeterProvider getMeterProvider() { + return DefaultMeterProvider.getInstance(); } } diff --git a/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerProviderTest.java b/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerProviderTest.java deleted file mode 100644 index 72a98f29f59..00000000000 --- a/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerProviderTest.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.trace; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -class DefaultTracerProviderTest { - - @Test - void returnsDefaultTracer() { - assertThat(TracerProvider.noop().get("test")).isInstanceOf(DefaultTracer.class); - assertThat(TracerProvider.noop().get("test", "1.0")).isInstanceOf(DefaultTracer.class); - } -} diff --git a/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerTest.java b/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerTest.java index dc364e96457..f0f577d9946 100644 --- a/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/trace/DefaultTracerTest.java @@ -5,89 +5,15 @@ package io.opentelemetry.api.trace; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; +class DefaultTracerTest extends AbstractDefaultTracerTest { -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.context.Context; -import org.junit.jupiter.api.Test; - -/** Unit tests for {@link DefaultTracer}. */ -// Need to suppress warnings for MustBeClosed because Android 14 does not support -// try-with-resources. -@SuppressWarnings("MustBeClosedChecker") -class DefaultTracerTest { - private static final Tracer defaultTracer = DefaultTracer.getInstance(); - private static final String SPAN_NAME = "MySpanName"; - private static final SpanContext spanContext = - SpanContext.create( - "00000000000000000000000000000061", - "0000000000000061", - TraceFlags.getDefault(), - TraceState.getDefault()); - - @Test - void defaultSpanBuilderWithName() { - assertThat(defaultTracer.spanBuilder(SPAN_NAME).startSpan().getSpanContext().isValid()) - .isFalse(); - } - - @Test - void testSpanContextPropagationExplicitParent() { - Span span = - defaultTracer - .spanBuilder(SPAN_NAME) - .setParent(Context.root().with(Span.wrap(spanContext))) - .startSpan(); - assertThat(span.getSpanContext()).isSameAs(spanContext); - } - - @Test - void testSpanContextPropagation() { - Span parent = Span.wrap(spanContext); - - Span span = - defaultTracer.spanBuilder(SPAN_NAME).setParent(Context.root().with(parent)).startSpan(); - assertThat(span.getSpanContext()).isSameAs(spanContext); - } - - @Test - void noSpanContextMakesInvalidSpans() { - Span span = defaultTracer.spanBuilder(SPAN_NAME).startSpan(); - assertThat(span.getSpanContext()).isSameAs(SpanContext.getInvalid()); - } - - @Test - void testSpanContextPropagation_fromContext() { - Context context = Context.current().with(Span.wrap(spanContext)); - - Span span = defaultTracer.spanBuilder(SPAN_NAME).setParent(context).startSpan(); - assertThat(span.getSpanContext()).isSameAs(spanContext); - } - - @Test - void testSpanContextPropagation_fromContextAfterNoParent() { - Context context = Context.current().with(Span.wrap(spanContext)); - - Span span = defaultTracer.spanBuilder(SPAN_NAME).setNoParent().setParent(context).startSpan(); - assertThat(span.getSpanContext()).isSameAs(spanContext); - } - - @Test - void testSpanContextPropagation_fromContextThenNoParent() { - Context context = Context.current().with(Span.wrap(spanContext)); - - Span span = defaultTracer.spanBuilder(SPAN_NAME).setParent(context).setNoParent().startSpan(); - assertThat(span.getSpanContext()).isEqualTo(SpanContext.getInvalid()); + @Override + public Tracer getTracer() { + return DefaultTracer.getInstance(); } - @Test - void addLink() { - Span span = Span.fromContext(Context.root()); - assertThatCode(() -> span.addLink(null)).doesNotThrowAnyException(); - assertThatCode(() -> span.addLink(SpanContext.getInvalid())).doesNotThrowAnyException(); - assertThatCode(() -> span.addLink(null, null)).doesNotThrowAnyException(); - assertThatCode(() -> span.addLink(SpanContext.getInvalid(), Attributes.empty())) - .doesNotThrowAnyException(); + @Override + public TracerProvider getTracerProvider() { + return DefaultTracerProvider.getInstance(); } } diff --git a/api/all/src/test/java/io/opentelemetry/api/trace/SpanBuilderTest.java b/api/all/src/test/java/io/opentelemetry/api/trace/SpanBuilderTest.java deleted file mode 100644 index a7ed2dc27cb..00000000000 --- a/api/all/src/test/java/io/opentelemetry/api/trace/SpanBuilderTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.trace; - -import static io.opentelemetry.api.common.AttributeKey.stringKey; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.context.Context; -import java.time.Instant; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.Test; - -/** Unit tests for {@link SpanBuilder}. */ -class SpanBuilderTest { - private final Tracer tracer = DefaultTracer.getInstance(); - - @Test - void doNotCrash_NoopImplementation() { - assertThatCode( - () -> { - SpanBuilder spanBuilder = tracer.spanBuilder(null); - spanBuilder.setSpanKind(null); - spanBuilder.setParent(null); - spanBuilder.setNoParent(); - spanBuilder.addLink(null); - spanBuilder.addLink(null, Attributes.empty()); - spanBuilder.addLink(SpanContext.getInvalid(), null); - spanBuilder.setAttribute((String) null, "foo"); - spanBuilder.setAttribute("foo", null); - spanBuilder.setAttribute(null, 0L); - spanBuilder.setAttribute(null, 0.0); - spanBuilder.setAttribute(null, false); - spanBuilder.setAttribute((AttributeKey) null, "foo"); - spanBuilder.setAttribute(stringKey(null), "foo"); - spanBuilder.setAttribute(stringKey(""), "foo"); - spanBuilder.setAttribute(stringKey("foo"), null); - spanBuilder.setStartTimestamp(-1, TimeUnit.MILLISECONDS); - spanBuilder.setStartTimestamp(1, null); - spanBuilder.setParent(Context.root().with(Span.wrap(null))); - spanBuilder.setParent(Context.root()); - spanBuilder.setNoParent(); - spanBuilder.addLink(Span.getInvalid().getSpanContext()); - spanBuilder.addLink(Span.getInvalid().getSpanContext(), Attributes.empty()); - spanBuilder.setAttribute("key", "value"); - spanBuilder.setAttribute("key", 12345L); - spanBuilder.setAttribute("key", .12345); - spanBuilder.setAttribute("key", true); - spanBuilder.setAttribute(stringKey("key"), "value"); - spanBuilder.setAllAttributes(Attributes.of(stringKey("key"), "value")); - spanBuilder.setAllAttributes(Attributes.empty()); - spanBuilder.setAllAttributes(null); - spanBuilder.setStartTimestamp(12345L, TimeUnit.NANOSECONDS); - spanBuilder.setStartTimestamp(Instant.EPOCH); - spanBuilder.setStartTimestamp(null); - assertThat(spanBuilder.startSpan().getSpanContext().isValid()).isFalse(); - }) - .doesNotThrowAnyException(); - } -} diff --git a/api/all/src/testFixtures/java/io/opentelemetry/api/AbstractOpenTelemetryTest.java b/api/all/src/testFixtures/java/io/opentelemetry/api/AbstractOpenTelemetryTest.java new file mode 100644 index 00000000000..6ba27d89760 --- /dev/null +++ b/api/all/src/testFixtures/java/io/opentelemetry/api/AbstractOpenTelemetryTest.java @@ -0,0 +1,114 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +/** Unit tests for {@link OpenTelemetry}. */ +public abstract class AbstractOpenTelemetryTest { + @BeforeAll + public static void beforeClass() { + GlobalOpenTelemetry.resetForTest(); + } + + private void setOpenTelemetry() { + GlobalOpenTelemetry.set(getOpenTelemetry()); + } + + private static OpenTelemetry getGlobalOpenTelemetry() { + return GlobalOpenTelemetry.get(); + } + + @AfterEach + public void after() { + GlobalOpenTelemetry.resetForTest(); + } + + @Test + void testDefault() { + assertThat(getOpenTelemetry().getTracerProvider()).isSameAs(getTracerProvider()); + assertThat(getOpenTelemetry().getPropagators()).isSameAs(ContextPropagators.noop()); + assertThat(getOpenTelemetry().getMeterProvider()).isSameAs(getMeterProvider()); + assertThat(getOpenTelemetry().getLogsBridge()).isSameAs(getLoggerProvider()); + } + + protected abstract TracerProvider getTracerProvider(); + + protected OpenTelemetry getOpenTelemetry() { + return OpenTelemetry.noop(); + } + + protected abstract MeterProvider getMeterProvider(); + + protected abstract LoggerProvider getLoggerProvider(); + + @Test + void propagating() { + ContextPropagators contextPropagators = Mockito.mock(ContextPropagators.class); + OpenTelemetry openTelemetry = OpenTelemetry.propagating(contextPropagators); + + assertThat(openTelemetry.getTracerProvider()).isSameAs(getTracerProvider()); + assertThat(openTelemetry.getMeterProvider()).isSameAs(getMeterProvider()); + assertThat(openTelemetry.getLogsBridge()).isSameAs(getLoggerProvider()); + assertThat(openTelemetry.getPropagators()).isSameAs(contextPropagators); + } + + @Test + void testGlobalBeforeSet() { + assertThat(GlobalOpenTelemetry.getTracerProvider()).isSameAs(getTracerProvider()); + assertThat(GlobalOpenTelemetry.getTracerProvider()) + .isSameAs(GlobalOpenTelemetry.getTracerProvider()); + assertThat(GlobalOpenTelemetry.getPropagators()).isSameAs(GlobalOpenTelemetry.getPropagators()); + } + + @Test + void independentNonGlobalPropagators() { + ContextPropagators propagators1 = Mockito.mock(ContextPropagators.class); + OpenTelemetry otel1 = OpenTelemetry.propagating(propagators1); + ContextPropagators propagators2 = Mockito.mock(ContextPropagators.class); + OpenTelemetry otel2 = OpenTelemetry.propagating(propagators2); + + assertThat(otel1.getPropagators()).isSameAs(propagators1); + assertThat(otel2.getPropagators()).isSameAs(propagators2); + } + + @Test + void setThenSet() { + setOpenTelemetry(); + assertThatThrownBy(() -> GlobalOpenTelemetry.set(getOpenTelemetry())) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("GlobalOpenTelemetry.set has already been called") + .hasStackTraceContaining("setOpenTelemetry"); + } + + @Test + void getThenSet() { + assertThat(getGlobalOpenTelemetry()).isInstanceOf(DefaultOpenTelemetry.class); + assertThatThrownBy(() -> GlobalOpenTelemetry.set(getOpenTelemetry())) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("GlobalOpenTelemetry.set has already been called") + .hasStackTraceContaining("getGlobalOpenTelemetry"); + } + + @Test + void toString_noop_Valid() { + assertThat(getOpenTelemetry().toString()) + .isEqualTo( + "DefaultOpenTelemetry{" + + "propagators=DefaultContextPropagators{textMapPropagator=NoopTextMapPropagator}" + + "}"); + } +} diff --git a/api/all/src/testFixtures/java/io/opentelemetry/api/logs/AbstractDefaultLoggerTest.java b/api/all/src/testFixtures/java/io/opentelemetry/api/logs/AbstractDefaultLoggerTest.java new file mode 100644 index 00000000000..88ecb74809a --- /dev/null +++ b/api/all/src/testFixtures/java/io/opentelemetry/api/logs/AbstractDefaultLoggerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.logs; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.context.Context; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link DefaultLogger}. */ +public abstract class AbstractDefaultLoggerTest { + + protected abstract LoggerProvider getLoggerProvider(); + + protected abstract Logger getLogger(); + + @Test + void noopLoggerProvider_doesNotThrow() { + LoggerProvider provider = LoggerProvider.noop(); + + assertThat(provider).isSameAs(getLoggerProvider()); + assertThatCode(() -> provider.get("scope-name")).doesNotThrowAnyException(); + assertThatCode( + () -> + provider + .loggerBuilder("scope-name") + .setInstrumentationVersion("1.0") + .setSchemaUrl("http://schema.com") + .build()) + .doesNotThrowAnyException(); + + assertThatCode(() -> provider.loggerBuilder("scope-name").build().logRecordBuilder()) + .doesNotThrowAnyException(); + } + + @Test + void buildAndEmit() { + assertThatCode( + () -> + getLogger() + .logRecordBuilder() + .setTimestamp(100, TimeUnit.SECONDS) + .setTimestamp(Instant.now()) + .setObservedTimestamp(100, TimeUnit.SECONDS) + .setObservedTimestamp(Instant.now()) + .setContext(Context.root()) + .setSeverity(Severity.DEBUG) + .setSeverityText("debug") + .setBody("body") + .setBody(Value.of("body")) + .setAttribute(AttributeKey.stringKey("key1"), "value1") + .setAllAttributes(Attributes.builder().put("key2", "value2").build()) + .emit()) + .doesNotThrowAnyException(); + } +} diff --git a/api/all/src/testFixtures/java/io/opentelemetry/api/metrics/AbstractDefaultMeterTest.java b/api/all/src/testFixtures/java/io/opentelemetry/api/metrics/AbstractDefaultMeterTest.java new file mode 100644 index 00000000000..b64c0929803 --- /dev/null +++ b/api/all/src/testFixtures/java/io/opentelemetry/api/metrics/AbstractDefaultMeterTest.java @@ -0,0 +1,251 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.metrics; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; +import io.opentelemetry.internal.testing.slf4j.SuppressLogger; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link DefaultMeter}. */ +@SuppressLogger() +public abstract class AbstractDefaultMeterTest { + private final Meter meter = getMeter(); + + protected abstract Meter getMeter(); + + protected abstract MeterProvider getMeterProvider(); + + @Test + void noopMeterProvider_getDoesNotThrow() { + MeterProvider provider = getMeterProvider(); + provider.get("user-instrumentation"); + } + + @Test + void noopMeterProvider_builderDoesNotThrow() { + MeterProvider provider = getMeterProvider(); + provider.meterBuilder("user-instrumentation").build(); + provider.meterBuilder("advanced-instrumetnation").setInstrumentationVersion("1.0").build(); + provider.meterBuilder("schema-instrumentation").setSchemaUrl("myschema://url").build(); + provider + .meterBuilder("schema-instrumentation") + .setInstrumentationVersion("1.0") + .setSchemaUrl("myschema://url") + .build(); + } + + @Test + void noopLongCounter_doesNotThrow() { + LongCounter counter = + meter.counterBuilder("size").setDescription("The size I'm measuring").setUnit("1").build(); + counter.add(1); + counter.add(1, Attributes.of(stringKey("thing"), "car")); + counter.add(1, Attributes.of(stringKey("thing"), "car"), Context.current()); + } + + @Test + void noopDoubleCounter_doesNotThrow() { + DoubleCounter counter = + meter + .counterBuilder("size") + .ofDoubles() + .setDescription("The size I'm measuring") + .setUnit("1") + .build(); + counter.add(1.2); + counter.add(2.5, Attributes.of(stringKey("thing"), "car")); + counter.add(2.5, Attributes.of(stringKey("thing"), "car"), Context.current()); + } + + @Test + void noopLongUpDownCounter_doesNotThrow() { + LongUpDownCounter counter = + meter + .upDownCounterBuilder("size") + .setDescription("The size I'm measuring") + .setUnit("1") + .build(); + counter.add(-1); + counter.add(1, Attributes.of(stringKey("thing"), "car")); + counter.add(1, Attributes.of(stringKey("thing"), "car"), Context.current()); + } + + @Test + void noopDoubleUpDownCounter_doesNotThrow() { + DoubleUpDownCounter counter = + meter + .upDownCounterBuilder("size") + .ofDoubles() + .setDescription("The size I'm measuring") + .setUnit("1") + .build(); + counter.add(-2e4); + counter.add(1.0e-1, Attributes.of(stringKey("thing"), "car")); + counter.add(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current()); + } + + @Test + void noopLongHistogram_doesNotThrow() { + LongHistogram histogram = + meter + .histogramBuilder("size") + .ofLongs() + .setDescription("The size I'm measuring") + .setUnit("1") + .build(); + histogram.record(-1); + histogram.record(1, Attributes.of(stringKey("thing"), "car")); + histogram.record(1, Attributes.of(stringKey("thing"), "car"), Context.current()); + } + + @Test + void noopDoubleHistogram_doesNotThrow() { + DoubleHistogram histogram = + meter + .histogramBuilder("size") + .setDescription("The size I'm measuring") + .setUnit("1") + .build(); + histogram.record(-2e4); + histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car")); + histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current()); + } + + @Test + void noopLongGauage_doesNotThrow() { + LongGauge gauge = + meter + .gaugeBuilder("temperature") + .ofLongs() + .setDescription("The current temperature") + .setUnit("C") + .build(); + gauge.set(1); + gauge.set(2, Attributes.of(stringKey("thing"), "engine")); + gauge.set(2, Attributes.of(stringKey("thing"), "engine"), Context.current()); + + ObservableLongMeasurement measurement = + meter + .gaugeBuilder("temperature") + .ofLongs() + .setDescription("The current temperature") + .setUnit("C") + .buildObserver(); + measurement.record(1); + measurement.record(1, Attributes.of(stringKey("thing"), "engine")); + } + + @Test + void noopObservableLongGauage_doesNotThrow() { + meter + .gaugeBuilder("temperature") + .ofLongs() + .setDescription("The current temperature") + .setUnit("C") + .buildWithCallback( + m -> { + m.record(1); + m.record(2, Attributes.of(stringKey("thing"), "engine")); + }); + } + + @Test + void noopDoubleGauage_doesNotThrow() { + DoubleGauge gauge = + meter + .gaugeBuilder("temperature") + .setDescription("The current temperature") + .setUnit("C") + .build(); + gauge.set(1); + gauge.set(2, Attributes.of(stringKey("thing"), "engine")); + gauge.set(2, Attributes.of(stringKey("thing"), "engine"), Context.current()); + + ObservableDoubleMeasurement measurement = + meter + .gaugeBuilder("temperature") + .setDescription("The current temperature") + .setUnit("C") + .buildObserver(); + measurement.record(1.0); + measurement.record(1.0, Attributes.of(stringKey("thing"), "engine")); + } + + @Test + void noopObservableDoubleGauage_doesNotThrow() { + meter + .gaugeBuilder("temperature") + .setDescription("The current temperature") + .setUnit("C") + .buildWithCallback( + m -> { + m.record(1.0e1); + m.record(-27.4, Attributes.of(stringKey("thing"), "engine")); + }); + } + + @Test + void noopObservableLongCounter_doesNotThrow() { + meter + .counterBuilder("temperature") + .setDescription("The current temperature") + .setUnit("C") + .buildWithCallback( + m -> { + m.record(1); + m.record(2, Attributes.of(stringKey("thing"), "engine")); + }); + } + + @Test + void noopObservableDoubleCounter_doesNotThrow() { + meter + .counterBuilder("temperature") + .ofDoubles() + .setDescription("The current temperature") + .setUnit("C") + .buildWithCallback( + m -> { + m.record(1.0e1); + m.record(-27.4, Attributes.of(stringKey("thing"), "engine")); + }); + } + + @Test + void noopObservableLongUpDownCounter_doesNotThrow() { + meter + .upDownCounterBuilder("temperature") + .setDescription("The current temperature") + .setUnit("C") + .buildWithCallback( + m -> { + m.record(1); + m.record(2, Attributes.of(stringKey("thing"), "engine")); + }); + } + + @Test + void noopObservableDoubleUpDownCounter_doesNotThrow() { + meter + .upDownCounterBuilder("temperature") + .ofDoubles() + .setDescription("The current temperature") + .setUnit("C") + .buildWithCallback( + m -> { + m.record(1.0e1); + m.record(-27.4, Attributes.of(stringKey("thing"), "engine")); + }); + } + + @Test + void noopBatchCallback_doesNotThrow() { + meter.batchCallback(() -> {}, null); + } +} diff --git a/api/all/src/testFixtures/java/io/opentelemetry/api/trace/AbstractDefaultTracerTest.java b/api/all/src/testFixtures/java/io/opentelemetry/api/trace/AbstractDefaultTracerTest.java new file mode 100644 index 00000000000..1933e289d5b --- /dev/null +++ b/api/all/src/testFixtures/java/io/opentelemetry/api/trace/AbstractDefaultTracerTest.java @@ -0,0 +1,153 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.trace; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link DefaultTracer}. */ +// Need to suppress warnings for MustBeClosed because Android 14 does not support +// try-with-resources. +@SuppressWarnings("MustBeClosedChecker") +public abstract class AbstractDefaultTracerTest { + private final Tracer defaultTracer = getTracer(); + private static final String SPAN_NAME = "MySpanName"; + private static final SpanContext spanContext = + SpanContext.create( + "00000000000000000000000000000061", + "0000000000000061", + TraceFlags.getDefault(), + TraceState.getDefault()); + + public abstract Tracer getTracer(); + + public abstract TracerProvider getTracerProvider(); + + @Test + void returnsDefaultTracer() { + TracerProvider tracerProvider = getTracerProvider(); + Class want = defaultTracer.getClass(); + assertThat( + tracerProvider + .tracerBuilder("test") + .setSchemaUrl("schema") + .setInstrumentationVersion("1") + .build()) + .isInstanceOf(want); + assertThat(tracerProvider.get("test")).isInstanceOf(want); + assertThat(tracerProvider.get("test", "1.0")).isInstanceOf(want); + } + + @Test + void defaultSpanBuilderWithName() { + assertThat(defaultTracer.spanBuilder(SPAN_NAME).startSpan().getSpanContext().isValid()) + .isFalse(); + } + + @Test + void spanContextPropagationExplicitParent() { + assertThat( + defaultTracer + .spanBuilder(SPAN_NAME) + .setParent(Context.root().with(Span.wrap(spanContext))) + .startSpan() + .getSpanContext()) + .isSameAs(spanContext); + + SpanBuilder builder = defaultTracer.spanBuilder(SPAN_NAME); + assertThat(builder.setParent(null)).isSameAs(builder); + } + + @Test + void spanContextPropagation() { + Span parent = Span.wrap(spanContext); + + Span span = + defaultTracer.spanBuilder(SPAN_NAME).setParent(Context.root().with(parent)).startSpan(); + assertThat(span.getSpanContext()).isSameAs(spanContext); + } + + @Test + void noSpanContextMakesInvalidSpans() { + Span span = defaultTracer.spanBuilder(SPAN_NAME).startSpan(); + assertThat(span.getSpanContext()).isSameAs(SpanContext.getInvalid()); + } + + @Test + void spanContextPropagation_fromContext() { + Context context = Context.current().with(Span.wrap(spanContext)); + + Span span = defaultTracer.spanBuilder(SPAN_NAME).setParent(context).startSpan(); + assertThat(span.getSpanContext()).isSameAs(spanContext); + } + + @Test + void spanContextPropagation_fromContextAfterNoParent() { + Context context = Context.current().with(Span.wrap(spanContext)); + + Span span = defaultTracer.spanBuilder(SPAN_NAME).setNoParent().setParent(context).startSpan(); + assertThat(span.getSpanContext()).isSameAs(spanContext); + } + + @Test + void spanContextPropagation_fromContextThenNoParent() { + Context context = Context.current().with(Span.wrap(spanContext)); + + Span span = defaultTracer.spanBuilder(SPAN_NAME).setParent(context).setNoParent().startSpan(); + assertThat(span.getSpanContext()).isEqualTo(SpanContext.getInvalid()); + } + + @Test + void doNotCrash_NoopImplementation() { + assertThatCode( + () -> { + SpanBuilder spanBuilder = defaultTracer.spanBuilder(null); + spanBuilder.setSpanKind(null); + spanBuilder.setParent(null); + spanBuilder.setNoParent(); + spanBuilder.addLink(null); + spanBuilder.addLink(null, Attributes.empty()); + spanBuilder.addLink(SpanContext.getInvalid(), null); + spanBuilder.setAttribute((String) null, "foo"); + spanBuilder.setAttribute("foo", null); + spanBuilder.setAttribute(null, 0L); + spanBuilder.setAttribute(null, 0.0); + spanBuilder.setAttribute(null, false); + spanBuilder.setAttribute((AttributeKey) null, "foo"); + spanBuilder.setAttribute(stringKey(null), "foo"); + spanBuilder.setAttribute(stringKey(""), "foo"); + spanBuilder.setAttribute(stringKey("foo"), null); + spanBuilder.setStartTimestamp(-1, TimeUnit.MILLISECONDS); + spanBuilder.setStartTimestamp(1, null); + spanBuilder.setParent(Context.root().with(Span.wrap(null))); + spanBuilder.setParent(Context.root()); + spanBuilder.setNoParent(); + spanBuilder.addLink(Span.getInvalid().getSpanContext()); + spanBuilder.addLink(Span.getInvalid().getSpanContext(), Attributes.empty()); + spanBuilder.setAttribute("key", "value"); + spanBuilder.setAttribute("key", 12345L); + spanBuilder.setAttribute("key", .12345); + spanBuilder.setAttribute("key", true); + spanBuilder.setAttribute(stringKey("key"), "value"); + spanBuilder.setAllAttributes(Attributes.of(stringKey("key"), "value")); + spanBuilder.setAllAttributes(Attributes.empty()); + spanBuilder.setAllAttributes(null); + spanBuilder.setStartTimestamp(12345L, TimeUnit.NANOSECONDS); + spanBuilder.setStartTimestamp(Instant.EPOCH); + spanBuilder.setStartTimestamp(null); + assertThat(spanBuilder.startSpan().getSpanContext().isValid()).isFalse(); + }) + .doesNotThrowAnyException(); + } +} diff --git a/api/incubator/build.gradle.kts b/api/incubator/build.gradle.kts index 3dfa0e79a3c..b28295de6d0 100644 --- a/api/incubator/build.gradle.kts +++ b/api/incubator/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { annotationProcessor("com.google.auto.value:auto-value") testImplementation(project(":sdk:testing")) + testImplementation(testFixtures(project(":api:all"))) testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating") diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLogger.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLogger.java new file mode 100644 index 00000000000..3e8dce08e74 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLogger.java @@ -0,0 +1,90 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.logs; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.logs.LogRecordBuilder; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +class ExtendedDefaultLogger implements ExtendedLogger { + + private static final Logger INSTANCE = new ExtendedDefaultLogger(); + private static final LogRecordBuilder NOOP_LOG_RECORD_BUILDER = new NoopLogRecordBuilder(); + + private ExtendedDefaultLogger() {} + + static Logger getNoop() { + return INSTANCE; + } + + @Override + public LogRecordBuilder logRecordBuilder() { + return NOOP_LOG_RECORD_BUILDER; + } + + private static final class NoopLogRecordBuilder implements ExtendedLogRecordBuilder { + + private NoopLogRecordBuilder() {} + + @Override + public LogRecordBuilder setTimestamp(long timestamp, TimeUnit unit) { + return this; + } + + @Override + public LogRecordBuilder setTimestamp(Instant instant) { + return this; + } + + @Override + public LogRecordBuilder setObservedTimestamp(long timestamp, TimeUnit unit) { + return this; + } + + @Override + public LogRecordBuilder setObservedTimestamp(Instant instant) { + return this; + } + + @Override + public LogRecordBuilder setContext(Context context) { + return this; + } + + @Override + public LogRecordBuilder setSeverity(Severity severity) { + return this; + } + + @Override + public LogRecordBuilder setSeverityText(String severityText) { + return this; + } + + @Override + public LogRecordBuilder setBody(String body) { + return this; + } + + @Override + public LogRecordBuilder setBody(Value body) { + return this; + } + + @Override + public LogRecordBuilder setAttribute(AttributeKey key, T value) { + return this; + } + + @Override + public void emit() {} + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLoggerProvider.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLoggerProvider.java new file mode 100644 index 00000000000..6cf93296689 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLoggerProvider.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.logs; + +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.LoggerBuilder; +import io.opentelemetry.api.logs.LoggerProvider; + +public class ExtendedDefaultLoggerProvider implements LoggerProvider { + + private static final LoggerProvider INSTANCE = new ExtendedDefaultLoggerProvider(); + private static final LoggerBuilder NOOP_BUILDER = new NoopLoggerBuilder(); + + private ExtendedDefaultLoggerProvider() {} + + public static LoggerProvider getNoop() { + return INSTANCE; + } + + @Override + public LoggerBuilder loggerBuilder(String instrumentationScopeName) { + return NOOP_BUILDER; + } + + private static class NoopLoggerBuilder implements LoggerBuilder { + + @Override + public LoggerBuilder setSchemaUrl(String schemaUrl) { + return this; + } + + @Override + public LoggerBuilder setInstrumentationVersion(String instrumentationVersion) { + return this; + } + + @Override + public Logger build() { + return ExtendedDefaultLogger.getNoop(); + } + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeter.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeter.java new file mode 100644 index 00000000000..de1ec1fdefc --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeter.java @@ -0,0 +1,454 @@ +/* + * 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.BatchCallback; +import io.opentelemetry.api.metrics.DoubleCounter; +import io.opentelemetry.api.metrics.DoubleCounterBuilder; +import io.opentelemetry.api.metrics.DoubleGauge; +import io.opentelemetry.api.metrics.DoubleGaugeBuilder; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.DoubleHistogramBuilder; +import io.opentelemetry.api.metrics.DoubleUpDownCounter; +import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongCounterBuilder; +import io.opentelemetry.api.metrics.LongGauge; +import io.opentelemetry.api.metrics.LongGaugeBuilder; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.api.metrics.LongHistogramBuilder; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableDoubleCounter; +import io.opentelemetry.api.metrics.ObservableDoubleGauge; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; +import io.opentelemetry.api.metrics.ObservableDoubleUpDownCounter; +import io.opentelemetry.api.metrics.ObservableLongCounter; +import io.opentelemetry.api.metrics.ObservableLongGauge; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.api.metrics.ObservableLongUpDownCounter; +import io.opentelemetry.api.metrics.ObservableMeasurement; +import io.opentelemetry.context.Context; +import java.util.function.Consumer; +import javax.annotation.concurrent.ThreadSafe; + +/** + * No-op implementation of {@link Meter}. + * + *

This implementation should induce as close to zero overhead as possible. + */ +@ThreadSafe +class ExtendedDefaultMeter implements Meter { + + private static final Meter INSTANCE = new ExtendedDefaultMeter(); + + private static final LongCounterBuilder NOOP_LONG_COUNTER_BUILDER = new NoopLongCounterBuilder(); + private static final LongUpDownCounterBuilder NOOP_LONG_UP_DOWN_COUNTER_BUILDER = + new NoopLongUpDownCounterBuilder(); + private static final DoubleHistogramBuilder NOOP_DOUBLE_HISTOGRAM_BUILDER = + new NoopDoubleHistogramBuilder(); + private static final DoubleGaugeBuilder NOOP_DOUBLE_GAUGE_BUILDER = new NoopDoubleGaugeBuilder(); + private static final BatchCallback NOOP_BATCH_CALLBACK = new BatchCallback() {}; + private static final ObservableDoubleMeasurement NOOP_OBSERVABLE_DOUBLE_MEASUREMENT = + new NoopObservableDoubleMeasurement(); + private static final ObservableLongMeasurement NOOP_OBSERVABLE_LONG_MEASUREMENT = + new NoopObservableLongMeasurement(); + + static Meter getNoop() { + return INSTANCE; + } + + @Override + public LongCounterBuilder counterBuilder(String name) { + return NOOP_LONG_COUNTER_BUILDER; + } + + @Override + public LongUpDownCounterBuilder upDownCounterBuilder(String name) { + return NOOP_LONG_UP_DOWN_COUNTER_BUILDER; + } + + @Override + public DoubleHistogramBuilder histogramBuilder(String name) { + return NOOP_DOUBLE_HISTOGRAM_BUILDER; + } + + @Override + public DoubleGaugeBuilder gaugeBuilder(String name) { + return NOOP_DOUBLE_GAUGE_BUILDER; + } + + @Override + public BatchCallback batchCallback( + Runnable callback, + ObservableMeasurement observableMeasurement, + ObservableMeasurement... additionalMeasurements) { + return NOOP_BATCH_CALLBACK; + } + + private ExtendedDefaultMeter() {} + + private static class NoopLongCounter implements ExtendedLongCounter { + @Override + public void add(long value, Attributes attributes, Context context) {} + + @Override + public void add(long value, Attributes attributes) {} + + @Override + public void add(long value) {} + } + + private static class NoopDoubleCounter implements ExtendedDoubleCounter { + @Override + public void add(double value, Attributes attributes, Context context) {} + + @Override + public void add(double value, Attributes attributes) {} + + @Override + public void add(double value) {} + } + + private static class NoopLongCounterBuilder implements ExtendedLongCounterBuilder { + private static final LongCounter NOOP_COUNTER = new NoopLongCounter(); + private static final ObservableLongCounter NOOP_OBSERVABLE_COUNTER = + new ObservableLongCounter() {}; + private static final DoubleCounterBuilder NOOP_DOUBLE_COUNTER_BUILDER = + new NoopDoubleCounterBuilder(); + + @Override + public LongCounterBuilder setDescription(String description) { + return this; + } + + @Override + public LongCounterBuilder setUnit(String unit) { + return this; + } + + @Override + public DoubleCounterBuilder ofDoubles() { + return NOOP_DOUBLE_COUNTER_BUILDER; + } + + @Override + public LongCounter build() { + return NOOP_COUNTER; + } + + @Override + public ObservableLongCounter buildWithCallback(Consumer callback) { + return NOOP_OBSERVABLE_COUNTER; + } + + @Override + public ObservableLongMeasurement buildObserver() { + return NOOP_OBSERVABLE_LONG_MEASUREMENT; + } + } + + private static class NoopDoubleCounterBuilder implements ExtendedDoubleCounterBuilder { + private static final DoubleCounter NOOP_COUNTER = new NoopDoubleCounter(); + private static final ObservableDoubleCounter NOOP_OBSERVABLE_COUNTER = + new ObservableDoubleCounter() {}; + + @Override + public DoubleCounterBuilder setDescription(String description) { + return this; + } + + @Override + public DoubleCounterBuilder setUnit(String unit) { + return this; + } + + @Override + public DoubleCounter build() { + return NOOP_COUNTER; + } + + @Override + public ObservableDoubleCounter buildWithCallback( + Consumer callback) { + return NOOP_OBSERVABLE_COUNTER; + } + + @Override + public ObservableDoubleMeasurement buildObserver() { + return NOOP_OBSERVABLE_DOUBLE_MEASUREMENT; + } + } + + private static class NoopLongUpDownCounter implements ExtendedLongUpDownCounter { + @Override + public void add(long value, Attributes attributes, Context context) {} + + @Override + public void add(long value, Attributes attributes) {} + + @Override + public void add(long value) {} + } + + private static class NoopDoubleUpDownCounter implements ExtendedDoubleUpDownCounter { + @Override + public void add(double value, Attributes attributes, Context context) {} + + @Override + public void add(double value, Attributes attributes) {} + + @Override + public void add(double value) {} + } + + private static class NoopLongUpDownCounterBuilder implements ExtendedLongUpDownCounterBuilder { + private static final LongUpDownCounter NOOP_UP_DOWN_COUNTER = new NoopLongUpDownCounter() {}; + private static final ObservableLongUpDownCounter NOOP_OBSERVABLE_UP_DOWN_COUNTER = + new ObservableLongUpDownCounter() {}; + private static final DoubleUpDownCounterBuilder NOOP_DOUBLE_UP_DOWN_COUNTER_BUILDER = + new NoopDoubleUpDownCounterBuilder(); + + @Override + public LongUpDownCounterBuilder setDescription(String description) { + return this; + } + + @Override + public LongUpDownCounterBuilder setUnit(String unit) { + return this; + } + + @Override + public DoubleUpDownCounterBuilder ofDoubles() { + return NOOP_DOUBLE_UP_DOWN_COUNTER_BUILDER; + } + + @Override + public LongUpDownCounter build() { + return NOOP_UP_DOWN_COUNTER; + } + + @Override + public ObservableLongUpDownCounter buildWithCallback( + Consumer callback) { + return NOOP_OBSERVABLE_UP_DOWN_COUNTER; + } + + @Override + public ObservableLongMeasurement buildObserver() { + return NOOP_OBSERVABLE_LONG_MEASUREMENT; + } + } + + private static class NoopDoubleUpDownCounterBuilder + implements ExtendedDoubleUpDownCounterBuilder { + private static final DoubleUpDownCounter NOOP_UP_DOWN_COUNTER = + new NoopDoubleUpDownCounter() {}; + private static final ObservableDoubleUpDownCounter NOOP_OBSERVABLE_UP_DOWN_COUNTER = + new ObservableDoubleUpDownCounter() {}; + + @Override + public DoubleUpDownCounterBuilder setDescription(String description) { + return this; + } + + @Override + public DoubleUpDownCounterBuilder setUnit(String unit) { + return this; + } + + @Override + public DoubleUpDownCounter build() { + return NOOP_UP_DOWN_COUNTER; + } + + @Override + public ObservableDoubleUpDownCounter buildWithCallback( + Consumer callback) { + return NOOP_OBSERVABLE_UP_DOWN_COUNTER; + } + + @Override + public ObservableDoubleMeasurement buildObserver() { + return NOOP_OBSERVABLE_DOUBLE_MEASUREMENT; + } + } + + private static class NoopDoubleHistogram implements ExtendedDoubleHistogram { + @Override + public void record(double value, Attributes attributes, Context context) {} + + @Override + public void record(double value, Attributes attributes) {} + + @Override + public void record(double value) {} + } + + private static class NoopLongHistogram implements ExtendedLongHistogram { + @Override + public void record(long value, Attributes attributes, Context context) {} + + @Override + public void record(long value, Attributes attributes) {} + + @Override + public void record(long value) {} + } + + private static class NoopDoubleHistogramBuilder implements ExtendedDoubleHistogramBuilder { + private static final DoubleHistogram NOOP = new NoopDoubleHistogram(); + private static final LongHistogramBuilder NOOP_LONG_HISTOGRAM_BUILDER = + new NoopLongHistogramBuilder(); + + @Override + public DoubleHistogramBuilder setDescription(String description) { + return this; + } + + @Override + public DoubleHistogramBuilder setUnit(String unit) { + return this; + } + + @Override + public LongHistogramBuilder ofLongs() { + return NOOP_LONG_HISTOGRAM_BUILDER; + } + + @Override + public DoubleHistogram build() { + return NOOP; + } + } + + private static class NoopLongHistogramBuilder implements ExtendedLongHistogramBuilder { + private static final LongHistogram NOOP = new NoopLongHistogram(); + + @Override + public LongHistogramBuilder setDescription(String description) { + return this; + } + + @Override + public LongHistogramBuilder setUnit(String unit) { + return this; + } + + @Override + public LongHistogram build() { + return NOOP; + } + } + + private static class NoopDoubleGaugeBuilder implements ExtendedDoubleGaugeBuilder { + private static final ObservableDoubleGauge NOOP_OBSERVABLE_GAUGE = + new ObservableDoubleGauge() {}; + private static final LongGaugeBuilder NOOP_LONG_GAUGE_BUILDER = new NoopLongGaugeBuilder(); + private static final NoopDoubleGauge NOOP_GAUGE = new NoopDoubleGauge(); + + @Override + public DoubleGaugeBuilder setDescription(String description) { + return this; + } + + @Override + public DoubleGaugeBuilder setUnit(String unit) { + return this; + } + + @Override + public LongGaugeBuilder ofLongs() { + return NOOP_LONG_GAUGE_BUILDER; + } + + @Override + public ObservableDoubleGauge buildWithCallback(Consumer callback) { + return NOOP_OBSERVABLE_GAUGE; + } + + @Override + public ObservableDoubleMeasurement buildObserver() { + return NOOP_OBSERVABLE_DOUBLE_MEASUREMENT; + } + + @Override + public DoubleGauge build() { + return NOOP_GAUGE; + } + } + + private static class NoopDoubleGauge implements ExtendedDoubleGauge { + @Override + public void set(double value) {} + + @Override + public void set(double value, Attributes attributes) {} + + @Override + public void set(double value, Attributes attributes, Context context) {} + } + + private static class NoopLongGaugeBuilder implements ExtendedLongGaugeBuilder { + private static final ObservableLongGauge NOOP_OBSERVABLE_GAUGE = new ObservableLongGauge() {}; + private static final NoopLongGauge NOOP_GAUGE = new NoopLongGauge(); + + @Override + public LongGaugeBuilder setDescription(String description) { + return this; + } + + @Override + public LongGaugeBuilder setUnit(String unit) { + return this; + } + + @Override + public ObservableLongGauge buildWithCallback(Consumer callback) { + return NOOP_OBSERVABLE_GAUGE; + } + + @Override + public ObservableLongMeasurement buildObserver() { + return NOOP_OBSERVABLE_LONG_MEASUREMENT; + } + + @Override + public LongGauge build() { + return NOOP_GAUGE; + } + } + + private static class NoopLongGauge implements ExtendedLongGauge { + @Override + public void set(long value) {} + + @Override + public void set(long value, Attributes attributes) {} + + @Override + public void set(long value, Attributes attributes, Context context) {} + } + + private static class NoopObservableDoubleMeasurement implements ObservableDoubleMeasurement { + @Override + public void record(double value) {} + + @Override + public void record(double value, Attributes attributes) {} + } + + private static class NoopObservableLongMeasurement implements ObservableLongMeasurement { + @Override + public void record(long value) {} + + @Override + public void record(long value, Attributes attributes) {} + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeterProvider.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeterProvider.java new file mode 100644 index 00000000000..3eeca2081f8 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeterProvider.java @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.MeterBuilder; +import io.opentelemetry.api.metrics.MeterProvider; + +/** A {@link MeterProvider} that does nothing. */ +public class ExtendedDefaultMeterProvider implements MeterProvider { + @Override + public MeterBuilder meterBuilder(String instrumentationScopeName) { + return BUILDER_INSTANCE; + } + + private static final ExtendedDefaultMeterProvider INSTANCE = new ExtendedDefaultMeterProvider(); + private static final MeterBuilder BUILDER_INSTANCE = new NoopMeterBuilder(); + + public static MeterProvider getNoop() { + return INSTANCE; + } + + private ExtendedDefaultMeterProvider() {} + + private static class NoopMeterBuilder implements MeterBuilder { + + @Override + public MeterBuilder setSchemaUrl(String schemaUrl) { + return this; + } + + @Override + public MeterBuilder setInstrumentationVersion(String instrumentationScopeVersion) { + return this; + } + + @Override + public Meter build() { + return ExtendedDefaultMeter.getNoop(); + } + } +} 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 new file mode 100644 index 00000000000..948f17e9996 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracer.java @@ -0,0 +1,156 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +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; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.ContextPropagators; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import javax.annotation.Nullable; +import javax.annotation.concurrent.ThreadSafe; + +/** No-op implementation of {@link ExtendedTracer}. */ +@ThreadSafe +final class ExtendedDefaultTracer implements ExtendedTracer { + + private static final Tracer INSTANCE = new ExtendedDefaultTracer(); + + static Tracer getNoop() { + return INSTANCE; + } + + @Override + public SpanBuilder spanBuilder(String spanName) { + return NoopSpanBuilder.create(); + } + + private ExtendedDefaultTracer() {} + + // Noop implementation of Span.Builder. + private static final class NoopSpanBuilder implements ExtendedSpanBuilder { + static NoopSpanBuilder create() { + return new NoopSpanBuilder(); + } + + @Nullable private SpanContext spanContext; + + @Override + public Span startSpan() { + if (spanContext == null) { + spanContext = Span.current().getSpanContext(); + } + + return Span.wrap(spanContext); + } + + @Override + public NoopSpanBuilder setParent(Context context) { + if (context == null) { + ApiUsageLogger.log("context is null"); + return this; + } + spanContext = Span.fromContext(context).getSpanContext(); + return this; + } + + @Override + public NoopSpanBuilder setParentFrom( + ContextPropagators propagators, Map carrier) { + setParent(ExtendedContextPropagators.extractTextMapPropagationContext(carrier, propagators)); + return this; + } + + @Override + public NoopSpanBuilder setNoParent() { + spanContext = SpanContext.getInvalid(); + return this; + } + + @Override + public NoopSpanBuilder addLink(SpanContext spanContext) { + return this; + } + + @Override + public NoopSpanBuilder addLink(SpanContext spanContext, Attributes attributes) { + return this; + } + + @Override + public NoopSpanBuilder setAttribute(String key, String value) { + return this; + } + + @Override + public NoopSpanBuilder setAttribute(String key, long value) { + return this; + } + + @Override + public NoopSpanBuilder setAttribute(String key, double value) { + return this; + } + + @Override + public NoopSpanBuilder setAttribute(String key, boolean value) { + return this; + } + + @Override + public NoopSpanBuilder setAttribute(AttributeKey key, T value) { + return this; + } + + @Override + public NoopSpanBuilder setAllAttributes(Attributes attributes) { + return this; + } + + @Override + public NoopSpanBuilder setSpanKind(SpanKind spanKind) { + return this; + } + + @Override + public NoopSpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { + return this; + } + + @Override + public T startAndCall(SpanCallable spanCallable) throws E { + return spanCallable.callInSpan(); + } + + @Override + public T startAndCall( + SpanCallable spanCallable, BiConsumer handleException) throws E { + return spanCallable.callInSpan(); + } + + @Override + public void startAndRun(SpanRunnable runnable) throws E { + runnable.runInSpan(); + } + + @Override + public void startAndRun( + SpanRunnable runnable, BiConsumer handleException) throws E { + runnable.runInSpan(); + } + + private NoopSpanBuilder() {} + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerBuilder.java new file mode 100644 index 00000000000..20469674ae5 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerBuilder.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerBuilder; + +final class ExtendedDefaultTracerBuilder implements TracerBuilder { + private static final ExtendedDefaultTracerBuilder INSTANCE = new ExtendedDefaultTracerBuilder(); + + static TracerBuilder getInstance() { + return INSTANCE; + } + + @Override + public TracerBuilder setSchemaUrl(String schemaUrl) { + return this; + } + + @Override + public TracerBuilder setInstrumentationVersion(String instrumentationScopeVersion) { + return this; + } + + @Override + public Tracer build() { + return ExtendedDefaultTracer.getNoop(); + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerProvider.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerProvider.java new file mode 100644 index 00000000000..b7bd2133ad7 --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerBuilder; +import io.opentelemetry.api.trace.TracerProvider; +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +public class ExtendedDefaultTracerProvider implements TracerProvider { + + private static final TracerProvider INSTANCE = new ExtendedDefaultTracerProvider(); + + public static TracerProvider getNoop() { + return INSTANCE; + } + + @Override + public Tracer get(String instrumentationScopeName) { + return ExtendedDefaultTracer.getNoop(); + } + + @Override + public Tracer get(String instrumentationScopeName, String instrumentationScopeVersion) { + return ExtendedDefaultTracer.getNoop(); + } + + @Override + public TracerBuilder tracerBuilder(String instrumentationScopeName) { + return ExtendedDefaultTracerBuilder.getInstance(); + } + + private ExtendedDefaultTracerProvider() {} +} diff --git a/api/incubator/src/main/resources/META-INF/native-image/io.opentelemetry/opentelemetry-api/reflect-config.json b/api/incubator/src/main/resources/META-INF/native-image/io.opentelemetry/opentelemetry-api/reflect-config.json new file mode 100644 index 00000000000..d9abd56c422 --- /dev/null +++ b/api/incubator/src/main/resources/META-INF/native-image/io.opentelemetry/opentelemetry-api/reflect-config.json @@ -0,0 +1,38 @@ +[ + { + "methods": [ + { + "name": "getNoop", + "parameterTypes": [] + } + ], + "name": "io.opentelemetry.api.incubator.logs.ExtendedDefaultLoggerProvider" + }, + { + "methods": [ + { + "name": "getNoop", + "parameterTypes": [] + } + ], + "name": "io.opentelemetry.api.incubator.metrics.ExtendedDefaultMeterProvider" + }, + { + "methods": [ + { + "name": "getNoop", + "parameterTypes": [] + } + ], + "name": "io.opentelemetry.api.incubator.trace.ExtendedDefaultTracerProvider" + }, + { + "methods": [ + { + "name": "getNoop", + "parameterTypes": [] + } + ], + "name": "io.opentelemetry.api.incubator.ExtendedDefaultOpenTelemetry" + } +] diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java new file mode 100644 index 00000000000..b33c29c8194 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.AbstractOpenTelemetryTest; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.logs.ExtendedDefaultLoggerProvider; +import io.opentelemetry.api.incubator.logs.ExtendedLogger; +import io.opentelemetry.api.incubator.metrics.ExtendedDefaultMeterProvider; +import io.opentelemetry.api.incubator.metrics.ExtendedLongCounterBuilder; +import io.opentelemetry.api.incubator.trace.ExtendedDefaultTracerProvider; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; +import org.junit.jupiter.api.Test; + +class ExtendedOpenTelemetryTest extends AbstractOpenTelemetryTest { + + @Override + protected TracerProvider getTracerProvider() { + return ExtendedDefaultTracerProvider.getNoop(); + } + + @Override + protected MeterProvider getMeterProvider() { + return ExtendedDefaultMeterProvider.getNoop(); + } + + @Override + protected LoggerProvider getLoggerProvider() { + return ExtendedDefaultLoggerProvider.getNoop(); + } + + @Test + void incubatingApiIsLoaded() { + assertIsExtended(OpenTelemetry.noop()); + assertIsExtended(OpenTelemetry.propagating(ContextPropagators.noop())); + } + + private static void assertIsExtended(OpenTelemetry openTelemetry) { + assertThat(openTelemetry.getMeter("test").counterBuilder("test")) + .isInstanceOf(ExtendedLongCounterBuilder.class); + assertThat(openTelemetry.getLogsBridge().get("test")).isInstanceOf(ExtendedLogger.class); + assertThat(openTelemetry.getTracer("test")).isInstanceOf(ExtendedTracer.class); + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLoggerTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLoggerTest.java new file mode 100644 index 00000000000..e558b53fcf1 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedDefaultLoggerTest.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.logs; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.logs.AbstractDefaultLoggerTest; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.LoggerProvider; +import org.junit.jupiter.api.Test; + +class ExtendedDefaultLoggerTest extends AbstractDefaultLoggerTest { + + @Override + protected LoggerProvider getLoggerProvider() { + return ExtendedDefaultLoggerProvider.getNoop(); + } + + @Override + protected Logger getLogger() { + return ExtendedDefaultLogger.getNoop(); + } + + @Test + void incubatingApiIsLoaded() { + Logger logger = LoggerProvider.noop().get("test"); + + assertThat(logger).isInstanceOf(ExtendedLogger.class); + ExtendedLogRecordBuilder builder = (ExtendedLogRecordBuilder) logger.logRecordBuilder(); + assertThat(builder).isInstanceOf(ExtendedLogRecordBuilder.class); + assertThat(builder.setBody(Value.of(0))).isSameAs(builder); + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeterTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeterTest.java new file mode 100644 index 00000000000..3d342a33661 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedDefaultMeterTest.java @@ -0,0 +1,70 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.metrics; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.metrics.AbstractDefaultMeterTest; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.MeterProvider; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +class ExtendedDefaultMeterTest extends AbstractDefaultMeterTest { + + @Override + protected Meter getMeter() { + return ExtendedDefaultMeter.getNoop(); + } + + @Override + protected MeterProvider getMeterProvider() { + return ExtendedDefaultMeterProvider.getNoop(); + } + + @Test + public void incubatingApiIsLoaded() { + Meter meter = MeterProvider.noop().get("test"); + assertThat(meter).isSameAs(OpenTelemetry.noop().getMeter("test")); + + Assertions.assertThat(meter.gaugeBuilder("test").ofLongs()) + .isInstanceOf(ExtendedLongGaugeBuilder.class); + Assertions.assertThat(meter.gaugeBuilder("test").ofLongs().build()) + .isInstanceOf(ExtendedLongGauge.class); + Assertions.assertThat(meter.gaugeBuilder("test")) + .isInstanceOf(ExtendedDoubleGaugeBuilder.class); + Assertions.assertThat(meter.gaugeBuilder("test").build()) + .isInstanceOf(ExtendedDoubleGauge.class); + + Assertions.assertThat(meter.histogramBuilder("test").ofLongs()) + .isInstanceOf(ExtendedLongHistogramBuilder.class); + Assertions.assertThat(meter.histogramBuilder("test").ofLongs().build()) + .isInstanceOf(ExtendedLongHistogram.class); + Assertions.assertThat(meter.histogramBuilder("test")) + .isInstanceOf(ExtendedDoubleHistogramBuilder.class); + Assertions.assertThat(meter.histogramBuilder("test").build()) + .isInstanceOf(ExtendedDoubleHistogram.class); + + Assertions.assertThat(meter.counterBuilder("test")) + .isInstanceOf(ExtendedLongCounterBuilder.class); + Assertions.assertThat(meter.counterBuilder("test").build()) + .isInstanceOf(ExtendedLongCounter.class); + Assertions.assertThat(meter.counterBuilder("test").ofDoubles()) + .isInstanceOf(ExtendedDoubleCounterBuilder.class); + Assertions.assertThat(meter.counterBuilder("test").ofDoubles().build()) + .isInstanceOf(ExtendedDoubleCounter.class); + + Assertions.assertThat(meter.upDownCounterBuilder("test")) + .isInstanceOf(ExtendedLongUpDownCounterBuilder.class); + Assertions.assertThat(meter.upDownCounterBuilder("test").build()) + .isInstanceOf(ExtendedLongUpDownCounter.class); + Assertions.assertThat(meter.upDownCounterBuilder("test").ofDoubles()) + .isInstanceOf(ExtendedDoubleUpDownCounterBuilder.class); + Assertions.assertThat(meter.upDownCounterBuilder("test").ofDoubles().build()) + .isInstanceOf(ExtendedDoubleUpDownCounter.class); + } +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerTest.java new file mode 100644 index 00000000000..1550796d42d --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/trace/ExtendedDefaultTracerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.trace; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.AbstractDefaultTracerTest; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class ExtendedDefaultTracerTest extends AbstractDefaultTracerTest { + + @Override + public Tracer getTracer() { + return ExtendedDefaultTracer.getNoop(); + } + + @Override + public TracerProvider getTracerProvider() { + return ExtendedDefaultTracerProvider.getNoop(); + } + + @Test + public void incubatingApiIsLoaded() { + Tracer tracer = TracerProvider.noop().get("test"); + assertThat(tracer).isSameAs(OpenTelemetry.noop().getTracer("test")); + + assertThat(tracer).isInstanceOf(ExtendedTracer.class); + assertThat(tracer.spanBuilder("test")).isInstanceOf(ExtendedSpanBuilder.class); + } + + @SuppressWarnings("unchecked") + @Test + public void incubatingApi() { + ExtendedSpanBuilder spanBuilder = + (ExtendedSpanBuilder) ExtendedDefaultTracer.getNoop().spanBuilder("test"); + assertThat(spanBuilder.setParentFrom(null, null)).isSameAs(spanBuilder); + + SpanRunnable spanRunnable = Mockito.mock(SpanRunnable.class); + + spanBuilder.startAndRun(spanRunnable); + Mockito.verify(spanRunnable).runInSpan(); + Mockito.reset(spanRunnable); + + spanBuilder.startAndRun(spanRunnable, null); + Mockito.verify(spanRunnable).runInSpan(); + Mockito.reset(spanRunnable); + + SpanCallable spanCallable = Mockito.mock(SpanCallable.class); + + spanBuilder.startAndCall(spanCallable); + Mockito.verify(spanCallable).callInSpan(); + Mockito.reset(spanCallable); + + spanBuilder.startAndCall(spanCallable, null); + Mockito.verify(spanCallable).callInSpan(); + Mockito.reset(spanCallable); + } +} diff --git a/integration-tests/graal-incubating/build.gradle.kts b/integration-tests/graal-incubating/build.gradle.kts new file mode 100644 index 00000000000..d050e01dee8 --- /dev/null +++ b/integration-tests/graal-incubating/build.gradle.kts @@ -0,0 +1,48 @@ +plugins { + id("otel.java-conventions") + id("org.graalvm.buildtools.native") +} + +description = "OpenTelemetry Graal Integration Tests (Incubating)" +otelJava.moduleName.set("io.opentelemetry.graal.integration.tests.incubating") + +sourceSets { + main { + // We need to ensure that we have the shadowed classes on the classpath, without this + // we will get the <:sdk:trace-shaded-deps> classes only, without the shadowed ones + val traceShadedDeps = project(":sdk:trace-shaded-deps") + output.dir(traceShadedDeps.file("build/extracted/shadow"), "builtBy" to ":sdk:trace-shaded-deps:extractShadowJar") + } +} + +dependencies { + implementation(project(":sdk:all")) + implementation(project(":sdk:trace-shaded-deps")) + implementation(project(":exporters:otlp:all")) + implementation(project(":api:incubator")) +} + +// org.graalvm.buildtools.native pluging requires java 11+ as of version 0.9.26 +// https://github.com/graalvm/native-build-tools/blob/master/docs/src/docs/asciidoc/index.adoc +tasks { + withType().configureEach { + sourceCompatibility = "11" + targetCompatibility = "11" + options.release.set(11) + } + withType().configureEach { + val testJavaVersion: String? by project + enabled = !testJavaVersion.equals("8") + } +} + +graalvmNative { + binaries { + named("test") { + // Required as of junit 5.10.0: https://junit.org/junit5/docs/5.10.0/release-notes/#deprecations-and-breaking-changes + buildArgs.add("--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig") + buildArgs.add("--initialize-at-build-time=org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter") + } + } + toolchainDetection.set(false) +} 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 new file mode 100644 index 00000000000..8d705419452 --- /dev/null +++ b/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.integrationtests.graal; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.incubator.logs.ExtendedLogger; +import io.opentelemetry.api.incubator.metrics.ExtendedLongCounterBuilder; +import io.opentelemetry.api.incubator.trace.ExtendedTracer; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerProvider; +import org.junit.jupiter.api.Test; + +class IncubatingApiTests { + @Test + void incubatingApiIsLoadedViaReflection() { + assertThat(LoggerProvider.noop().get("test")).isInstanceOf(ExtendedLogger.class); + assertThat(TracerProvider.noop().get("test")).isInstanceOf(ExtendedTracer.class); + assertThat(MeterProvider.noop().get("test").counterBuilder("test")) + .isInstanceOf(ExtendedLongCounterBuilder.class); + } +} diff --git a/integration-tests/graal/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingNotFoundApiTests.java b/integration-tests/graal/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingNotFoundApiTests.java new file mode 100644 index 00000000000..ba2ba02a2c3 --- /dev/null +++ b/integration-tests/graal/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingNotFoundApiTests.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.integrationtests.graal; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.LongCounterBuilder; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; +import org.junit.jupiter.api.Test; + +class IncubatingNotFoundApiTests { + @Test + void incubatingApiIsNotFoundViaReflection() { + assertThat(LoggerProvider.noop().get("test")).isInstanceOf(Logger.class); + assertThat(TracerProvider.noop().get("test")).isInstanceOf(Tracer.class); + assertThat(MeterProvider.noop().get("test").counterBuilder("test")) + .isInstanceOf(LongCounterBuilder.class); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 1ad4058a096..4bf7ca86538 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -48,6 +48,7 @@ include(":integration-tests") include(":integration-tests:otlp") include(":integration-tests:tracecontext") include(":integration-tests:graal") +include(":integration-tests:graal-incubating") include(":opencensus-shim") include(":opentracing-shim") include(":perf-harness")