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}