opentelemetry/global/
trace.rs

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