opentelemetry/global/trace.rs
1use crate::trace::{noop::NoopTracerProvider, SpanContext, Status};
2use crate::{otel_error, otel_info, InstrumentationScope};
3use crate::{trace, trace::TracerProvider, Context, KeyValue};
4use std::borrow::Cow;
5use std::fmt;
6use std::sync::{Arc, OnceLock, RwLock};
7use std::time::SystemTime;
8
9/// Allows a specific [`crate::trace::Span`] to be used generically by [`BoxedSpan`]
10/// instances by mirroring the interface and boxing the return types.
11pub trait ObjectSafeSpan {
12 /// An API to record events at a specific time in the context of a given `Span`.
13 ///
14 /// Events SHOULD preserve the order in which they're set. This will typically match
15 /// the ordering of the events' timestamps.
16 ///
17 /// Note that the OpenTelemetry project documents certain ["standard event names and
18 /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
19 /// which have prescribed semantic meanings.
20 fn add_event_with_timestamp(
21 &mut self,
22 name: Cow<'static, str>,
23 timestamp: SystemTime,
24 attributes: Vec<KeyValue>,
25 );
26
27 /// Returns the `SpanContext` for the given `Span`. The returned value may be used even after
28 /// the `Span is finished. The returned value MUST be the same for the entire `Span` lifetime.
29 fn span_context(&self) -> &SpanContext;
30
31 /// Returns true if this `Span` is recording information like events with the `add_event`
32 /// operation, attributes using `set_attributes`, status with `set_status`, etc.
33 ///
34 /// This flag SHOULD be used to avoid expensive computations of a `Span` attributes or events in
35 /// case when a `Span` is definitely not recorded. Note that any child span's recording is
36 /// determined independently from the value of this flag (typically based on the sampled flag of
37 /// a `TraceFlag` on `SpanContext`).
38 ///
39 /// This flag may be true despite the entire trace being sampled out. This allows to record and
40 /// process information about the individual Span without sending it to the backend. An example
41 /// of this scenario may be recording and processing of all incoming requests for the processing
42 /// and building of SLA/SLO latency charts while sending only a subset - sampled spans - to the
43 /// backend. See also the sampling section of SDK design.
44 ///
45 /// Users of the API should only access the `is_recording` property when instrumenting code and
46 /// never access `SampledFlag` unless used in context propagators.
47 fn is_recording(&self) -> bool;
48
49 /// An API to set a single `Attribute` where the attribute properties are passed
50 /// as arguments. To avoid extra allocations some implementations may offer a separate API for
51 /// each of the possible value types.
52 ///
53 /// An `Attribute` is defined as a `KeyValue` pair.
54 ///
55 /// Attributes SHOULD preserve the order in which they're set. Setting an attribute
56 /// with the same key as an existing attribute SHOULD overwrite the existing
57 /// attribute's value.
58 ///
59 /// Note that the OpenTelemetry project documents certain ["standard
60 /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
61 /// that have prescribed semantic meanings.
62 fn set_attribute(&mut self, attribute: KeyValue);
63
64 /// Sets the status of the `Span`. `message` MUST be ignored when the status is `OK` or
65 /// `Unset`.
66 ///
67 /// The order of status is `Ok` > `Error` > `Unset`. That's means set the status
68 /// to `Unset` will always be ignore, set the status to `Error` only works when current
69 /// status is `Unset`, set the status to `Ok` will be consider final and any further call
70 /// to this function will be ignore.
71 fn set_status(&mut self, status: Status);
72
73 /// Updates the `Span`'s name. After this update, any sampling behavior based on the
74 /// name will depend on the implementation.
75 ///
76 /// It is highly discouraged to update the name of a `Span` after its creation.
77 /// `Span` name is often used to group, filter and identify the logical groups of
78 /// spans. Often, filtering logic will be implemented before the `Span` creation
79 /// for performance reasons, and the name update may interfere with this logic.
80 ///
81 /// The method name is called `update_name` to differentiate this method from the
82 /// regular property. It emphasizes that this operation signifies a
83 /// major change for a `Span` and may lead to re-calculation of sampling or
84 /// filtering decisions made previously depending on the implementation.
85 fn update_name(&mut self, new_name: Cow<'static, str>);
86
87 /// Adds a link to this span
88 ///
89 fn add_link(&mut self, span_context: SpanContext, attributes: Vec<KeyValue>);
90
91 /// Finishes the `Span`.
92 ///
93 /// Implementations MUST ignore all subsequent calls to `end` (there might be
94 /// exceptions when the tracer is streaming events and has no mutable state
95 /// associated with the Span).
96 ///
97 /// Calls to `end` a Span MUST not have any effects on child `Span`s as they may
98 /// still be running and can be ended later.
99 ///
100 /// This API MUST be non-blocking.
101 fn end(&mut self) {
102 self.end_with_timestamp(crate::time::now());
103 }
104
105 /// Finishes the `Span` with given timestamp
106 ///
107 /// For more details, refer to [`Span::end`]
108 ///
109 /// [`Span::end`]: trace::Span::end
110 fn end_with_timestamp(&mut self, timestamp: SystemTime);
111}
112
113impl<T: trace::Span> ObjectSafeSpan for T {
114 fn add_event_with_timestamp(
115 &mut self,
116 name: Cow<'static, str>,
117 timestamp: SystemTime,
118 attributes: Vec<KeyValue>,
119 ) {
120 self.add_event_with_timestamp(name, timestamp, attributes)
121 }
122
123 fn span_context(&self) -> &SpanContext {
124 self.span_context()
125 }
126
127 fn is_recording(&self) -> bool {
128 self.is_recording()
129 }
130
131 fn set_attribute(&mut self, attribute: KeyValue) {
132 self.set_attribute(attribute)
133 }
134
135 fn set_status(&mut self, status: Status) {
136 self.set_status(status)
137 }
138
139 fn update_name(&mut self, new_name: Cow<'static, str>) {
140 self.update_name(new_name)
141 }
142
143 fn add_link(&mut self, span_context: SpanContext, attributes: Vec<KeyValue>) {
144 self.add_link(span_context, attributes)
145 }
146
147 fn end_with_timestamp(&mut self, timestamp: SystemTime) {
148 self.end_with_timestamp(timestamp)
149 }
150}
151
152/// Wraps the [`BoxedTracer`]'s [`Span`] so it can be used generically by
153/// applications without knowing the underlying type.
154///
155/// [`Span`]: crate::trace::Span
156pub struct BoxedSpan(Box<dyn ObjectSafeSpan + Send + Sync>);
157
158impl BoxedSpan {
159 pub(crate) fn new<T>(span: T) -> Self
160 where
161 T: ObjectSafeSpan + Send + Sync + 'static,
162 {
163 BoxedSpan(Box::new(span))
164 }
165}
166
167impl fmt::Debug for BoxedSpan {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 f.write_str("BoxedSpan")
170 }
171}
172
173impl trace::Span for BoxedSpan {
174 /// Records events at a specific time in the context of a given `Span`.
175 ///
176 /// Note that the OpenTelemetry project documents certain ["standard event names and
177 /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
178 /// which have prescribed semantic meanings.
179 fn add_event_with_timestamp<T>(
180 &mut self,
181 name: T,
182 timestamp: SystemTime,
183 attributes: Vec<KeyValue>,
184 ) where
185 T: Into<Cow<'static, str>>,
186 {
187 self.0
188 .add_event_with_timestamp(name.into(), timestamp, attributes)
189 }
190
191 /// Returns the `SpanContext` for the given `Span`.
192 fn span_context(&self) -> &trace::SpanContext {
193 self.0.span_context()
194 }
195
196 /// Returns true if this `Span` is recording information like events with the `add_event`
197 /// operation, attributes using `set_attributes`, status with `set_status`, etc.
198 fn is_recording(&self) -> bool {
199 self.0.is_recording()
200 }
201
202 /// Sets a single `Attribute` where the attribute properties are passed as arguments.
203 ///
204 /// Note that the OpenTelemetry project documents certain ["standard
205 /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
206 /// that have prescribed semantic meanings.
207 fn set_attribute(&mut self, attribute: KeyValue) {
208 self.0.set_attribute(attribute)
209 }
210
211 /// Sets the status of the `Span`. If used, this will override the default `Span`
212 /// status, which is `Unset`.
213 fn set_status(&mut self, status: trace::Status) {
214 self.0.set_status(status)
215 }
216
217 /// Updates the `Span`'s name.
218 fn update_name<T>(&mut self, new_name: T)
219 where
220 T: Into<Cow<'static, str>>,
221 {
222 self.0.update_name(new_name.into())
223 }
224
225 /// Adds a link to this span
226 ///
227 fn add_link(&mut self, span_context: trace::SpanContext, attributes: Vec<KeyValue>) {
228 self.0.add_link(span_context, attributes)
229 }
230
231 /// Finishes the span with given timestamp.
232 fn end_with_timestamp(&mut self, timestamp: SystemTime) {
233 self.0.end_with_timestamp(timestamp);
234 }
235}
236
237/// Wraps the [`GlobalTracerProvider`]'s [`Tracer`] so it can be used generically by
238/// applications without knowing the underlying type.
239///
240/// [`Tracer`]: crate::trace::Tracer
241/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
242pub struct BoxedTracer(Box<dyn ObjectSafeTracer + Send + Sync>);
243
244impl BoxedTracer {
245 /// Create a `BoxedTracer` from an object-safe tracer.
246 pub fn new(tracer: Box<dyn ObjectSafeTracer + Send + Sync>) -> Self {
247 BoxedTracer(tracer)
248 }
249}
250
251impl fmt::Debug for BoxedTracer {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 f.write_str("BoxedTracer")
254 }
255}
256
257impl trace::Tracer for BoxedTracer {
258 /// Global tracer uses `BoxedSpan`s so that it can be a global singleton,
259 /// which is not possible if it takes generic type parameters.
260 type Span = BoxedSpan;
261
262 /// Create a span from a `SpanBuilder`
263 fn build_with_context(&self, builder: trace::SpanBuilder, parent_cx: &Context) -> Self::Span {
264 BoxedSpan(self.0.build_with_context_boxed(builder, parent_cx))
265 }
266}
267
268/// Allows a specific [`Tracer`] to be used generically by [`BoxedTracer`]
269/// instances by mirroring the interface and boxing the return types.
270///
271/// [`Tracer`]: crate::trace::Tracer
272pub trait ObjectSafeTracer {
273 /// Returns a trait object so the underlying implementation can be swapped
274 /// out at runtime.
275 fn build_with_context_boxed(
276 &self,
277 builder: trace::SpanBuilder,
278 parent_cx: &Context,
279 ) -> Box<dyn ObjectSafeSpan + Send + Sync>;
280}
281
282impl<S, T> ObjectSafeTracer for T
283where
284 S: trace::Span + Send + Sync + 'static,
285 T: trace::Tracer<Span = S>,
286{
287 /// Returns a trait object so the underlying implementation can be swapped
288 /// out at runtime.
289 fn build_with_context_boxed(
290 &self,
291 builder: trace::SpanBuilder,
292 parent_cx: &Context,
293 ) -> Box<dyn ObjectSafeSpan + Send + Sync> {
294 Box::new(self.build_with_context(builder, parent_cx))
295 }
296}
297
298/// Allows a specific [`TracerProvider`] to be used generically by the
299/// [`GlobalTracerProvider`] by mirroring the interface and boxing the return types.
300///
301/// [`TracerProvider`]: crate::trace::TracerProvider
302/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
303pub trait ObjectSafeTracerProvider {
304 /// Creates a versioned named tracer instance that is a trait object through the underlying
305 /// `TracerProvider`.
306 fn boxed_tracer(&self, scope: InstrumentationScope) -> Box<dyn ObjectSafeTracer + Send + Sync>;
307}
308
309impl<S, T, P> ObjectSafeTracerProvider for P
310where
311 S: trace::Span + Send + Sync + 'static,
312 T: trace::Tracer<Span = S> + Send + Sync + 'static,
313 P: trace::TracerProvider<Tracer = T>,
314{
315 /// Return a versioned boxed tracer
316 fn boxed_tracer(&self, scope: InstrumentationScope) -> Box<dyn ObjectSafeTracer + Send + Sync> {
317 Box::new(self.tracer_with_scope(scope))
318 }
319}
320
321/// Represents the globally configured [`TracerProvider`] instance for this
322/// application. This allows generic tracing through the returned
323/// [`BoxedTracer`] instances.
324///
325/// [`TracerProvider`]: crate::trace::TracerProvider
326#[derive(Clone)]
327pub struct GlobalTracerProvider {
328 provider: Arc<dyn ObjectSafeTracerProvider + Send + Sync>,
329}
330
331impl fmt::Debug for GlobalTracerProvider {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 f.write_str("GlobalTracerProvider")
334 }
335}
336
337impl GlobalTracerProvider {
338 /// Create a new GlobalTracerProvider instance from a struct that implements `TracerProvider`.
339 fn new<P, T, S>(provider: P) -> Self
340 where
341 S: trace::Span + Send + Sync + 'static,
342 T: trace::Tracer<Span = S> + Send + Sync + 'static,
343 P: trace::TracerProvider<Tracer = T> + Send + Sync + 'static,
344 {
345 GlobalTracerProvider {
346 provider: Arc::new(provider),
347 }
348 }
349}
350
351impl trace::TracerProvider for GlobalTracerProvider {
352 type Tracer = BoxedTracer;
353
354 /// Create a tracer using the global provider.
355 fn tracer_with_scope(&self, scope: InstrumentationScope) -> Self::Tracer {
356 BoxedTracer(self.provider.boxed_tracer(scope))
357 }
358}
359
360/// The global `Tracer` provider singleton.
361static GLOBAL_TRACER_PROVIDER: OnceLock<RwLock<GlobalTracerProvider>> = OnceLock::new();
362
363#[inline]
364fn global_tracer_provider() -> &'static RwLock<GlobalTracerProvider> {
365 GLOBAL_TRACER_PROVIDER
366 .get_or_init(|| RwLock::new(GlobalTracerProvider::new(NoopTracerProvider::new())))
367}
368
369/// Returns an instance of the currently configured global [`TracerProvider`] through
370/// [`GlobalTracerProvider`].
371///
372/// [`TracerProvider`]: crate::trace::TracerProvider
373/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
374pub fn tracer_provider() -> GlobalTracerProvider {
375 // Try to get the global tracer provider. If the RwLock is poisoned, we'll log an error and return a NoopTracerProvider.
376 let global_provider = global_tracer_provider().read();
377 if let Ok(provider) = global_provider {
378 provider.clone()
379 } else {
380 otel_error!(name: "TracerProvider.GlobalGetFailed", message = "Getting global tracer provider failed. Traces created using global::tracer() or global::tracer_with_scope() will not function. Report this issue in OpenTelemetry repo.");
381 GlobalTracerProvider::new(NoopTracerProvider::new())
382 }
383}
384
385/// Creates a named instance of [`Tracer`] via the configured [`GlobalTracerProvider`].
386///
387/// If the name is an empty string, the provider will use a default name.
388///
389/// This is a more convenient way of expressing `global::tracer_provider().tracer(name)`.
390///
391/// [`Tracer`]: crate::trace::Tracer
392pub fn tracer(name: impl Into<Cow<'static, str>>) -> BoxedTracer {
393 tracer_provider().tracer(name.into())
394}
395
396/// Creates a [`Tracer`] with the given instrumentation scope
397/// via the configured [`GlobalTracerProvider`].
398///
399/// This is a simpler alternative to `global::tracer_provider().tracer_with_scope(...)`
400///
401/// # Example
402///
403/// ```
404/// use std::sync::Arc;
405/// use opentelemetry::global::tracer_with_scope;
406/// use opentelemetry::InstrumentationScope;
407/// use opentelemetry::KeyValue;
408///
409/// let scope = InstrumentationScope::builder("io.opentelemetry")
410/// .with_version("0.17")
411/// .with_schema_url("https://opentelemetry.io/schema/1.2.0")
412/// .with_attributes(vec![(KeyValue::new("key", "value"))])
413/// .build();
414///
415/// let tracer = tracer_with_scope(scope);
416/// ```
417///
418/// [`Tracer`]: crate::trace::Tracer
419pub fn tracer_with_scope(scope: InstrumentationScope) -> BoxedTracer {
420 tracer_provider().tracer_with_scope(scope)
421}
422
423/// Sets the given [`TracerProvider`] instance as the current global provider.
424///
425/// Libraries should NOT call this function. It is intended for applications/executables.
426/// [`TracerProvider`]: crate::trace::TracerProvider
427pub fn set_tracer_provider<P, T, S>(new_provider: P)
428where
429 S: trace::Span + Send + Sync + 'static,
430 T: trace::Tracer<Span = S> + Send + Sync + 'static,
431 P: trace::TracerProvider<Tracer = T> + Send + Sync + 'static,
432{
433 let mut global_provider = global_tracer_provider().write();
434 if let Ok(ref mut provider) = global_provider {
435 **provider = GlobalTracerProvider::new(new_provider);
436 otel_info!(name: "TracerProvider.GlobalSet", message = "Global tracer provider is set. Traces can now be created using global::tracer() or global::tracer_with_scope().");
437 } else {
438 otel_error!(name: "TracerProvider.GlobalSetFailed", message = "Setting global tracer provider failed. Traces created using global::tracer() or global::tracer_with_scope() will not function. Report this issue in OpenTelemetry repo.");
439 }
440}