|
26 | 26 | import javax.annotation.concurrent.ThreadSafe; |
27 | 27 |
|
28 | 28 | /** |
29 | | - * A global singleton for the entrypoint to telemetry functionality for tracing, metrics and |
30 | | - * baggage. |
| 29 | + * Provides access to a global singleton {@link OpenTelemetry} instance. |
31 | 30 | * |
32 | | - * <p>If using the OpenTelemetry SDK, you may want to instantiate the {@link OpenTelemetry} to |
33 | | - * provide configuration, for example of {@code Resource} or {@code Sampler}. See {@code |
34 | | - * OpenTelemetrySdk} and {@code OpenTelemetrySdk.builder} for information on how to construct the |
35 | | - * SDK's {@link OpenTelemetry} implementation. |
| 31 | + * <p>WARNING: To avoid inherent complications around initialization ordering, it's best-practice to |
| 32 | + * pass around instances of {@link OpenTelemetry} rather than using {@link GlobalOpenTelemetry}. |
| 33 | + * However, the OpenTelemetry javagent makes the {@link OpenTelemetry} instance it installs |
| 34 | + * available via {@link GlobalOpenTelemetry}. As a result, {@link GlobalOpenTelemetry} plays an |
| 35 | + * important role in native instrumentation and application custom instrumentation. |
36 | 36 | * |
37 | | - * <p>WARNING: Due to the inherent complications around initialization order involving this class |
38 | | - * and its single global instance, we strongly recommend *not* using GlobalOpenTelemetry unless you |
39 | | - * have a use-case that absolutely requires it. Please favor using instances of OpenTelemetry |
40 | | - * wherever possible. |
| 37 | + * <p>Native instrumentation should use {@link #getOrNoop()} as the default {@link OpenTelemetry} |
| 38 | + * instance, and expose APIs for setting a custom instance. This results in the following behavior: |
41 | 39 | * |
42 | | - * <p>If you are using the OpenTelemetry javaagent, it is generally best to only call |
43 | | - * GlobalOpenTelemetry.get() once, and then pass the resulting reference where you need to use it. |
| 40 | + * <ul> |
| 41 | + * <li>If the OpenTelemetry javaagent is installed, the native instrumentation will default to the |
| 42 | + * {@link OpenTelemetry} it installs. |
| 43 | + * <li>If the OpenTelemetry javaagent is not installed, the native instrumentation will default to |
| 44 | + * a noop instance. |
| 45 | + * <li>If the user explicitly sets a custom instance, it will be used, regardless of whether or |
| 46 | + * not the OpenTelemetry javaagent is installed. |
| 47 | + * </ul> |
| 48 | + * |
| 49 | + * <p>Applications with custom instrumentation should call {@link #getOrSet(Supplier)} once during |
| 50 | + * initialization, and pass the resulting instance around manually (or with dependency injection) to |
| 51 | + * install custom instrumentation. This results in the following behavior: |
| 52 | + * |
| 53 | + * <ul> |
| 54 | + * <li>If the OpenTelemetry javaagent is installed, custom instrumentation will use the {@link |
| 55 | + * OpenTelemetry} it installs. |
| 56 | + * <li>If the OpenTelemetry javaagent is not installed, custom instrumentation will use the {@link |
| 57 | + * OpenTelemetry} instance returned by {@link Supplier} passed to {@link #getOrSet(Supplier)}. |
| 58 | + * </ul> |
44 | 59 | * |
45 | 60 | * @see TracerProvider |
46 | 61 | * @see ContextPropagators |
@@ -68,10 +83,68 @@ public final class GlobalOpenTelemetry { |
68 | 83 | private GlobalOpenTelemetry() {} |
69 | 84 |
|
70 | 85 | /** |
71 | | - * Returns the registered global {@link OpenTelemetry}. |
| 86 | + * Returns the registered global {@link OpenTelemetry} if set, or else {@link |
| 87 | + * OpenTelemetry#noop()}. |
| 88 | + * |
| 89 | + * <p>NOTE: if the global instance is set, the response is obfuscated to prevent callers from |
| 90 | + * casting to SDK implementation instances and inappropriately accessing non-instrumentation APIs. |
72 | 91 | * |
73 | | - * @throws IllegalStateException if a provider has been specified by system property using the |
74 | | - * interface FQCN but the specified provider cannot be found. |
| 92 | + * <p>NOTE: This does not result in the {@link #set(OpenTelemetry)} side effects of {@link |
| 93 | + * #get()}. |
| 94 | + * |
| 95 | + * <p>Native instrumentation should use this method to initialize their default {@link |
| 96 | + * OpenTelemetry} instance. See class javadoc for more details. |
| 97 | + */ |
| 98 | + public static OpenTelemetry getOrNoop() { |
| 99 | + synchronized (mutex) { |
| 100 | + return globalOpenTelemetry != null ? globalOpenTelemetry : OpenTelemetry.noop(); |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + /** |
| 105 | + * Returns the registered global {@link OpenTelemetry} if set, or else calls {@link |
| 106 | + * #set(Supplier)} with the {@code supplier}. |
| 107 | + * |
| 108 | + * <p>NOTE: if the global instance is set, the response is obfuscated to prevent callers from |
| 109 | + * casting to SDK implementation instances and inappropriately accessing non-instrumentation APIs. |
| 110 | + * |
| 111 | + * <p>NOTE: This does not result in the {@link #set(OpenTelemetry)} side effects of {@link |
| 112 | + * #get()}. |
| 113 | + * |
| 114 | + * <p>Application custom instrumentation should use this method during initialization. See class |
| 115 | + * javadoc for more details. |
| 116 | + */ |
| 117 | + public static OpenTelemetry getOrSet(Supplier<OpenTelemetry> supplier) { |
| 118 | + synchronized (mutex) { |
| 119 | + if (globalOpenTelemetry == null) { |
| 120 | + OpenTelemetry openTelemetry = supplier.get(); |
| 121 | + set(openTelemetry); |
| 122 | + return openTelemetry; |
| 123 | + } |
| 124 | + return globalOpenTelemetry; |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Returns the registered global {@link OpenTelemetry} if set, else calls {@link |
| 130 | + * GlobalOpenTelemetry#set(OpenTelemetry)} with a no-op {@link OpenTelemetry} instance and returns |
| 131 | + * that. |
| 132 | + * |
| 133 | + * <p>NOTE: all returned instanced are obfuscated to prevent callers from casting to SDK |
| 134 | + * implementation instances and inappropriately accessing non-instrumentation APIs. |
| 135 | + * |
| 136 | + * <p>Native instrumentations should use {@link #getOrNoop()} instad. See class javadoc for more |
| 137 | + * details. |
| 138 | + * |
| 139 | + * <p>Application custom instrumentation should use {@link #getOrSet(Supplier)} instead. See class |
| 140 | + * javadoc for more details. |
| 141 | + * |
| 142 | + * <p>If the global instance has not been set, and {@code |
| 143 | + * io.opentelemetry:opentelemetry-sdk-extension-autoconfigure} is present, and {@value |
| 144 | + * GLOBAL_AUTOCONFIGURE_ENABLED_PROPERTY} is {@code true}, the global instance will be set to an |
| 145 | + * autoconfigured instance instead of {@link OpenTelemetry#noop()}. |
| 146 | + * |
| 147 | + * @throws IllegalStateException if autoconfigure initialization is triggered and fails. |
75 | 148 | */ |
76 | 149 | public static OpenTelemetry get() { |
77 | 150 | OpenTelemetry openTelemetry = globalOpenTelemetry; |
@@ -134,20 +207,6 @@ public static void set(Supplier<OpenTelemetry> supplier) { |
134 | 207 | } |
135 | 208 | } |
136 | 209 |
|
137 | | - /** |
138 | | - * Evaluate if the global instance has been set without the side effects of {@link #get()}. |
139 | | - * |
140 | | - * <p>This is useful for evaluating if any code, like the OpenTelemetry javaagent, has previously |
141 | | - * set the global instance while preserving the ability to set it. |
142 | | - * |
143 | | - * @return true if the global instance has been set, false otherwise. |
144 | | - */ |
145 | | - public static boolean isSet() { |
146 | | - synchronized (mutex) { |
147 | | - return globalOpenTelemetry != null; |
148 | | - } |
149 | | - } |
150 | | - |
151 | 210 | /** Returns the globally registered {@link TracerProvider}. */ |
152 | 211 | public static TracerProvider getTracerProvider() { |
153 | 212 | return get().getTracerProvider(); |
|
0 commit comments