Ensure GlobalLoggerProvider is set once (#4804)

* Ensure GlobalLoggerProvider is set once

* Add GlobalLoggerProviderTest

* PR feedback
This commit is contained in:
jack-berg 2022-10-03 13:47:36 -05:00 committed by GitHub
parent b0802ad102
commit bd0cf78c39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 4 deletions

View File

@ -6,20 +6,29 @@
package io.opentelemetry.api.logs;
import io.opentelemetry.api.GlobalOpenTelemetry;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
* This class provides a temporary global accessor for {@link LoggerProvider} until the log API is
* marked stable. It will eventually be merged into {@link GlobalOpenTelemetry}.
*/
// We intentionally assign to be used for error reporting.
@SuppressWarnings("StaticAssignmentOfThrowable")
public final class GlobalLoggerProvider {
private static volatile LoggerProvider globalLoggerProvider = DefaultLoggerProvider.getInstance();
private static final AtomicReference<LoggerProvider> instance =
new AtomicReference<>(LoggerProvider.noop());
@Nullable private static volatile Throwable setInstanceCaller;
private GlobalLoggerProvider() {}
/** Returns the globally registered {@link LoggerProvider}. */
// instance cannot be set to null
@SuppressWarnings("NullAway")
public static LoggerProvider get() {
return globalLoggerProvider;
return instance.get();
}
/**
@ -28,7 +37,22 @@ public final class GlobalLoggerProvider {
* application initialization logic.
*/
public static void set(LoggerProvider loggerProvider) {
globalLoggerProvider =
loggerProvider == null ? DefaultLoggerProvider.getInstance() : loggerProvider;
boolean changed = instance.compareAndSet(LoggerProvider.noop(), loggerProvider);
if (!changed && (loggerProvider != LoggerProvider.noop())) {
throw new IllegalStateException(
"GlobalLoggerProvider.set has already been called. GlobalLoggerProvider.set "
+ "must be called only once before any calls to GlobalLoggerProvider.get. "
+ "Previous invocation set to cause of this exception.",
setInstanceCaller);
}
setInstanceCaller = new Throwable();
}
/**
* Unsets the global {@link LoggerProvider}. This is only meant to be used from tests which need
* to reconfigure {@link LoggerProvider}.
*/
public static void resetForTest() {
instance.set(LoggerProvider.noop());
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.logs;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class GlobalLoggerProviderTest {
@BeforeAll
static void beforeClass() {
GlobalLoggerProvider.resetForTest();
}
@AfterEach
void after() {
GlobalLoggerProvider.resetForTest();
}
@Test
void setAndGet() {
assertThat(GlobalLoggerProvider.get()).isEqualTo(LoggerProvider.noop());
LoggerProvider loggerProvider =
instrumentationScopeName -> LoggerProvider.noop().loggerBuilder(instrumentationScopeName);
GlobalLoggerProvider.set(loggerProvider);
assertThat(GlobalLoggerProvider.get()).isEqualTo(loggerProvider);
}
@Test
void setThenSet() {
GlobalLoggerProvider.set(
instrumentationScopeName -> LoggerProvider.noop().loggerBuilder(instrumentationScopeName));
assertThatThrownBy(
() ->
GlobalLoggerProvider.set(
instrumentationScopeName ->
LoggerProvider.noop().loggerBuilder(instrumentationScopeName)))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("GlobalLoggerProvider.set has already been called")
.hasStackTraceContaining("setThenSet");
}
}

View File

@ -126,6 +126,7 @@ class AutoConfiguredOpenTelemetrySdkTest {
@BeforeEach
void resetGlobal() {
GlobalOpenTelemetry.resetForTest();
GlobalLoggerProvider.resetForTest();
builder =
AutoConfiguredOpenTelemetrySdk.builder()
.setResultAsGlobal(false)

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.autoconfigure;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.logs.GlobalLoggerProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -17,6 +18,7 @@ class AutoConfiguredOpenTelemetrySdkTest {
@BeforeEach
void setUp() {
GlobalOpenTelemetry.resetForTest();
GlobalLoggerProvider.resetForTest();
}
@Test

View File

@ -16,6 +16,7 @@ import static org.awaitility.Awaitility.await;
import com.google.common.collect.Lists;
import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.logs.GlobalLoggerProvider;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
@ -58,6 +59,7 @@ class OtlpGrpcConfigTest {
@BeforeEach
void setUp() {
GlobalOpenTelemetry.resetForTest();
GlobalLoggerProvider.resetForTest();
}
@AfterEach
@ -65,6 +67,7 @@ class OtlpGrpcConfigTest {
server.reset();
shutdownGlobalSdk();
GlobalOpenTelemetry.resetForTest();
GlobalLoggerProvider.resetForTest();
}
@Test

View File

@ -16,6 +16,7 @@ import static org.awaitility.Awaitility.await;
import com.google.common.collect.Lists;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.logs.GlobalLoggerProvider;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
@ -44,12 +45,14 @@ class OtlpHttpConfigTest {
void setUp() {
server.reset();
GlobalOpenTelemetry.resetForTest();
GlobalLoggerProvider.resetForTest();
}
@AfterEach
public void tearDown() {
shutdownGlobalSdk();
GlobalOpenTelemetry.resetForTest();
GlobalLoggerProvider.resetForTest();
}
@Test