/* * Copyright 2016-2020 The OpenTracing 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.opentracing.util; import io.opentracing.Scope; import io.opentracing.ScopeManager; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.Tracer; import io.opentracing.noop.NoopTracer; import io.opentracing.noop.NoopTracerFactory; import io.opentracing.propagation.Format; import java.util.concurrent.Callable; /** * Global tracer that forwards all methods to another tracer that can be * configured by calling {@link #registerIfAbsent(Tracer) register}. * *
* The {@linkplain #registerIfAbsent(Tracer) register} method should only be called once
* during the application initialization phase.
* If the {@linkplain #registerIfAbsent(Tracer)} register} method is never called,
* the default {@link NoopTracer} is used.
*
*
* Where possible, use some form of dependency injection (of which there are * many) to access the `Tracer` instance. For vanilla application code, this is * often reasonable and cleaner for all of the usual DI reasons. * *
* That said, instrumentation for packages that are themselves statically * configured (e.g., JDBC drivers) may be unable to make use of said DI * mechanisms for {@link Tracer} access, and as such they should fall back on * {@link GlobalTracer}. By and large, OpenTracing instrumentation should * always allow the programmer to specify a {@link Tracer} instance to use for * instrumentation, though the {@link GlobalTracer} is a reasonable fallback or * default value. */ public final class GlobalTracer implements Tracer { /** * Singleton instance. *
* Since we cannot prevent people using {@linkplain #get() GlobalTracer.get()} as a constant,
* this guarantees that references obtained before, during or after initialization
* all behave as if obtained after initialization once properly initialized.
* As a minor additional benefit it makes it harder to circumvent the {@link Tracer} API.
*/
private static final GlobalTracer INSTANCE = new GlobalTracer();
/**
* The registered {@link Tracer} delegate or the {@link NoopTracer} if none was registered yet.
* Never {@code null}.
*/
private static volatile Tracer tracer = NoopTracerFactory.create();
private static volatile boolean isRegistered = false;
private GlobalTracer() {
}
/**
* Returns the constant {@linkplain GlobalTracer}.
*
* All methods are forwarded to the currently configured tracer.
* Until a tracer is {@link #registerIfAbsent(Tracer) explicitly configured},
* the {@link io.opentracing.noop.NoopTracer NoopTracer} is used.
*
* @return The global tracer constant.
* @see #registerIfAbsent(Tracer) and {@link #registerIfAbsent(Callable)}
*/
public static Tracer get() {
return INSTANCE;
}
/**
* Identify whether a {@link Tracer} has previously been registered.
*
* This check is useful in scenarios where more than one component may be responsible * for registering a tracer. For example, when using a Java Agent, it will need to determine * if the application has already registered a tracer, and if not attempt to resolve and * register one itself. * * @return Whether a tracer has been registered */ public static boolean isRegistered() { return isRegistered; } /** * Register a {@link Tracer} to back the behaviour of the {@link #get()}. *
* The tracer is provided through a {@linkplain Callable} that will only be called if the global tracer is absent. * Registration is a one-time operation. Once a tracer has been registered, all attempts at re-registering * will return {@code false}. *
* Every application intending to use the global tracer is responsible for registering it once
* during its initialization.
*
* @param provider Provider for the tracer to use as global tracer.
* @return {@code true} if the provided tracer was registered as a result of this call,
* {@code false} otherwise.
* @throws NullPointerException if the tracer provider is {@code null} or provides a {@code null} Tracer.
* @throws RuntimeException any exception thrown by the provider gets rethrown,
* checked exceptions will be wrapped into appropriate runtime exceptions.
*/
public static synchronized boolean registerIfAbsent(final Callable
* Registration is a one-time operation. Once a tracer has been registered, all attempts at re-registering
* will return {@code false}. Use {@link #registerIfAbsent(Callable)} for lazy initiation to avoid multiple
* instantiations of tracer.
*
* Every application intending to use the global tracer is responsible for registering it once
* during its initialization.
*
* @param tracer tracer to be registered.
* @return {@code true} if the provided tracer was registered as a result of this call,
* {@code false} otherwise.
* @throws NullPointerException if the tracer {@code null}.
* @throws RuntimeException any exception thrown by the provider gets rethrown,
* checked exceptions will be wrapped into appropriate runtime exceptions.
*
* @see #registerIfAbsent(Callable)
*/
public static synchronized boolean registerIfAbsent(final Tracer tracer) {
requireNonNull(tracer, "Cannot register GlobalTracer. Tracer is null");
return registerIfAbsent(new Callable
* Registration is a one-time operation, attempting to call it more often will result in a runtime exception.
*
* Every application intending to use the global tracer is responsible for registering it once
* during its initialization.
*
* @param tracer Tracer to use as global tracer.
* @throws RuntimeException if there is already a current tracer registered
* @see #registerIfAbsent(Callable)
* @deprecated Please use {@link #registerIfAbsent(Tracer)} or {@link #registerIfAbsent(Callable)} instead.
*/
@Deprecated
public static void register(final Tracer tracer) {
if (!registerIfAbsent(provide(tracer))
&& !tracer.equals(GlobalTracer.tracer)
&& !(tracer instanceof GlobalTracer)) {
throw new IllegalStateException("There is already a current global Tracer registered.");
}
}
@Override
public ScopeManager scopeManager() {
return tracer.scopeManager();
}
@Override
public SpanBuilder buildSpan(String operationName) {
return tracer.buildSpan(operationName);
}
@Override
public