/* * Copyright 2019, OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.opentelemetry; import io.opentelemetry.baggage.BaggageManager; import io.opentelemetry.baggage.DefaultBaggageManager; import io.opentelemetry.baggage.spi.BaggageManagerFactory; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.context.propagation.DefaultContextPropagators; import io.opentelemetry.internal.Obfuscated; import io.opentelemetry.internal.Utils; import io.opentelemetry.metrics.DefaultMeterProvider; import io.opentelemetry.metrics.Meter; import io.opentelemetry.metrics.MeterProvider; import io.opentelemetry.metrics.spi.MeterProviderFactory; import io.opentelemetry.trace.DefaultTracerProvider; import io.opentelemetry.trace.Tracer; import io.opentelemetry.trace.TracerProvider; import io.opentelemetry.trace.propagation.HttpTraceContext; import io.opentelemetry.trace.spi.TracerProviderFactory; import java.util.ServiceLoader; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; /** * This class provides a static global accessor for telemetry objects {@link Tracer}, {@link Meter} * and {@link BaggageManager}. * *

The telemetry objects are lazy-loaded singletons resolved via {@link ServiceLoader} mechanism. * * @see TracerProvider * @see MeterProviderFactory * @see BaggageManagerFactory */ @ThreadSafe public final class OpenTelemetry { private static final Object mutex = new Object(); @Nullable private static volatile OpenTelemetry instance; private final TracerProvider tracerProvider; private final MeterProvider meterProvider; private final BaggageManager contextManager; private volatile ContextPropagators propagators = DefaultContextPropagators.builder().build(); /** * Returns a singleton {@link TracerProvider}. * * @return registered TracerProvider or default via {@link DefaultTracerProvider#getInstance()}. * @throws IllegalStateException if a specified TracerProvider (via system properties) could not * be found. * @since 0.1.0 */ public static TracerProvider getTracerProvider() { return getInstance().tracerProvider; } /** * Gets or creates a named tracer instance. * *

This is a shortcut method for getTracerProvider().get(instrumentationName). * * @param instrumentationName The name of the instrumentation library, not the name of the * instrument*ed* library (e.g., "io.opentelemetry.contrib.mongodb"). Must not be null. * @return a tracer instance. * @since 0.5.0 */ public static Tracer getTracer(String instrumentationName) { return getTracerProvider().get(instrumentationName); } /** * Gets or creates a named and versioned tracer instance. * *

This is a shortcut method for * getTracerProvider().get(instrumentationName, instrumentationVersion). * * @param instrumentationName The name of the instrumentation library, not the name of the * instrument*ed* library (e.g., "io.opentelemetry.contrib.mongodb"). Must not be null. * @param instrumentationVersion The version of the instrumentation library (e.g., * "semver:1.0.0"). * @return a tracer instance. * @since 0.5.0 */ public static Tracer getTracer(String instrumentationName, String instrumentationVersion) { return getTracerProvider().get(instrumentationName, instrumentationVersion); } /** * Returns a singleton {@link MeterProvider}. * * @return registered MeterProvider or default via {@link DefaultMeterProvider#getInstance()}. * @throws IllegalStateException if a specified MeterProvider (via system properties) could not be * found. * @since 0.1.0 */ public static MeterProvider getMeterProvider() { return getInstance().meterProvider; } /** * Gets or creates a named meter instance. * *

This is a shortcut method for getMeterProvider().get(instrumentationName). * * @param instrumentationName The name of the instrumentation library, not the name of the * instrument*ed* library. * @return a tracer instance. * @since 0.5.0 */ public static Meter getMeter(String instrumentationName) { return getMeterProvider().get(instrumentationName); } /** * Gets or creates a named and versioned meter instance. * *

This is a shortcut method for * getMeterProvider().get(instrumentationName, instrumentationVersion). * * @param instrumentationName The name of the instrumentation library, not the name of the * instrument*ed* library. * @param instrumentationVersion The version of the instrumentation library. * @return a tracer instance. * @since 0.5.0 */ public static Meter getMeter(String instrumentationName, String instrumentationVersion) { return getMeterProvider().get(instrumentationName, instrumentationVersion); } /** * Returns a singleton {@link BaggageManager}. * * @return registered manager or default via {@link DefaultBaggageManager#getInstance()}. * @throws IllegalStateException if a specified manager (via system properties) could not be * found. * @since 0.1.0 */ public static BaggageManager getBaggageManager() { return getInstance().contextManager; } /** * Returns a {@link ContextPropagators} object, which can be used to access the set of registered * propagators for each supported format. * * @return registered propagators container, defaulting to a {@link ContextPropagators} object * with {@link HttpTraceContext} registered. * @throws IllegalStateException if a specified manager (via system properties) could not be * found. * @since 0.3.0 */ public static ContextPropagators getPropagators() { return getInstance().propagators; } /** * Sets the {@link ContextPropagators} object, which can be used to access the set of registered * propagators for each supported format. * * @param propagators the {@link ContextPropagators} object to be registered. * @throws IllegalStateException if a specified manager (via system properties) could not be * found. * @throws NullPointerException if {@code propagators} is {@code null}. * @since 0.3.0 */ public static void setPropagators(ContextPropagators propagators) { Utils.checkNotNull(propagators, "propagators"); getInstance().propagators = propagators; } /** Lazy loads an instance. */ private static OpenTelemetry getInstance() { if (instance == null) { synchronized (mutex) { if (instance == null) { instance = new OpenTelemetry(); } } } return instance; } private OpenTelemetry() { TracerProviderFactory tracerProviderFactory = loadSpi(TracerProviderFactory.class); this.tracerProvider = tracerProviderFactory != null ? new ObfuscatedTracerProvider(tracerProviderFactory.create()) : DefaultTracerProvider.getInstance(); MeterProviderFactory meterProviderFactory = loadSpi(MeterProviderFactory.class); meterProvider = meterProviderFactory != null ? meterProviderFactory.create() : DefaultMeterProvider.getInstance(); BaggageManagerFactory contextManagerProvider = loadSpi(BaggageManagerFactory.class); contextManager = contextManagerProvider != null ? contextManagerProvider.create() : DefaultBaggageManager.getInstance(); } /** * Load provider class via {@link ServiceLoader}. A specific provider class can be requested via * setting a system property with FQCN. * * @param providerClass a provider class * @param provider type * @return a provider or null if not found * @throws IllegalStateException if a specified provider is not found */ @Nullable private static T loadSpi(Class providerClass) { String specifiedProvider = System.getProperty(providerClass.getName()); ServiceLoader providers = ServiceLoader.load(providerClass); for (T provider : providers) { if (specifiedProvider == null || specifiedProvider.equals(provider.getClass().getName())) { return provider; } } if (specifiedProvider != null) { throw new IllegalStateException( String.format("Service provider %s not found", specifiedProvider)); } return null; } // for testing static void reset() { instance = null; } /** * A {@link TracerProvider} wrapper that forces users to access the SDK specific implementation * via the SDK, instead of via the API and casting it to the SDK specific implementation. * * @see Obfuscated */ @ThreadSafe private static class ObfuscatedTracerProvider implements TracerProvider, Obfuscated { private final TracerProvider delegate; private ObfuscatedTracerProvider(TracerProvider delegate) { this.delegate = delegate; } @Override public Tracer get(String instrumentationName) { return delegate.get(instrumentationName); } @Override public Tracer get(String instrumentationName, String instrumentationVersion) { return delegate.get(instrumentationName, instrumentationVersion); } @Override public TracerProvider unobfuscate() { return delegate; } } }