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}