opentelemetry/global/trace.rs
1use crate::trace::{noop::NoopTracerProvider, SpanContext, Status};
2use crate::InstrumentationScope;
3use crate::{trace, trace::TracerProvider, Context, KeyValue};
4use std::borrow::Cow;
5use std::fmt;
6use std::mem;
7use std::sync::{Arc, OnceLock, 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 /// Adds a link to this span
89 ///
90 fn add_link(&mut self, span_context: SpanContext, attributes: Vec<KeyValue>);
91
92 /// Finishes the `Span`.
93 ///
94 /// Implementations MUST ignore all subsequent calls to `end` (there might be
95 /// exceptions when the tracer is streaming events and has no mutable state
96 /// associated with the Span).
97 ///
98 /// Calls to `end` a Span MUST not have any effects on child `Span`s as they may
99 /// still be running and can be ended later.
100 ///
101 /// This API MUST be non-blocking.
102 fn end(&mut self) {
103 self.end_with_timestamp(crate::time::now());
104 }
105
106 /// Finishes the `Span` with given timestamp
107 ///
108 /// For more details, refer to [`Span::end`]
109 ///
110 /// [`Span::end`]: trace::Span::end
111 fn end_with_timestamp(&mut self, timestamp: SystemTime);
112}
113
114impl<T: trace::Span> ObjectSafeSpan for T {
115 fn add_event_with_timestamp(
116 &mut self,
117 name: Cow<'static, str>,
118 timestamp: SystemTime,
119 attributes: Vec<KeyValue>,
120 ) {
121 self.add_event_with_timestamp(name, timestamp, attributes)
122 }
123
124 fn span_context(&self) -> &SpanContext {
125 self.span_context()
126 }
127
128 fn is_recording(&self) -> bool {
129 self.is_recording()
130 }
131
132 fn set_attribute(&mut self, attribute: KeyValue) {
133 self.set_attribute(attribute)
134 }
135
136 fn set_status(&mut self, status: Status) {
137 self.set_status(status)
138 }
139
140 fn update_name(&mut self, new_name: Cow<'static, str>) {
141 self.update_name(new_name)
142 }
143
144 fn add_link(&mut self, span_context: SpanContext, attributes: Vec<KeyValue>) {
145 self.add_link(span_context, attributes)
146 }
147
148 fn end_with_timestamp(&mut self, timestamp: SystemTime) {
149 self.end_with_timestamp(timestamp)
150 }
151}
152
153/// Wraps the [`BoxedTracer`]'s [`Span`] so it can be used generically by
154/// applications without knowing the underlying type.
155///
156/// [`Span`]: crate::trace::Span
157pub struct BoxedSpan(Box<dyn ObjectSafeSpan + Send + Sync>);
158
159impl BoxedSpan {
160 pub(crate) fn new<T>(span: T) -> Self
161 where
162 T: ObjectSafeSpan + Send + Sync + 'static,
163 {
164 BoxedSpan(Box::new(span))
165 }
166}
167
168impl fmt::Debug for BoxedSpan {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 f.write_str("BoxedSpan")
171 }
172}
173
174impl trace::Span for BoxedSpan {
175 /// Records events at a specific time in the context of a given `Span`.
176 ///
177 /// Note that the OpenTelemetry project documents certain ["standard event names and
178 /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
179 /// which have prescribed semantic meanings.
180 fn add_event_with_timestamp<T>(
181 &mut self,
182 name: T,
183 timestamp: SystemTime,
184 attributes: Vec<KeyValue>,
185 ) where
186 T: Into<Cow<'static, str>>,
187 {
188 self.0
189 .add_event_with_timestamp(name.into(), timestamp, attributes)
190 }
191
192 /// Returns the `SpanContext` for the given `Span`.
193 fn span_context(&self) -> &trace::SpanContext {
194 self.0.span_context()
195 }
196
197 /// Returns true if this `Span` is recording information like events with the `add_event`
198 /// operation, attributes using `set_attributes`, status with `set_status`, etc.
199 fn is_recording(&self) -> bool {
200 self.0.is_recording()
201 }
202
203 /// Sets a single `Attribute` where the attribute properties are passed as arguments.
204 ///
205 /// Note that the OpenTelemetry project documents certain ["standard
206 /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
207 /// that have prescribed semantic meanings.
208 fn set_attribute(&mut self, attribute: KeyValue) {
209 self.0.set_attribute(attribute)
210 }
211
212 /// Sets the status of the `Span`. If used, this will override the default `Span`
213 /// status, which is `Unset`.
214 fn set_status(&mut self, status: trace::Status) {
215 self.0.set_status(status)
216 }
217
218 /// Updates the `Span`'s name.
219 fn update_name<T>(&mut self, new_name: T)
220 where
221 T: Into<Cow<'static, str>>,
222 {
223 self.0.update_name(new_name.into())
224 }
225
226 /// Adds a link to this span
227 ///
228 fn add_link(&mut self, span_context: trace::SpanContext, attributes: Vec<KeyValue>) {
229 self.0.add_link(span_context, attributes)
230 }
231
232 /// Finishes the span with given timestamp.
233 fn end_with_timestamp(&mut self, timestamp: SystemTime) {
234 self.0.end_with_timestamp(timestamp);
235 }
236}
237
238/// Wraps the [`GlobalTracerProvider`]'s [`Tracer`] so it can be used generically by
239/// applications without knowing the underlying type.
240///
241/// [`Tracer`]: crate::trace::Tracer
242/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
243pub struct BoxedTracer(Box<dyn ObjectSafeTracer + Send + Sync>);
244
245impl BoxedTracer {
246 /// Create a `BoxedTracer` from an object-safe tracer.
247 pub fn new(tracer: Box<dyn ObjectSafeTracer + Send + Sync>) -> Self {
248 BoxedTracer(tracer)
249 }
250}
251
252impl fmt::Debug for BoxedTracer {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 f.write_str("BoxedTracer")
255 }
256}
257
258impl trace::Tracer for BoxedTracer {
259 /// Global tracer uses `BoxedSpan`s so that it can be a global singleton,
260 /// which is not possible if it takes generic type parameters.
261 type Span = BoxedSpan;
262
263 /// Create a span from a `SpanBuilder`
264 fn build_with_context(&self, builder: trace::SpanBuilder, parent_cx: &Context) -> Self::Span {
265 BoxedSpan(self.0.build_with_context_boxed(builder, parent_cx))
266 }
267}
268
269/// Allows a specific [`Tracer`] to be used generically by [`BoxedTracer`]
270/// instances by mirroring the interface and boxing the return types.
271///
272/// [`Tracer`]: crate::trace::Tracer
273pub trait ObjectSafeTracer {
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}
282
283impl<S, T> ObjectSafeTracer for T
284where
285 S: trace::Span + Send + Sync + 'static,
286 T: trace::Tracer<Span = S>,
287{
288 /// Returns a trait object so the underlying implementation can be swapped
289 /// out at runtime.
290 fn build_with_context_boxed(
291 &self,
292 builder: trace::SpanBuilder,
293 parent_cx: &Context,
294 ) -> Box<dyn ObjectSafeSpan + Send + Sync> {
295 Box::new(self.build_with_context(builder, parent_cx))
296 }
297}
298
299/// Allows a specific [`TracerProvider`] to be used generically by the
300/// [`GlobalTracerProvider`] by mirroring the interface and boxing the return types.
301///
302/// [`TracerProvider`]: crate::trace::TracerProvider
303/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
304pub trait ObjectSafeTracerProvider {
305 /// Creates a versioned named tracer instance that is a trait object through the underlying
306 /// `TracerProvider`.
307 fn boxed_tracer(&self, scope: InstrumentationScope) -> Box<dyn ObjectSafeTracer + Send + Sync>;
308}
309
310impl<S, T, P> ObjectSafeTracerProvider for P
311where
312 S: trace::Span + Send + Sync + 'static,
313 T: trace::Tracer<Span = S> + Send + Sync + 'static,
314 P: trace::TracerProvider<Tracer = T>,
315{
316 /// Return a versioned boxed tracer
317 fn boxed_tracer(&self, scope: InstrumentationScope) -> Box<dyn ObjectSafeTracer + Send + Sync> {
318 Box::new(self.tracer_with_scope(scope))
319 }
320}
321
322/// Represents the globally configured [`TracerProvider`] instance for this
323/// application. This allows generic tracing through the returned
324/// [`BoxedTracer`] instances.
325///
326/// [`TracerProvider`]: crate::trace::TracerProvider
327#[derive(Clone)]
328pub struct GlobalTracerProvider {
329 provider: Arc<dyn ObjectSafeTracerProvider + Send + Sync>,
330}
331
332impl fmt::Debug for GlobalTracerProvider {
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 f.write_str("GlobalTracerProvider")
335 }
336}
337
338impl GlobalTracerProvider {
339 /// Create a new GlobalTracerProvider instance from a struct that implements `TracerProvider`.
340 fn new<P, T, S>(provider: P) -> Self
341 where
342 S: trace::Span + Send + Sync + 'static,
343 T: trace::Tracer<Span = S> + Send + Sync + 'static,
344 P: trace::TracerProvider<Tracer = T> + Send + Sync + 'static,
345 {
346 GlobalTracerProvider {
347 provider: Arc::new(provider),
348 }
349 }
350}
351
352impl trace::TracerProvider for GlobalTracerProvider {
353 type Tracer = BoxedTracer;
354
355 /// Create a tracer using the global provider.
356 fn tracer_with_scope(&self, scope: InstrumentationScope) -> Self::Tracer {
357 BoxedTracer(self.provider.boxed_tracer(scope))
358 }
359}
360
361/// The global `Tracer` provider singleton.
362static GLOBAL_TRACER_PROVIDER: OnceLock<RwLock<GlobalTracerProvider>> = OnceLock::new();
363
364#[inline]
365fn global_tracer_provider() -> &'static RwLock<GlobalTracerProvider> {
366 GLOBAL_TRACER_PROVIDER
367 .get_or_init(|| RwLock::new(GlobalTracerProvider::new(NoopTracerProvider::new())))
368}
369
370/// Returns an instance of the currently configured global [`TracerProvider`] through
371/// [`GlobalTracerProvider`].
372///
373/// [`TracerProvider`]: crate::trace::TracerProvider
374/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
375pub fn tracer_provider() -> GlobalTracerProvider {
376 global_tracer_provider()
377 .read()
378 .expect("GLOBAL_TRACER_PROVIDER RwLock poisoned")
379 .clone()
380}
381
382/// Creates a named instance of [`Tracer`] via the configured [`GlobalTracerProvider`].
383///
384/// If the name is an empty string, the provider will use a default name.
385///
386/// This is a more convenient way of expressing `global::tracer_provider().tracer(name)`.
387///
388/// [`Tracer`]: crate::trace::Tracer
389pub fn tracer(name: impl Into<Cow<'static, str>>) -> BoxedTracer {
390 tracer_provider().tracer(name.into())
391}
392
393/// Creates a [`Tracer`] with the given instrumentation scope
394/// via the configured [`GlobalTracerProvider`].
395///
396/// This is a simpler alternative to `global::tracer_provider().tracer_with_scope(...)`
397///
398/// # Example
399///
400/// ```
401/// use std::sync::Arc;
402/// use opentelemetry::global::tracer_with_scope;
403/// use opentelemetry::InstrumentationScope;
404/// use opentelemetry::KeyValue;
405///
406/// let scope = InstrumentationScope::builder("io.opentelemetry")
407/// .with_version("0.17")
408/// .with_schema_url("https://opentelemetry.io/schema/1.2.0")
409/// .with_attributes(vec![(KeyValue::new("key", "value"))])
410/// .build();
411///
412/// let tracer = tracer_with_scope(scope);
413/// ```
414///
415/// [`Tracer`]: crate::trace::Tracer
416pub fn tracer_with_scope(scope: InstrumentationScope) -> BoxedTracer {
417 tracer_provider().tracer_with_scope(scope)
418}
419
420/// Sets the given [`TracerProvider`] instance as the current global provider.
421///
422/// It returns the [`TracerProvider`] instance that was previously mounted as global provider
423/// (e.g. [`NoopTracerProvider`] if a provider had not been set before).
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) -> GlobalTracerProvider
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 tracer_provider = global_tracer_provider()
434 .write()
435 .expect("GLOBAL_TRACER_PROVIDER RwLock poisoned");
436 mem::replace(
437 &mut *tracer_provider,
438 GlobalTracerProvider::new(new_provider),
439 )
440}