Skip to content

Commit

Permalink
don't throw class cast exception when we have a noop tracer, meter, l…
Browse files Browse the repository at this point in the history
…ogger (#6617)

Co-authored-by: Jack Berg <jberg@newrelic.com>
  • Loading branch information
zeitlinger and jack-berg committed Sep 5, 2024
1 parent 1f6de35 commit f85a57b
Show file tree
Hide file tree
Showing 34 changed files with 1,889 additions and 536 deletions.
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")
}

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

0 comments on commit f85a57b

Please sign in to comment.