From 1d5245f3be7ab2510f961d6ee02073a3e41f427e Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 23 May 2025 23:37:58 +0200 Subject: [PATCH 01/17] hold mutex --- ...AutoConfiguredOpenTelemetrySdkBuilder.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index e12848f0d81..256c4c2d675 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -36,6 +36,7 @@ import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; import java.io.IOException; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -424,6 +425,10 @@ AutoConfiguredOpenTelemetrySdkBuilder setComponentLoader(ComponentLoader compone * the settings of this {@link AutoConfiguredOpenTelemetrySdkBuilder}. */ public AutoConfiguredOpenTelemetrySdk build() { + return maybeRunWithGlobalOpenTelemetryLock(this::buildImpl); + } + + private AutoConfiguredOpenTelemetrySdk buildImpl() { SpiHelper spiHelper = SpiHelper.create(componentLoader); if (!customized) { customized = true; @@ -572,6 +577,34 @@ private void maybeRegisterShutdownHook(OpenTelemetrySdk openTelemetrySdk) { Runtime.getRuntime().addShutdownHook(shutdownHook(openTelemetrySdk)); } + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + private T maybeRunWithGlobalOpenTelemetryLock(Supplier supplier) { + if (setResultAsGlobal) { + return supplier.get(); + } + + Object mutex = null; + try { + Field mutexField = GlobalOpenTelemetry.class.getDeclaredField("mutex"); + mutexField.setAccessible(true); + mutex = mutexField.get(null); + if (mutex == null) { + logger.log( + Level.SEVERE, + "Found a null Global OpenTelemetry mutex, this is a bug in the opentelemetry-java SDK and should be reported"); + } + } catch (Exception exception) { + logger.log(Level.WARNING, "Could not acquire Global OpenTelemetry mutex", exception); + } + + if (mutex == null) { + return supplier.get(); + } + synchronized (mutex) { + return supplier.get(); + } + } + private void maybeSetAsGlobal( OpenTelemetrySdk openTelemetrySdk, @Nullable Object configProvider) { if (!setResultAsGlobal) { From 89181a928b086d6a2a1a2a780d21c2f2d6d8de7d Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 23 May 2025 23:56:44 +0200 Subject: [PATCH 02/17] test --- ...AutoConfiguredOpenTelemetrySdkBuilder.java | 21 ++++++++++++------- ...ConfiguredOpenTelemetrySdkBuilderTest.java | 18 ++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index 256c4c2d675..a39524cc0af 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -577,12 +577,23 @@ private void maybeRegisterShutdownHook(OpenTelemetrySdk openTelemetrySdk) { Runtime.getRuntime().addShutdownHook(shutdownHook(openTelemetrySdk)); } - @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") private T maybeRunWithGlobalOpenTelemetryLock(Supplier supplier) { if (setResultAsGlobal) { return supplier.get(); } + Object mutex = getGlobalOpenTelemetryLock(); + if (mutex == null) { + return supplier.get(); + } + synchronized (mutex) { + return supplier.get(); + } + } + + // Visible for testing + @Nullable + static Object getGlobalOpenTelemetryLock() { Object mutex = null; try { Field mutexField = GlobalOpenTelemetry.class.getDeclaredField("mutex"); @@ -596,13 +607,7 @@ private T maybeRunWithGlobalOpenTelemetryLock(Supplier supplier) { } catch (Exception exception) { logger.log(Level.WARNING, "Could not acquire Global OpenTelemetry mutex", exception); } - - if (mutex == null) { - return supplier.get(); - } - synchronized (mutex) { - return supplier.get(); - } + return mutex; } private void maybeSetAsGlobal( diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java new file mode 100644 index 00000000000..0b7b655c931 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.autoconfigure; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class AutoConfiguredOpenTelemetrySdkBuilderTest { + + @Test + void getGlobalOpenTelemetryLock_findsLock() { + assertThat(AutoConfiguredOpenTelemetrySdkBuilder.getGlobalOpenTelemetryLock()).isNotNull(); + } +} From 06ff8eb91ee9dea740c74c532912f23d6f8cf47a Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 23 May 2025 23:58:39 +0200 Subject: [PATCH 03/17] fix condition --- .../AutoConfiguredOpenTelemetrySdkBuilder.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index a39524cc0af..c2146a49e9e 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -578,12 +578,8 @@ private void maybeRegisterShutdownHook(OpenTelemetrySdk openTelemetrySdk) { } private T maybeRunWithGlobalOpenTelemetryLock(Supplier supplier) { - if (setResultAsGlobal) { - return supplier.get(); - } - - Object mutex = getGlobalOpenTelemetryLock(); - if (mutex == null) { + Object mutex; + if (!setResultAsGlobal || (mutex = getGlobalOpenTelemetryLock()) == null) { return supplier.get(); } synchronized (mutex) { From 2ff428b10c47f59be2c72cc61b600906db0782e8 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 8 Jun 2025 16:49:10 +0000 Subject: [PATCH 04/17] review comments --- .../api/GlobalOpenTelemetry.java | 9 +++ .../AutoConfiguredOpenTelemetrySdk.java | 26 ++++++++- ...AutoConfiguredOpenTelemetrySdkBuilder.java | 57 ++++--------------- ...ConfiguredOpenTelemetrySdkBuilderTest.java | 18 ------ 4 files changed, 44 insertions(+), 66 deletions(-) delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.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 230a85e06a9..7b4adeca8f5 100644 --- a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java +++ b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java @@ -17,6 +17,7 @@ import io.opentelemetry.context.propagation.ContextPropagators; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; @@ -116,6 +117,14 @@ public static void set(OpenTelemetry openTelemetry) { } } + public static T set(Supplier supplier) { + synchronized (mutex) { + T openTelemetry = supplier.get(); + set(openTelemetry); + return openTelemetry; + } + } + /** Returns the globally registered {@link TracerProvider}. */ public static TracerProvider getTracerProvider() { return get().getTracerProvider(); diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java index c5d9c77f4ee..9d10eff135b 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java @@ -9,6 +9,10 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.incubator.config.ConfigProvider; +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 io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -25,7 +29,7 @@ */ @Immutable @AutoValue -public abstract class AutoConfiguredOpenTelemetrySdk { +public abstract class AutoConfiguredOpenTelemetrySdk implements OpenTelemetry { /** * Returns an {@link AutoConfiguredOpenTelemetrySdk} automatically initialized through recognized @@ -90,4 +94,24 @@ static AutoConfiguredOpenTelemetrySdk create( abstract Object getConfigProvider(); AutoConfiguredOpenTelemetrySdk() {} + + @Override + public TracerProvider getTracerProvider() { + return getOpenTelemetrySdk().getTracerProvider(); + } + + @Override + public MeterProvider getMeterProvider() { + return getOpenTelemetrySdk().getMeterProvider(); + } + + @Override + public LoggerProvider getLogsBridge() { + return getOpenTelemetrySdk().getLogsBridge(); + } + + @Override + public ContextPropagators getPropagators() { + return getOpenTelemetrySdk().getPropagators(); + } } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index c2146a49e9e..5df07f410a3 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -36,7 +36,6 @@ import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; import java.io.IOException; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -425,7 +424,12 @@ AutoConfiguredOpenTelemetrySdkBuilder setComponentLoader(ComponentLoader compone * the settings of this {@link AutoConfiguredOpenTelemetrySdkBuilder}. */ public AutoConfiguredOpenTelemetrySdk build() { - return maybeRunWithGlobalOpenTelemetryLock(this::buildImpl); + if (!setResultAsGlobal) { + return buildImpl(); + } + AutoConfiguredOpenTelemetrySdk sdk = GlobalOpenTelemetry.set(this::buildImpl); + logger.log(Level.FINE, "Global OpenTelemetry set to {0} by autoconfiguration", sdk); + return sdk; } private AutoConfiguredOpenTelemetrySdk buildImpl() { @@ -445,8 +449,10 @@ private AutoConfiguredOpenTelemetrySdk buildImpl() { maybeConfigureFromFile(config, componentLoader); if (fromFileConfiguration != null) { maybeRegisterShutdownHook(fromFileConfiguration.getOpenTelemetrySdk()); - maybeSetAsGlobal( - fromFileConfiguration.getOpenTelemetrySdk(), fromFileConfiguration.getConfigProvider()); + Object configProvider = fromFileConfiguration.getConfigProvider(); + if (setResultAsGlobal && INCUBATOR_AVAILABLE && configProvider != null) { + IncubatingUtil.setGlobalConfigProvider(configProvider); + } return fromFileConfiguration; } @@ -472,7 +478,6 @@ private AutoConfiguredOpenTelemetrySdk buildImpl() { OpenTelemetrySdk openTelemetrySdk = sdkBuilder.build(); maybeRegisterShutdownHook(openTelemetrySdk); - maybeSetAsGlobal(openTelemetrySdk, null); callAutoConfigureListeners(spiHelper, openTelemetrySdk); return AutoConfiguredOpenTelemetrySdk.create(openTelemetrySdk, resource, config, null); @@ -577,48 +582,6 @@ private void maybeRegisterShutdownHook(OpenTelemetrySdk openTelemetrySdk) { Runtime.getRuntime().addShutdownHook(shutdownHook(openTelemetrySdk)); } - private T maybeRunWithGlobalOpenTelemetryLock(Supplier supplier) { - Object mutex; - if (!setResultAsGlobal || (mutex = getGlobalOpenTelemetryLock()) == null) { - return supplier.get(); - } - synchronized (mutex) { - return supplier.get(); - } - } - - // Visible for testing - @Nullable - static Object getGlobalOpenTelemetryLock() { - Object mutex = null; - try { - Field mutexField = GlobalOpenTelemetry.class.getDeclaredField("mutex"); - mutexField.setAccessible(true); - mutex = mutexField.get(null); - if (mutex == null) { - logger.log( - Level.SEVERE, - "Found a null Global OpenTelemetry mutex, this is a bug in the opentelemetry-java SDK and should be reported"); - } - } catch (Exception exception) { - logger.log(Level.WARNING, "Could not acquire Global OpenTelemetry mutex", exception); - } - return mutex; - } - - private void maybeSetAsGlobal( - OpenTelemetrySdk openTelemetrySdk, @Nullable Object configProvider) { - if (!setResultAsGlobal) { - return; - } - GlobalOpenTelemetry.set(openTelemetrySdk); - if (INCUBATOR_AVAILABLE && configProvider != null) { - IncubatingUtil.setGlobalConfigProvider(configProvider); - } - logger.log( - Level.FINE, "Global OpenTelemetry set to {0} by autoconfiguration", openTelemetrySdk); - } - // Visible for testing void callAutoConfigureListeners(SpiHelper spiHelper, OpenTelemetrySdk openTelemetrySdk) { for (AutoConfigureListener listener : spiHelper.getListeners()) { diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java deleted file mode 100644 index 0b7b655c931..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilderTest.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.autoconfigure; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -class AutoConfiguredOpenTelemetrySdkBuilderTest { - - @Test - void getGlobalOpenTelemetryLock_findsLock() { - assertThat(AutoConfiguredOpenTelemetrySdkBuilder.getGlobalOpenTelemetryLock()).isNotNull(); - } -} From 70aede17f23ef4e7163dc598ae9c1c55a22be659 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 8 Jun 2025 20:54:19 +0000 Subject: [PATCH 05/17] fix test --- .../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 c7ae65de9a0..8e3abff52a1 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 @@ -374,7 +374,7 @@ void builder_setResultAsGlobalFalse() { @Test void builder_setResultAsGlobalTrue() { - OpenTelemetrySdk openTelemetry = builder.setResultAsGlobal().build().getOpenTelemetrySdk(); + OpenTelemetry openTelemetry = builder.setResultAsGlobal().build(); assertThat(GlobalOpenTelemetry.get()).extracting("delegate").isSameAs(openTelemetry); } From e0d0405a33b3dcf90ada6d33a28db38856170668 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 8 Jun 2025 21:53:31 +0000 Subject: [PATCH 06/17] supplier and then function --- .../api/GlobalOpenTelemetry.java | 16 +++++++++--- .../AutoConfiguredOpenTelemetrySdk.java | 26 +------------------ ...AutoConfiguredOpenTelemetrySdkBuilder.java | 4 ++- .../AutoConfiguredOpenTelemetrySdkTest.java | 2 +- 4 files changed, 17 insertions(+), 31 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 7b4adeca8f5..3e9623a4eff 100644 --- a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java +++ b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java @@ -17,6 +17,7 @@ import io.opentelemetry.context.propagation.ContextPropagators; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -117,11 +118,18 @@ public static void set(OpenTelemetry openTelemetry) { } } - public static T set(Supplier supplier) { + /** + * Sets the {@link OpenTelemetry} that should be the global instance. + * + *

This method calls the given {@code supplier}, converts the output to an {@link + * OpenTelemetry} object, and finally calls {@link #set(OpenTelemetry)}, all while holding the + * {@link GlobalOpenTelemetry} mutex. + */ + public static T set(Supplier supplier, Function converter) { synchronized (mutex) { - T openTelemetry = supplier.get(); - set(openTelemetry); - return openTelemetry; + T output = supplier.get(); + set(converter.apply(output)); + return output; } } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java index 9d10eff135b..c5d9c77f4ee 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdk.java @@ -9,10 +9,6 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.incubator.config.ConfigProvider; -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 io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -29,7 +25,7 @@ */ @Immutable @AutoValue -public abstract class AutoConfiguredOpenTelemetrySdk implements OpenTelemetry { +public abstract class AutoConfiguredOpenTelemetrySdk { /** * Returns an {@link AutoConfiguredOpenTelemetrySdk} automatically initialized through recognized @@ -94,24 +90,4 @@ static AutoConfiguredOpenTelemetrySdk create( abstract Object getConfigProvider(); AutoConfiguredOpenTelemetrySdk() {} - - @Override - public TracerProvider getTracerProvider() { - return getOpenTelemetrySdk().getTracerProvider(); - } - - @Override - public MeterProvider getMeterProvider() { - return getOpenTelemetrySdk().getMeterProvider(); - } - - @Override - public LoggerProvider getLogsBridge() { - return getOpenTelemetrySdk().getLogsBridge(); - } - - @Override - public ContextPropagators getPropagators() { - return getOpenTelemetrySdk().getPropagators(); - } } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index 5df07f410a3..e91d44270b3 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -427,7 +427,9 @@ public AutoConfiguredOpenTelemetrySdk build() { if (!setResultAsGlobal) { return buildImpl(); } - AutoConfiguredOpenTelemetrySdk sdk = GlobalOpenTelemetry.set(this::buildImpl); + AutoConfiguredOpenTelemetrySdk sdk = + GlobalOpenTelemetry.set( + this::buildImpl, AutoConfiguredOpenTelemetrySdk::getOpenTelemetrySdk); logger.log(Level.FINE, "Global OpenTelemetry set to {0} by autoconfiguration", sdk); return sdk; } 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 8e3abff52a1..c7ae65de9a0 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 @@ -374,7 +374,7 @@ void builder_setResultAsGlobalFalse() { @Test void builder_setResultAsGlobalTrue() { - OpenTelemetry openTelemetry = builder.setResultAsGlobal().build(); + OpenTelemetrySdk openTelemetry = builder.setResultAsGlobal().build().getOpenTelemetrySdk(); assertThat(GlobalOpenTelemetry.get()).extracting("delegate").isSameAs(openTelemetry); } From 5dbbbc17adf89adfc2307df8858504a466099ee5 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Sun, 8 Jun 2025 22:30:42 +0000 Subject: [PATCH 07/17] new api --- docs/apidiffs/current_vs_latest/opentelemetry-api.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt index fa356d6958e..bc383776af9 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt @@ -1,2 +1,5 @@ -Comparing source compatibility of opentelemetry-api-1.51.0-SNAPSHOT.jar against opentelemetry-api-1.50.0.jar -No changes. \ No newline at end of file +Comparing source compatibility of opentelemetry-api-1.51.0-SNAPSHOT.jar against opentelemetry-api-1.51.0.jar +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.api.GlobalOpenTelemetry (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) STATIC(+) java.lang.Object set(java.util.function.Supplier, java.util.function.Function) + GENERIC TEMPLATES: +++ T:java.lang.Object From 69202789b6b8a6db4b39fce834dccbacc5d4da5a Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Mon, 9 Jun 2025 13:26:23 -0500 Subject: [PATCH 08/17] Adjust API to be only supplier --- .../io/opentelemetry/api/GlobalOpenTelemetry.java | 10 ++++------ .../AutoConfiguredOpenTelemetrySdkBuilder.java | 12 +++++++----- 2 files changed, 11 insertions(+), 11 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 3e9623a4eff..0ffe16961fe 100644 --- a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java +++ b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java @@ -121,15 +121,13 @@ public static void set(OpenTelemetry openTelemetry) { /** * Sets the {@link OpenTelemetry} that should be the global instance. * - *

This method calls the given {@code supplier}, converts the output to an {@link - * OpenTelemetry} object, and finally calls {@link #set(OpenTelemetry)}, all while holding the + *

This method calls the given {@code supplier} and calls {@link #set(OpenTelemetry)}, all while holding the * {@link GlobalOpenTelemetry} mutex. */ - public static T set(Supplier supplier, Function converter) { + public static void set(Supplier supplier) { synchronized (mutex) { - T output = supplier.get(); - set(converter.apply(output)); - return output; + OpenTelemetry openTelemetry = supplier.get(); + set(openTelemetry); } } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index e91d44270b3..174d16f011e 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -41,6 +41,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -427,11 +428,12 @@ public AutoConfiguredOpenTelemetrySdk build() { if (!setResultAsGlobal) { return buildImpl(); } - AutoConfiguredOpenTelemetrySdk sdk = - GlobalOpenTelemetry.set( - this::buildImpl, AutoConfiguredOpenTelemetrySdk::getOpenTelemetrySdk); - logger.log(Level.FINE, "Global OpenTelemetry set to {0} by autoconfiguration", sdk); - return sdk; + AtomicReference autoConfiguredRef = new AtomicReference<>(); + GlobalOpenTelemetry.set(() -> { + autoConfiguredRef.set(buildImpl()); + return autoConfiguredRef.get().getOpenTelemetrySdk(); + }); + return autoConfiguredRef.get(); } private AutoConfiguredOpenTelemetrySdk buildImpl() { From a5f3c0cc03d9602fcd2aedfb0b6a3cdf73926d90 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 9 Jun 2025 20:56:49 +0200 Subject: [PATCH 09/17] fix api --- docs/apidiffs/current_vs_latest/opentelemetry-api.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt index bc383776af9..04dfbeb5291 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt @@ -1,5 +1,5 @@ Comparing source compatibility of opentelemetry-api-1.51.0-SNAPSHOT.jar against opentelemetry-api-1.51.0.jar *** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.api.GlobalOpenTelemetry (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 - +++ NEW METHOD: PUBLIC(+) STATIC(+) java.lang.Object set(java.util.function.Supplier, java.util.function.Function) + +++ NEW METHOD: PUBLIC(+) STATIC(+) java.lang.Object set(java.util.function.Supplier) GENERIC TEMPLATES: +++ T:java.lang.Object From 4c7028d1ab15a858dfc7c361e3e195d8d6974f4f Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 9 Jun 2025 22:26:33 +0200 Subject: [PATCH 10/17] fix format and cmpl --- .../io/opentelemetry/api/GlobalOpenTelemetry.java | 5 ++--- .../AutoConfiguredOpenTelemetrySdkBuilder.java | 13 ++++++++----- 2 files changed, 10 insertions(+), 8 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 0ffe16961fe..83e70bf7d8b 100644 --- a/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java +++ b/api/all/src/main/java/io/opentelemetry/api/GlobalOpenTelemetry.java @@ -17,7 +17,6 @@ import io.opentelemetry.context.propagation.ContextPropagators; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -121,8 +120,8 @@ public static void set(OpenTelemetry openTelemetry) { /** * Sets the {@link OpenTelemetry} that should be the global instance. * - *

This method calls the given {@code supplier} and calls {@link #set(OpenTelemetry)}, all while holding the - * {@link GlobalOpenTelemetry} mutex. + *

This method calls the given {@code supplier} and calls {@link #set(OpenTelemetry)}, all + * while holding the {@link GlobalOpenTelemetry} mutex. */ public static void set(Supplier supplier) { synchronized (mutex) { diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index 174d16f011e..4a6998f18a8 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -41,6 +41,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; import java.util.function.Function; @@ -429,11 +430,13 @@ public AutoConfiguredOpenTelemetrySdk build() { return buildImpl(); } AtomicReference autoConfiguredRef = new AtomicReference<>(); - GlobalOpenTelemetry.set(() -> { - autoConfiguredRef.set(buildImpl()); - return autoConfiguredRef.get().getOpenTelemetrySdk(); - }); - return autoConfiguredRef.get(); + GlobalOpenTelemetry.set( + () -> { + AutoConfiguredOpenTelemetrySdk sdk = buildImpl(); + autoConfiguredRef.set(sdk); + return sdk.getOpenTelemetrySdk(); + }); + return Objects.requireNonNull(autoConfiguredRef.get()); } private AutoConfiguredOpenTelemetrySdk buildImpl() { From 138601c9fa26fb524a8cfac478f6a9d5841a447f Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 9 Jun 2025 22:30:27 +0200 Subject: [PATCH 11/17] add log statement --- .../AutoConfiguredOpenTelemetrySdkBuilder.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index 4a6998f18a8..124231fa325 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -436,7 +436,12 @@ public AutoConfiguredOpenTelemetrySdk build() { autoConfiguredRef.set(sdk); return sdk.getOpenTelemetrySdk(); }); - return Objects.requireNonNull(autoConfiguredRef.get()); + AutoConfiguredOpenTelemetrySdk sdk = Objects.requireNonNull(autoConfiguredRef.get()); + logger.log( + Level.FINE, + "Global OpenTelemetry set to {0} by autoconfiguration", + sdk.getOpenTelemetrySdk()); + return sdk; } private AutoConfiguredOpenTelemetrySdk buildImpl() { From 71ca31c8a84f146706c3ef3fbdda546dcfe7acbd Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 13 Jun 2025 01:22:08 +0200 Subject: [PATCH 12/17] new test --- .../AutoConfiguredOpenTelemetrySdkTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) 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 c7ae65de9a0..891fc7c2128 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 @@ -65,6 +65,9 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -74,6 +77,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; @@ -674,4 +678,36 @@ void configurationError_ClosesResources() { logs.assertContains("Error closing io.opentelemetry.sdk.trace.SdkTracerProvider: Error!"); } + + @Test + @SuppressWarnings("unchecked") + void test() throws Exception { + AutoConfiguredOpenTelemetrySdkBuilder globalBuilder = builder.setResultAsGlobal(); + ExecutorService executor = Executors.newSingleThreadExecutor(); + + OpenTelemetry gotGetOutput; + AutoConfiguredOpenTelemetrySdk autoConfiguredSdk; + try (MockedStatic mockGot = + Mockito.mockStatic(GlobalOpenTelemetry.class)) { + mockGot.when(GlobalOpenTelemetry::get).thenCallRealMethod(); + mockGot.when(() -> GlobalOpenTelemetry.set(any(Supplier.class))).thenCallRealMethod(); + mockGot + .when(() -> GlobalOpenTelemetry.set(any(OpenTelemetry.class))) + .then( + invocation -> { + Thread.sleep(1000); + return invocation.callRealMethod(); + }); + + Future autoConfiguredSdkFuture = + executor.submit(globalBuilder::build); + gotGetOutput = GlobalOpenTelemetry.get(); + autoConfiguredSdk = autoConfiguredSdkFuture.get(); + } + assertThat(gotGetOutput) + .extracting("delegate") + .isSameAs(autoConfiguredSdk.getOpenTelemetrySdk()); + + executor.shutdown(); + } } From e1dd23edb75a5de7e56a99de210be6b350e998fa Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 18 Jun 2025 01:14:24 +0200 Subject: [PATCH 13/17] test --- .../AutoConfiguredOpenTelemetrySdkTest.java | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) 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 891fc7c2128..c7aed94419c 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 @@ -65,13 +65,13 @@ import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Supplier; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -680,13 +680,17 @@ void configurationError_ClosesResources() { } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "FutureReturnValueIgnored"}) void test() throws Exception { - AutoConfiguredOpenTelemetrySdkBuilder globalBuilder = builder.setResultAsGlobal(); - ExecutorService executor = Executors.newSingleThreadExecutor(); + // Idea of the test: + // 1. Thread 1 calls AutoConfiguredOpenTelemetrySdkBuilder#build + // 2. It acquires the mutex in GlobalOpenTelemetry.set(Supplier) + // 3. While holding the mutex before the call to GlobalOpenTelemetry.set(OpenTelemetry), + // it spawns Thread 2 which calls GlobalOpenTelemetry.get + // 4. We test that Thread 2 does not fail, and that its result is the same OpenTelemetry + // instance embedded in the AutoConfiguredOpenTelemetrySdk + SynchronousQueue gotGetResult = new SynchronousQueue<>(); - OpenTelemetry gotGetOutput; - AutoConfiguredOpenTelemetrySdk autoConfiguredSdk; try (MockedStatic mockGot = Mockito.mockStatic(GlobalOpenTelemetry.class)) { mockGot.when(GlobalOpenTelemetry::get).thenCallRealMethod(); @@ -695,19 +699,30 @@ void test() throws Exception { .when(() -> GlobalOpenTelemetry.set(any(OpenTelemetry.class))) .then( invocation -> { - Thread.sleep(1000); + CompletableFuture.supplyAsync(GlobalOpenTelemetry::get) + .handle( + (sdk, exc) -> { + if (exc != null) { + Assertions.fail(exc); + } else { + try { + gotGetResult.put(sdk); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + Assertions.fail(exception); + } + } + return null; + }); return invocation.callRealMethod(); }); - Future autoConfiguredSdkFuture = - executor.submit(globalBuilder::build); - gotGetOutput = GlobalOpenTelemetry.get(); - autoConfiguredSdk = autoConfiguredSdkFuture.get(); - } - assertThat(gotGetOutput) - .extracting("delegate") - .isSameAs(autoConfiguredSdk.getOpenTelemetrySdk()); + AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk = + builder.setResultAsGlobal().build(); - executor.shutdown(); + assertThat(gotGetResult.poll(3, TimeUnit.SECONDS)) + .extracting("delegate") + .isSameAs(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk()); + } } } From f2d9648d6385b7a0e04e33ca166b94f320122eed Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 18 Jun 2025 01:35:47 +0200 Subject: [PATCH 14/17] comment and sleep --- .../sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java | 2 ++ 1 file changed, 2 insertions(+) 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 c7aed94419c..4d91da971c9 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 @@ -714,6 +714,8 @@ void test() throws Exception { } return null; }); + // Give Thread 2 some time to try obtaining the mutex and getting blocked + Thread.sleep(500); return invocation.callRealMethod(); }); From 8ebb79a77c56f2b8dde1155b5591181d36c81330 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 20 Jun 2025 23:16:22 +0200 Subject: [PATCH 15/17] apply suggestion Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com> --- .../AutoConfiguredOpenTelemetrySdkTest.java | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) 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 4d91da971c9..93c17cf74fe 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 @@ -680,51 +680,64 @@ void configurationError_ClosesResources() { } @Test - @SuppressWarnings({"unchecked", "FutureReturnValueIgnored"}) - void test() throws Exception { - // Idea of the test: - // 1. Thread 1 calls AutoConfiguredOpenTelemetrySdkBuilder#build - // 2. It acquires the mutex in GlobalOpenTelemetry.set(Supplier) - // 3. While holding the mutex before the call to GlobalOpenTelemetry.set(OpenTelemetry), - // it spawns Thread 2 which calls GlobalOpenTelemetry.get - // 4. We test that Thread 2 does not fail, and that its result is the same OpenTelemetry - // instance embedded in the AutoConfiguredOpenTelemetrySdk - SynchronousQueue gotGetResult = new SynchronousQueue<>(); - - try (MockedStatic mockGot = - Mockito.mockStatic(GlobalOpenTelemetry.class)) { - mockGot.when(GlobalOpenTelemetry::get).thenCallRealMethod(); - mockGot.when(() -> GlobalOpenTelemetry.set(any(Supplier.class))).thenCallRealMethod(); - mockGot - .when(() -> GlobalOpenTelemetry.set(any(OpenTelemetry.class))) - .then( - invocation -> { - CompletableFuture.supplyAsync(GlobalOpenTelemetry::get) - .handle( - (sdk, exc) -> { - if (exc != null) { - Assertions.fail(exc); - } else { - try { - gotGetResult.put(sdk); - } catch (InterruptedException exception) { - Thread.currentThread().interrupt(); - Assertions.fail(exception); - } + void globalOpenTelemetryLock() throws InterruptedException, ExecutionException, TimeoutException { + CountDownLatch autoconfigStarted = new CountDownLatch(1); + CountDownLatch completeAutoconfig = new CountDownLatch(1); + ExecutorService executorService = Executors.newFixedThreadPool(2); + + // Submit a future to autoconfigure the SDK and set the result as global. Add a customization + // hook which blocks until we say so. + CompletableFuture autoConfiguredOpenTelemetryFuture = + CompletableFuture.supplyAsync( + () -> + builder + .addLoggerProviderCustomizer( + (sdkLoggerProviderBuilder, configProperties) -> { + autoconfigStarted.countDown(); + try { + completeAutoconfig.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } - return null; - }); - // Give Thread 2 some time to try obtaining the mutex and getting blocked - Thread.sleep(500); - return invocation.callRealMethod(); - }); - - AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk = - builder.setResultAsGlobal().build(); - - assertThat(gotGetResult.poll(3, TimeUnit.SECONDS)) - .extracting("delegate") - .isSameAs(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk()); + return sdkLoggerProviderBuilder; + }) + .setResultAsGlobal() + .build() + .getOpenTelemetrySdk(), + executorService); + + // Wait for autoconfiguration to enter our callback, then try to get an instance of + // GlobalOpenTelemetry. GlobalOpenTelemetry.get() should block until we release the + // completeAutoconfig latch and allow autoconfiguration to complete. + autoconfigStarted.await(); + CompletableFuture globalOpenTelemetryFuture = + CompletableFuture.supplyAsync(GlobalOpenTelemetry::get, executorService); + Thread.sleep(10); + assertThat(globalOpenTelemetryFuture.isDone()).isFalse(); + assertThat(autoConfiguredOpenTelemetryFuture.isDone()).isFalse(); + + // Release the latch, allowing autoconfiguration to complete. Confirm that our + // GlobalOpenTelemetry.get() future resolved to the same instance as autoconfiguration. + completeAutoconfig.countDown(); + assertThat(unobfuscate(globalOpenTelemetryFuture.get(10, TimeUnit.SECONDS))) + .isSameAs(autoConfiguredOpenTelemetryFuture.get(10, TimeUnit.SECONDS)); + + // Cleanup + executorService.shutdown(); + autoConfiguredOpenTelemetryFuture.get().shutdown().join(10, TimeUnit.SECONDS); + GlobalOpenTelemetry.resetForTest(); + } + + private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) { + try { + Field delegateField = + Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry") + .getDeclaredField("delegate"); + delegateField.setAccessible(true); + Object delegate = delegateField.get(openTelemetry); + return (OpenTelemetry) delegate; + } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) { + throw new IllegalStateException("Error unobfuscating OpenTelemetry", e); } } } From 4cce67cf98bdc0c9bf42b37942b018703475a902 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 20 Jun 2025 23:18:01 +0200 Subject: [PATCH 16/17] spotless --- .../sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java | 3 --- 1 file changed, 3 deletions(-) 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 93c17cf74fe..438f48d7ba9 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 @@ -66,18 +66,15 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Supplier; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; From 9d00edd9309fb7ce160b0167c519625d7ee4bfb5 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Fri, 20 Jun 2025 23:47:04 +0200 Subject: [PATCH 17/17] imports --- .../autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 438f48d7ba9..45d26308320 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 @@ -58,6 +58,7 @@ import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.IOException; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collections; @@ -66,7 +67,12 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Supplier;