Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't throw class cast exception when we have a noop tracer, meter, logger #6617

Merged
merged 12 commits into from
Sep 5, 2024
5 changes: 5 additions & 0 deletions api/all/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -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")
Expand All @@ -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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first usage of java-test-fixtures in this repo. I kind of like it, but would be good to update otel.java-conventions.gradle.kts to include all the standard test dependencies:
https://github.com/open-telemetry/opentelemetry-java/blob/main/buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts#L237-L270

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you give me a hint how to do that? fixtures { or similar doesn't exist

}

tasks.test {
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>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> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.api.logs;

import io.opentelemetry.api.internal.IncubatingUtil;
import javax.annotation.concurrent.ThreadSafe;

/**
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

package io.opentelemetry.api.metrics;

import io.opentelemetry.api.internal.IncubatingUtil;

/** A {@link MeterProvider} that does nothing. */
class DefaultMeterProvider implements MeterProvider {
@Override
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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
96 changes: 10 additions & 86 deletions api/all/src/test/java/io/opentelemetry/api/OpenTelemetryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

This file was deleted.

Loading
Loading