com.aliyun.openservices.shade.io.opentelemetry.api.GlobalOpenTelemetry Maven / Gradle / Ivy
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.internal.GuardedBy;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.metrics.Meter;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.metrics.MeterBuilder;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.metrics.MeterProvider;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.trace.Tracer;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.trace.TracerBuilder;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.api.trace.TracerProvider;
import com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.context.propagation.ContextPropagators;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
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
* baggage.
*
* If using the OpenTelemetry SDK, you may want to instantiate the {@link OpenTelemetry} to
* provide configuration, for example of {@code Resource} or {@code Sampler}. See {@code
* OpenTelemetrySdk} and {@code OpenTelemetrySdk.builder} for information on how to construct the
* SDK's {@link OpenTelemetry} implementation.
*
*
WARNING: Due to the inherent complications around initialization order involving this class
* and its single global instance, we strongly recommend *not* using GlobalOpenTelemetry unless you
* have a use-case that absolutely requires it. Please favor using instances of OpenTelemetry
* wherever possible.
*
*
If you are using the OpenTelemetry javaagent, it is generally best to only call
* GlobalOpenTelemetry.get() once, and then pass the resulting reference where you need to use it.
*
* @see TracerProvider
* @see ContextPropagators
*/
// We intentionally assign to be use for error reporting.
@SuppressWarnings("StaticAssignmentOfThrowable")
public final class GlobalOpenTelemetry {
private static final Logger logger = Logger.getLogger(GlobalOpenTelemetry.class.getName());
private static final Object mutex = new Object();
@Nullable private static volatile ObfuscatedOpenTelemetry globalOpenTelemetry;
@GuardedBy("mutex")
@Nullable
private static Throwable setGlobalCaller;
private GlobalOpenTelemetry() {}
/**
* Returns the registered global {@link OpenTelemetry}.
*
* @throws IllegalStateException if a provider has been specified by system property using the
* interface FQCN but the specified provider cannot be found.
*/
public static OpenTelemetry get() {
OpenTelemetry openTelemetry = globalOpenTelemetry;
if (openTelemetry == null) {
synchronized (mutex) {
openTelemetry = globalOpenTelemetry;
if (openTelemetry == null) {
OpenTelemetry autoConfigured = maybeAutoConfigureAndSetGlobal();
if (autoConfigured != null) {
return autoConfigured;
}
set(OpenTelemetry.noop());
return OpenTelemetry.noop();
}
}
}
return openTelemetry;
}
/**
* Sets the {@link OpenTelemetry} that should be the global instance. Future calls to {@link
* #get()} will return the provided {@link OpenTelemetry} instance. This should be called once as
* early as possible in your application initialization logic, often in a {@code static} block in
* your main class. It should only be called once - an attempt to call it a second time will
* result in an error. If trying to set the global {@link OpenTelemetry} multiple times in tests,
* use {@link GlobalOpenTelemetry#resetForTest()} between them.
*
*
If you are using the OpenTelemetry SDK, you should generally use {@code
* OpenTelemetrySdk.builder().buildAndRegisterGlobal()} instead of calling this method directly.
*/
public static void set(OpenTelemetry openTelemetry) {
synchronized (mutex) {
if (globalOpenTelemetry != null) {
throw new IllegalStateException(
"GlobalOpenTelemetry.set has already been called. GlobalOpenTelemetry.set must be "
+ "called only once before any calls to GlobalOpenTelemetry.get. If you are using "
+ "the OpenTelemetrySdk, use OpenTelemetrySdkBuilder.buildAndRegisterGlobal "
+ "instead. Previous invocation set to cause of this exception.",
setGlobalCaller);
}
globalOpenTelemetry = new ObfuscatedOpenTelemetry(openTelemetry);
setGlobalCaller = new Throwable();
}
}
/** Returns the globally registered {@link TracerProvider}. */
public static TracerProvider getTracerProvider() {
return get().getTracerProvider();
}
/**
* Gets or creates a named tracer instance from the globally registered {@link TracerProvider}.
*
*
This is a shortcut method for {@code getTracerProvider().get(instrumentationScopeName)}
*
* @param instrumentationScopeName A name uniquely identifying the instrumentation scope, such as
* the instrumentation library, package, or fully qualified class name. Must not be null.
* @return a tracer instance.
*/
public static Tracer getTracer(String instrumentationScopeName) {
return get().getTracer(instrumentationScopeName);
}
/**
* Gets or creates a named and versioned tracer instance from the globally registered {@link
* TracerProvider}.
*
*
This is a shortcut method for {@code getTracerProvider().get(instrumentationScopeName,
* instrumentationScopeVersion)}
*
* @param instrumentationScopeName A name uniquely identifying the instrumentation scope, such as
* the instrumentation library, package, or fully qualified class name. Must not be null.
* @param instrumentationScopeVersion The version of the instrumentation scope (e.g., "1.0.0").
* @return a tracer instance.
*/
public static Tracer getTracer(
String instrumentationScopeName, String instrumentationScopeVersion) {
return get().getTracer(instrumentationScopeName, instrumentationScopeVersion);
}
/**
* Creates a TracerBuilder for a named {@link Tracer} instance.
*
*
This is a shortcut method for {@code get().tracerBuilder(instrumentationScopeName)}
*
* @param instrumentationScopeName A name uniquely identifying the instrumentation scope, such as
* the instrumentation library, package, or fully qualified class name. Must not be null.
* @return a TracerBuilder instance.
* @since 1.4.0
*/
public static TracerBuilder tracerBuilder(String instrumentationScopeName) {
return get().tracerBuilder(instrumentationScopeName);
}
/**
* Returns the globally registered {@link MeterProvider}.
*
* @since 1.10.0
*/
public static MeterProvider getMeterProvider() {
return get().getMeterProvider();
}
/**
* Gets or creates a named meter instance from the globally registered {@link MeterProvider}.
*
*
This is a shortcut method for {@code getMeterProvider().get(instrumentationScopeName)}
*
* @param instrumentationScopeName A name uniquely identifying the instrumentation scope, such as
* the instrumentation library, package, or fully qualified class name. Must not be null.
* @return a Meter instance.
* @since 1.10.0
*/
public static Meter getMeter(String instrumentationScopeName) {
return get().getMeter(instrumentationScopeName);
}
/**
* Creates a MeterBuilder for a named {@link Meter} instance.
*
*
This is a shortcut method for {@code get().meterBuilder(instrumentationScopeName)}
*
* @param instrumentationScopeName A name uniquely identifying the instrumentation scope, such as
* the instrumentation library, package, or fully qualified class name. Must not be null.
* @return a MeterBuilder instance.
* @since 1.10.0
*/
public static MeterBuilder meterBuilder(String instrumentationScopeName) {
return get().meterBuilder(instrumentationScopeName);
}
/**
* Unsets the global {@link OpenTelemetry}. This is only meant to be used from tests which need to
* reconfigure {@link OpenTelemetry}.
*/
public static void resetForTest() {
globalOpenTelemetry = null;
}
/**
* Returns the globally registered {@link ContextPropagators} for remote propagation of a context.
*/
public static ContextPropagators getPropagators() {
return get().getPropagators();
}
@Nullable
private static OpenTelemetry maybeAutoConfigureAndSetGlobal() {
Class> openTelemetrySdkAutoConfiguration;
try {
openTelemetrySdkAutoConfiguration =
Class.forName("com.aliyun.openservices.shade.com.aliyun.openservices.shade.io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk");
} catch (ClassNotFoundException e) {
return null;
}
try {
Method initialize = openTelemetrySdkAutoConfiguration.getMethod("initialize");
Object autoConfiguredSdk = initialize.invoke(null);
Method getOpenTelemetrySdk =
openTelemetrySdkAutoConfiguration.getMethod("getOpenTelemetrySdk");
return (OpenTelemetry) getOpenTelemetrySdk.invoke(autoConfiguredSdk);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new IllegalStateException(
"OpenTelemetrySdkAutoConfiguration detected on classpath "
+ "but could not invoke initialize method. This is a bug in OpenTelemetry.",
e);
} catch (InvocationTargetException t) {
logger.log(
Level.SEVERE,
"Error automatically configuring OpenTelemetry SDK. OpenTelemetry will not be enabled.",
t.getTargetException());
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 ContextPropagators getPropagators() {
return delegate.getPropagators();
}
@Override
public TracerBuilder tracerBuilder(String instrumentationScopeName) {
return delegate.tracerBuilder(instrumentationScopeName);
}
}
}