ts_opentelemetry_api/global/
trace.rs

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