From 8a66ed909478bf76138704bc6858f971b13627bd Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Oct 2025 08:51:43 +0100 Subject: [PATCH 1/7] support ExtendedOpenTelemetry in GlobalOpenTelemetry --- .../api/GlobalOpenTelemetry.java | 49 ++------------ .../api/internal/IncubatingUtil.java | 66 +++++++++++++++++++ .../ObfuscatedExtendedOpenTelemetry.java | 63 ++++++++++++++++++ .../incubator/ExtendedOpenTelemetryTest.java | 20 ++++++ 4 files changed, 153 insertions(+), 45 deletions(-) create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java diff --git a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java index 5141307c343..f365a789694 100644 --- a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java +++ b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java @@ -7,7 +7,7 @@ import io.opentelemetry.api.internal.ConfigUtil; import io.opentelemetry.api.internal.GuardedBy; -import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.internal.IncubatingUtil; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.MeterBuilder; import io.opentelemetry.api.metrics.MeterProvider; @@ -21,7 +21,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; -import javax.annotation.concurrent.ThreadSafe; /** * A global singleton for the entrypoint to telemetry functionality for tracing, metrics and @@ -56,7 +55,7 @@ public final class GlobalOpenTelemetry { @SuppressWarnings("NonFinalStaticField") @Nullable - private static volatile ObfuscatedOpenTelemetry globalOpenTelemetry; + private static volatile OpenTelemetry globalOpenTelemetry; @SuppressWarnings("NonFinalStaticField") @GuardedBy("mutex") @@ -112,7 +111,7 @@ public static void set(OpenTelemetry openTelemetry) { + "instead. Previous invocation set to cause of this exception.", setGlobalCaller); } - globalOpenTelemetry = new ObfuscatedOpenTelemetry(openTelemetry); + globalOpenTelemetry = IncubatingUtil.obfuscatedOpenTelemetry(openTelemetry); setGlobalCaller = new Throwable(); } } @@ -261,7 +260,7 @@ private static OpenTelemetry maybeAutoConfigureAndSetGlobal() { Object autoConfiguredSdk = initialize.invoke(null); Method getOpenTelemetrySdk = openTelemetrySdkAutoConfiguration.getMethod("getOpenTelemetrySdk"); - return new ObfuscatedOpenTelemetry( + return IncubatingUtil.obfuscatedOpenTelemetry( (OpenTelemetry) getOpenTelemetrySdk.invoke(autoConfiguredSdk)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new IllegalStateException( @@ -276,44 +275,4 @@ private static OpenTelemetry maybeAutoConfigureAndSetGlobal() { return null; } } - - /** - * Static global instances are obfuscated when they are returned from the API to prevent users - * from casting them to their SDK-specific implementation. For example, we do not want users to - * use patterns like {@code (OpenTelemetrySdk) GlobalOpenTelemetry.get()}. - */ - @ThreadSafe - static class ObfuscatedOpenTelemetry implements OpenTelemetry { - - private final OpenTelemetry delegate; - - ObfuscatedOpenTelemetry(OpenTelemetry delegate) { - this.delegate = delegate; - } - - @Override - public TracerProvider getTracerProvider() { - return delegate.getTracerProvider(); - } - - @Override - public MeterProvider getMeterProvider() { - return delegate.getMeterProvider(); - } - - @Override - public LoggerProvider getLogsBridge() { - return delegate.getLogsBridge(); - } - - @Override - public ContextPropagators getPropagators() { - return delegate.getPropagators(); - } - - @Override - public TracerBuilder tracerBuilder(String instrumentationScopeName) { - return delegate.tracerBuilder(instrumentationScopeName); - } - } } 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 index 1ef82d373f2..44f15904c4f 100644 --- a/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java +++ b/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java @@ -5,6 +5,13 @@ package io.opentelemetry.api.internal; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerBuilder; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; +import javax.annotation.concurrent.ThreadSafe; import java.lang.reflect.Method; /** @@ -26,4 +33,63 @@ public static T incubatingApiIfAvailable(T stableApi, String incubatingClass return stableApi; } } + + public static OpenTelemetry obfuscatedOpenTelemetry(OpenTelemetry openTelemetry) { + try { + Class extendedClass = + Class.forName("io.opentelemetry.api.incubator.ExtendedOpenTelemetry"); + if (extendedClass.isInstance(openTelemetry)) { + Class incubatingClass = + Class.forName( + "io.opentelemetry.api.incubator.internal.ObfuscatedExtendedOpenTelemetry"); + return (OpenTelemetry) + incubatingClass + .getDeclaredConstructor(extendedClass) + .newInstance(extendedClass.cast(openTelemetry)); + } + } catch (Exception e) { + // incubator not available + } + return new ObfuscatedOpenTelemetry(openTelemetry); + } + + /** + * Static global instances are obfuscated when they are returned from the API to prevent users + * from casting them to their SDK-specific implementation. For example, we do not want users to + * use patterns like {@code (OpenTelemetrySdk) GlobalOpenTelemetry.get()}. + */ + @ThreadSafe + static class ObfuscatedOpenTelemetry implements OpenTelemetry { + + private final OpenTelemetry delegate; + + ObfuscatedOpenTelemetry(OpenTelemetry delegate) { + this.delegate = delegate; + } + + @Override + public TracerProvider getTracerProvider() { + return delegate.getTracerProvider(); + } + + @Override + public MeterProvider getMeterProvider() { + return delegate.getMeterProvider(); + } + + @Override + public LoggerProvider getLogsBridge() { + return delegate.getLogsBridge(); + } + + @Override + public ContextPropagators getPropagators() { + return delegate.getPropagators(); + } + + @Override + public TracerBuilder tracerBuilder(String instrumentationScopeName) { + return delegate.tracerBuilder(instrumentationScopeName); + } + } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java new file mode 100644 index 00000000000..e45b6bf102e --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java @@ -0,0 +1,63 @@ +package io.opentelemetry.api.incubator.internal; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerBuilder; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Static global instances are obfuscated when they are returned from the API to prevent users from + * casting them to their SDK-specific implementation. For example, we do not want users to use + * patterns like {@code (OpenTelemetrySdk) GlobalOpenTelemetry.get()}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@ThreadSafe +public final class ObfuscatedExtendedOpenTelemetry implements ExtendedOpenTelemetry { + + private final ExtendedOpenTelemetry delegate; + + /** + * This constructor is called via reflection from {@link + * io.opentelemetry.api.internal.IncubatingUtil#obfuscatedOpenTelemetry(OpenTelemetry)} + */ + public ObfuscatedExtendedOpenTelemetry(ExtendedOpenTelemetry delegate) { + this.delegate = delegate; + } + + @Override + public TracerProvider getTracerProvider() { + return delegate.getTracerProvider(); + } + + @Override + public MeterProvider getMeterProvider() { + return delegate.getMeterProvider(); + } + + @Override + public LoggerProvider getLogsBridge() { + return delegate.getLogsBridge(); + } + + @Override + public ContextPropagators getPropagators() { + return delegate.getPropagators(); + } + + @Override + public TracerBuilder tracerBuilder(String instrumentationScopeName) { + return delegate.tracerBuilder(instrumentationScopeName); + } + + @Override + public ConfigProvider getConfigProvider() { + return delegate.getConfigProvider(); + } +} 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 index 4903d00c2e6..651eae4bc14 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.incubator.logs.ExtendedDefaultLoggerProvider; import io.opentelemetry.api.incubator.logs.ExtendedLogger; @@ -19,6 +20,11 @@ import io.opentelemetry.api.testing.internal.AbstractOpenTelemetryTest; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.ExtendedOpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class ExtendedOpenTelemetryTest extends AbstractOpenTelemetryTest { @@ -38,12 +44,26 @@ protected LoggerProvider getLoggerProvider() { return ExtendedDefaultLoggerProvider.getNoop(); } + @BeforeEach + void setUp() { + GlobalOpenTelemetry.resetForTest(); + } + @Test void incubatingApiIsLoaded() { assertIsExtended(OpenTelemetry.noop()); assertIsExtended(OpenTelemetry.propagating(ContextPropagators.noop())); } + @Test + void globalOpenTelemetry() { + GlobalOpenTelemetry.set( + ExtendedOpenTelemetrySdk.create( + OpenTelemetrySdk.builder().build(), + SdkConfigProvider.create(new OpenTelemetryConfigurationModel()))); + assertThat(GlobalOpenTelemetry.get()).isInstanceOf(ExtendedOpenTelemetry.class); + } + private static void assertIsExtended(OpenTelemetry openTelemetry) { assertThat(openTelemetry.getMeter("test").counterBuilder("test")) .isInstanceOf(ExtendedLongCounterBuilder.class); From 7f9124d9aac5fd80834539a99b194f250e491424 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Oct 2025 09:14:26 +0100 Subject: [PATCH 2/7] format --- .../java/io/opentelemetry/api/internal/IncubatingUtil.java | 2 +- .../incubator/internal/ObfuscatedExtendedOpenTelemetry.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 index 44f15904c4f..c2242c88b96 100644 --- a/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java +++ b/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java @@ -11,8 +11,8 @@ import io.opentelemetry.api.trace.TracerBuilder; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; -import javax.annotation.concurrent.ThreadSafe; import java.lang.reflect.Method; +import javax.annotation.concurrent.ThreadSafe; /** * Incubating utilities. diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java index e45b6bf102e..9236be408e6 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.api.incubator.internal; import io.opentelemetry.api.OpenTelemetry; From eeab542298fa43d9675629026adc92818814e648 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Oct 2025 11:16:51 +0100 Subject: [PATCH 3/7] format --- .../api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java index 9236be408e6..d90528f64ec 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java @@ -30,7 +30,7 @@ public final class ObfuscatedExtendedOpenTelemetry implements ExtendedOpenTeleme /** * This constructor is called via reflection from {@link - * io.opentelemetry.api.internal.IncubatingUtil#obfuscatedOpenTelemetry(OpenTelemetry)} + * io.opentelemetry.api.internal.IncubatingUtil#obfuscatedOpenTelemetry(OpenTelemetry)}. */ public ObfuscatedExtendedOpenTelemetry(ExtendedOpenTelemetry delegate) { this.delegate = delegate; From 74f1fc45985bd4a3a5fd5ae7c7fe164345946156 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Oct 2025 13:02:52 +0100 Subject: [PATCH 4/7] fix --- .../sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java index 8ed8c578693..6de64f10ad6 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java @@ -758,7 +758,7 @@ void globalOpenTelemetryLock() throws InterruptedException, ExecutionException, private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) { try { Field delegateField = - Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry") + Class.forName("io.opentelemetry.api.internal.IncubatingUtil$ObfuscatedOpenTelemetry") .getDeclaredField("delegate"); delegateField.setAccessible(true); Object delegate = delegateField.get(openTelemetry); From d223ebed1870f3abcbf3b56da455169dba84f051 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Oct 2025 13:32:30 +0100 Subject: [PATCH 5/7] fix --- .../sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java b/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java index f630b814cb7..e813e94538e 100644 --- a/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java +++ b/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java @@ -91,7 +91,7 @@ void globalOpenTelemetry_AutoConfigureEnabled() { private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) { try { Field delegateField = - Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry") + Class.forName("io.opentelemetry.api.internal.IncubatingUtil$ObfuscatedOpenTelemetry") .getDeclaredField("delegate"); delegateField.setAccessible(true); Object delegate = delegateField.get(openTelemetry); From fdc808c2a9ba7c5da21916f177aa52ca4d999cc5 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Sun, 2 Nov 2025 10:54:56 +0100 Subject: [PATCH 6/7] pr review --- .../api/GlobalOpenTelemetry.java | 55 ++++++++++++++++++- .../api/internal/IncubatingUtil.java | 52 ++---------------- .../ObfuscatedExtendedOpenTelemetry.java | 2 +- .../AutoConfiguredOpenTelemetrySdkTest.java | 2 +- .../AutoConfiguredOpenTelemetrySdkTest.java | 2 +- 5 files changed, 59 insertions(+), 54 deletions(-) diff --git a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java index f365a789694..5e3a1e0ecdb 100644 --- a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java +++ b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.internal.ConfigUtil; import io.opentelemetry.api.internal.GuardedBy; import io.opentelemetry.api.internal.IncubatingUtil; +import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.MeterBuilder; import io.opentelemetry.api.metrics.MeterProvider; @@ -21,6 +22,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; +import javax.annotation.concurrent.ThreadSafe; /** * A global singleton for the entrypoint to telemetry functionality for tracing, metrics and @@ -111,7 +113,7 @@ public static void set(OpenTelemetry openTelemetry) { + "instead. Previous invocation set to cause of this exception.", setGlobalCaller); } - globalOpenTelemetry = IncubatingUtil.obfuscatedOpenTelemetry(openTelemetry); + globalOpenTelemetry = obfuscatedOpenTelemetry(openTelemetry); setGlobalCaller = new Throwable(); } } @@ -260,8 +262,7 @@ private static OpenTelemetry maybeAutoConfigureAndSetGlobal() { Object autoConfiguredSdk = initialize.invoke(null); Method getOpenTelemetrySdk = openTelemetrySdkAutoConfiguration.getMethod("getOpenTelemetrySdk"); - return IncubatingUtil.obfuscatedOpenTelemetry( - (OpenTelemetry) getOpenTelemetrySdk.invoke(autoConfiguredSdk)); + return obfuscatedOpenTelemetry((OpenTelemetry) getOpenTelemetrySdk.invoke(autoConfiguredSdk)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new IllegalStateException( "AutoConfiguredOpenTelemetrySdk detected on classpath " @@ -275,4 +276,52 @@ private static OpenTelemetry maybeAutoConfigureAndSetGlobal() { return null; } } + + private static OpenTelemetry obfuscatedOpenTelemetry(OpenTelemetry openTelemetry) { + OpenTelemetry incubating = IncubatingUtil.obfuscatedOpenTelemetryIfIncubating(openTelemetry); + if (incubating != null) { + return incubating; + } + return new ObfuscatedOpenTelemetry(openTelemetry); + } + + /** + * Static global instances are obfuscated when they are returned from the API to prevent users + * from casting them to their SDK-specific implementation. For example, we do not want users to + * use patterns like {@code (OpenTelemetrySdk) GlobalOpenTelemetry.get()}. + */ + @ThreadSafe + static class ObfuscatedOpenTelemetry implements OpenTelemetry { + + private final OpenTelemetry delegate; + + ObfuscatedOpenTelemetry(OpenTelemetry delegate) { + this.delegate = delegate; + } + + @Override + public TracerProvider getTracerProvider() { + return delegate.getTracerProvider(); + } + + @Override + public MeterProvider getMeterProvider() { + return delegate.getMeterProvider(); + } + + @Override + public LoggerProvider getLogsBridge() { + return delegate.getLogsBridge(); + } + + @Override + public ContextPropagators getPropagators() { + return delegate.getPropagators(); + } + + @Override + public TracerBuilder tracerBuilder(String instrumentationScopeName) { + return delegate.tracerBuilder(instrumentationScopeName); + } + } } 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 index c2242c88b96..e03b1e22f8c 100644 --- a/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java +++ b/api/all/src/main/java/io/opentelemetry/api/internal/IncubatingUtil.java @@ -6,13 +6,8 @@ package io.opentelemetry.api.internal; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.logs.LoggerProvider; -import io.opentelemetry.api.metrics.MeterProvider; -import io.opentelemetry.api.trace.TracerBuilder; -import io.opentelemetry.api.trace.TracerProvider; -import io.opentelemetry.context.propagation.ContextPropagators; import java.lang.reflect.Method; -import javax.annotation.concurrent.ThreadSafe; +import javax.annotation.Nullable; /** * Incubating utilities. @@ -34,7 +29,8 @@ public static T incubatingApiIfAvailable(T stableApi, String incubatingClass } } - public static OpenTelemetry obfuscatedOpenTelemetry(OpenTelemetry openTelemetry) { + @Nullable + public static OpenTelemetry obfuscatedOpenTelemetryIfIncubating(OpenTelemetry openTelemetry) { try { Class extendedClass = Class.forName("io.opentelemetry.api.incubator.ExtendedOpenTelemetry"); @@ -50,46 +46,6 @@ public static OpenTelemetry obfuscatedOpenTelemetry(OpenTelemetry openTelemetry) } catch (Exception e) { // incubator not available } - return new ObfuscatedOpenTelemetry(openTelemetry); - } - - /** - * Static global instances are obfuscated when they are returned from the API to prevent users - * from casting them to their SDK-specific implementation. For example, we do not want users to - * use patterns like {@code (OpenTelemetrySdk) GlobalOpenTelemetry.get()}. - */ - @ThreadSafe - static class ObfuscatedOpenTelemetry implements OpenTelemetry { - - private final OpenTelemetry delegate; - - ObfuscatedOpenTelemetry(OpenTelemetry delegate) { - this.delegate = delegate; - } - - @Override - public TracerProvider getTracerProvider() { - return delegate.getTracerProvider(); - } - - @Override - public MeterProvider getMeterProvider() { - return delegate.getMeterProvider(); - } - - @Override - public LoggerProvider getLogsBridge() { - return delegate.getLogsBridge(); - } - - @Override - public ContextPropagators getPropagators() { - return delegate.getPropagators(); - } - - @Override - public TracerBuilder tracerBuilder(String instrumentationScopeName) { - return delegate.tracerBuilder(instrumentationScopeName); - } + return null; } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java index d90528f64ec..93a0b90ea91 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetry.java @@ -30,7 +30,7 @@ public final class ObfuscatedExtendedOpenTelemetry implements ExtendedOpenTeleme /** * This constructor is called via reflection from {@link - * io.opentelemetry.api.internal.IncubatingUtil#obfuscatedOpenTelemetry(OpenTelemetry)}. + * io.opentelemetry.api.internal.IncubatingUtil#obfuscatedOpenTelemetryIfIncubating(OpenTelemetry)}. */ public ObfuscatedExtendedOpenTelemetry(ExtendedOpenTelemetry delegate) { this.delegate = delegate; diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java index 6de64f10ad6..8ed8c578693 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java @@ -758,7 +758,7 @@ void globalOpenTelemetryLock() throws InterruptedException, ExecutionException, private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) { try { Field delegateField = - Class.forName("io.opentelemetry.api.internal.IncubatingUtil$ObfuscatedOpenTelemetry") + Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry") .getDeclaredField("delegate"); delegateField.setAccessible(true); Object delegate = delegateField.get(openTelemetry); diff --git a/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java b/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java index e813e94538e..f630b814cb7 100644 --- a/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java +++ b/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java @@ -91,7 +91,7 @@ void globalOpenTelemetry_AutoConfigureEnabled() { private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) { try { Field delegateField = - Class.forName("io.opentelemetry.api.internal.IncubatingUtil$ObfuscatedOpenTelemetry") + Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry") .getDeclaredField("delegate"); delegateField.setAccessible(true); Object delegate = delegateField.get(openTelemetry); From 2798f9f63b6a3e0a02a93b624220ab578df33696 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 3 Nov 2025 07:47:32 +0100 Subject: [PATCH 7/7] add coverage --- .../ObfuscatedExtendedOpenTelemetryTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 api/incubator/src/test/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetryTest.java diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetryTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetryTest.java new file mode 100644 index 00000000000..5752419bb78 --- /dev/null +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/internal/ObfuscatedExtendedOpenTelemetryTest.java @@ -0,0 +1,62 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerBuilder; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; +import org.junit.jupiter.api.Test; + +class ObfuscatedExtendedOpenTelemetryTest { + + @Test + void delegatesAllCallsToDelegate() { + ExtendedOpenTelemetry delegate = mock(ExtendedOpenTelemetry.class); + + TracerProvider tracerProvider = mock(TracerProvider.class); + MeterProvider meterProvider = mock(MeterProvider.class); + LoggerProvider loggerProvider = mock(LoggerProvider.class); + ContextPropagators propagators = mock(ContextPropagators.class); + TracerBuilder tracerBuilder = mock(TracerBuilder.class); + ConfigProvider configProvider = mock(ConfigProvider.class); + + when(delegate.getTracerProvider()).thenReturn(tracerProvider); + when(delegate.getMeterProvider()).thenReturn(meterProvider); + when(delegate.getLogsBridge()).thenReturn(loggerProvider); + when(delegate.getPropagators()).thenReturn(propagators); + when(delegate.tracerBuilder("test-instrumentation")).thenReturn(tracerBuilder); + when(delegate.getConfigProvider()).thenReturn(configProvider); + + ObfuscatedExtendedOpenTelemetry obfuscated = new ObfuscatedExtendedOpenTelemetry(delegate); + + assertThat(obfuscated.getTracerProvider()).isSameAs(tracerProvider); + verify(delegate).getTracerProvider(); + + assertThat(obfuscated.getMeterProvider()).isSameAs(meterProvider); + verify(delegate).getMeterProvider(); + + assertThat(obfuscated.getLogsBridge()).isSameAs(loggerProvider); + verify(delegate).getLogsBridge(); + + assertThat(obfuscated.getPropagators()).isSameAs(propagators); + verify(delegate).getPropagators(); + + assertThat(obfuscated.tracerBuilder("test-instrumentation")).isSameAs(tracerBuilder); + verify(delegate).tracerBuilder("test-instrumentation"); + + assertThat(obfuscated.getConfigProvider()).isSameAs(configProvider); + verify(delegate).getConfigProvider(); + } +}