opentelemetry/trace/
mod.rs

1//! API for tracing applications and libraries.
2//!
3//! The `trace` module includes types for tracking the progression of a single
4//! request while it is handled by services that make up an application. A trace
5//! is a tree of [`Span`]s which are objects that represent the work being done
6//! by individual services or components involved in a request as it flows
7//! through a system. This module implements the OpenTelemetry [trace
8//! specification].
9//!
10//! [trace specification]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md
11//!
12//! ## Getting Started
13//!
14//! In application code:
15//!
16//! ```
17//! use opentelemetry::trace::{Tracer, noop::NoopTracerProvider};
18//! use opentelemetry::global;
19//!
20//! fn init_tracer() {
21//!     // Swap this no-op provider for your tracing service of choice (jaeger, zipkin, etc)
22//!     let provider = NoopTracerProvider::new();
23//!
24//!     // Configure the global `TracerProvider` singleton when your app starts
25//!     // (there is a no-op default if this is not set by your application)
26//!     let _ = global::set_tracer_provider(provider);
27//! }
28//!
29//! fn do_something_tracked() {
30//!     // Then you can get a named tracer instance anywhere in your codebase.
31//!     let tracer = global::tracer("my-component");
32//!
33//!     tracer.in_span("doing_work", |cx| {
34//!         // Traced app logic here...
35//!     });
36//! }
37//!
38//! // in main or other app start
39//! init_tracer();
40//! do_something_tracked();
41//! ```
42//!
43//! In library code:
44//!
45//! ```
46//! use opentelemetry::{global, trace::{Span, Tracer, TracerProvider}};
47//! use opentelemetry::InstrumentationScope;
48//! use std::sync::Arc;
49//!
50//! fn my_library_function() {
51//!     // Use the global tracer provider to get access to the user-specified
52//!     // tracer configuration
53//!     let tracer_provider = global::tracer_provider();
54//!
55//!     // Get a tracer for this library
56//!     let scope = InstrumentationScope::builder("my_name")
57//!         .with_version(env!("CARGO_PKG_VERSION"))
58//!         .with_schema_url("https://opentelemetry.io/schemas/1.17.0")
59//!         .build();
60//!
61//!     let tracer = tracer_provider.tracer_with_scope(scope);
62//!
63//!     // Create spans
64//!     let mut span = tracer.start("doing_work");
65//!
66//!     // Do work...
67//!
68//!     // End the span
69//!     span.end();
70//! }
71//! ```
72//!
73//! ## Overview
74//!
75//! The tracing API consists of a three main traits:
76//!
77//! * [`TracerProvider`]s are the entry point of the API. They provide access to
78//!   `Tracer`s.
79//! * [`Tracer`]s are types responsible for creating `Span`s.
80//! * [`Span`]s provide the API to trace an operation.
81//!
82//! ## Working with Async Runtimes
83//!
84//! Exporting spans often involves sending data over a network or performing
85//! other I/O tasks. OpenTelemetry allows you to schedule these tasks using
86//! whichever runtime you are already using such as [Tokio] or [async-std].
87//! When using an async runtime it's best to use the batch span processor
88//! where the spans will be sent in batches as opposed to being sent once ended,
89//! which often ends up being more efficient.
90//!
91//! [Tokio]: https://tokio.rs
92//! [async-std]: https://async.rs
93//!
94//! ## Managing Active Spans
95//!
96//! Spans can be marked as "active" for a given [`Context`], and all newly
97//! created spans will automatically be children of the currently active span.
98//!
99//! The active span for a given thread can be managed via [`get_active_span`]
100//! and [`mark_span_as_active`].
101//!
102//! [`Context`]: crate::Context
103//!
104//! ```
105//! use opentelemetry::{global, trace::{self, Span, Status, Tracer, TracerProvider}};
106//!
107//! fn may_error(rand: f32) {
108//!     if rand < 0.5 {
109//!         // Get the currently active span to record additional attributes,
110//!         // status, etc.
111//!         trace::get_active_span(|span| {
112//!             span.set_status(Status::error("value too small"));
113//!         });
114//!     }
115//! }
116//!
117//! // Get a tracer
118//! let tracer = global::tracer("my_tracer");
119//!
120//! // Create a span
121//! let span = tracer.start("parent_span");
122//!
123//! // Mark the span as active
124//! let active = trace::mark_span_as_active(span);
125//!
126//! // Any span created here will be a child of `parent_span`...
127//!
128//! // Drop the guard and the span will no longer be active
129//! drop(active)
130//! ```
131//!
132//! Additionally [`Tracer::in_span`] can be used as shorthand to simplify
133//! managing the parent context.
134//!
135//! ```
136//! use opentelemetry::{global, trace::Tracer};
137//!
138//! // Get a tracer
139//! let tracer = global::tracer("my_tracer");
140//!
141//! // Use `in_span` to create a new span and mark it as the parent, dropping it
142//! // at the end of the block.
143//! tracer.in_span("parent_span", |cx| {
144//!     // spans created here will be children of `parent_span`
145//! });
146//! ```
147//!
148//! #### Async active spans
149//!
150//! Async spans can be propagated with [`TraceContextExt`] and [`FutureExt`].
151//!
152//! ```
153//! use opentelemetry::{Context, global, trace::{FutureExt, TraceContextExt, Tracer}};
154//!
155//! async fn some_work() { }
156//! # async fn in_an_async_context() {
157//!
158//! // Get a tracer
159//! let tracer = global::tracer("my_tracer");
160//!
161//! // Start a span
162//! let span = tracer.start("my_span");
163//!
164//! // Perform some async work with this span as the currently active parent.
165//! some_work().with_context(Context::current_with_span(span)).await;
166//! # }
167//! ```
168
169use std::borrow::Cow;
170use std::time;
171use thiserror::Error;
172
173pub(crate) mod context;
174pub mod noop;
175mod span;
176mod span_context;
177mod tracer;
178mod tracer_provider;
179
180pub use self::{
181    context::{
182        get_active_span, mark_span_as_active, FutureExt, SpanRef, TraceContextExt, WithContext,
183    },
184    span::{Span, SpanKind, Status},
185    span_context::{SpanContext, TraceState},
186    tracer::{SamplingDecision, SamplingResult, SpanBuilder, Tracer},
187    tracer_provider::TracerProvider,
188};
189use crate::KeyValue;
190pub use crate::{SpanId, TraceFlags, TraceId};
191use std::sync::PoisonError;
192
193// TODO - Move ExportError and TraceError to opentelemetry-sdk
194
195/// Trait for errors returned by exporters
196pub trait ExportError: std::error::Error + Send + Sync + 'static {
197    /// The name of exporter that returned this error
198    fn exporter_name(&self) -> &'static str;
199}
200
201/// Describe the result of operations in tracing API.
202pub type TraceResult<T> = Result<T, TraceError>;
203
204/// Errors returned by the trace API.
205#[derive(Error, Debug)]
206#[non_exhaustive]
207pub enum TraceError {
208    /// Export failed with the error returned by the exporter
209    #[error("Exporter {0} encountered the following error(s): {name}", name = .0.exporter_name())]
210    ExportFailed(Box<dyn ExportError>),
211
212    /// Export failed to finish after certain period and processor stopped the export.
213    #[error("Exporting timed out after {} seconds", .0.as_secs())]
214    ExportTimedOut(time::Duration),
215
216    /// already shutdown error
217    #[error("TracerProvider already shutdown")]
218    TracerProviderAlreadyShutdown,
219
220    /// Other errors propagated from trace SDK that weren't covered above
221    #[error(transparent)]
222    Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
223}
224
225impl<T> From<T> for TraceError
226where
227    T: ExportError,
228{
229    fn from(err: T) -> Self {
230        TraceError::ExportFailed(Box::new(err))
231    }
232}
233
234impl From<String> for TraceError {
235    fn from(err_msg: String) -> Self {
236        TraceError::Other(Box::new(Custom(err_msg)))
237    }
238}
239
240impl From<&'static str> for TraceError {
241    fn from(err_msg: &'static str) -> Self {
242        TraceError::Other(Box::new(Custom(err_msg.into())))
243    }
244}
245
246impl<T> From<PoisonError<T>> for TraceError {
247    fn from(err: PoisonError<T>) -> Self {
248        TraceError::Other(err.to_string().into())
249    }
250}
251
252/// Wrap type for string
253#[derive(Error, Debug)]
254#[error("{0}")]
255struct Custom(String);
256
257/// Events record things that happened during a [`Span`]'s lifetime.
258#[non_exhaustive]
259#[derive(Clone, Debug, PartialEq)]
260pub struct Event {
261    /// The name of this event.
262    pub name: Cow<'static, str>,
263
264    /// The time at which this event occurred.
265    pub timestamp: time::SystemTime,
266
267    /// Attributes that describe this event.
268    pub attributes: Vec<KeyValue>,
269
270    /// The number of attributes that were above the configured limit, and thus
271    /// dropped.
272    pub dropped_attributes_count: u32,
273}
274
275impl Event {
276    /// Create new `Event`
277    pub fn new<T: Into<Cow<'static, str>>>(
278        name: T,
279        timestamp: time::SystemTime,
280        attributes: Vec<KeyValue>,
281        dropped_attributes_count: u32,
282    ) -> Self {
283        Event {
284            name: name.into(),
285            timestamp,
286            attributes,
287            dropped_attributes_count,
288        }
289    }
290
291    /// Create new `Event` with a given name.
292    pub fn with_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
293        Event {
294            name: name.into(),
295            timestamp: crate::time::now(),
296            attributes: Vec::new(),
297            dropped_attributes_count: 0,
298        }
299    }
300}
301
302/// Link is the relationship between two Spans.
303///
304/// The relationship can be within the same trace or across different traces.
305#[non_exhaustive]
306#[derive(Clone, Debug, PartialEq)]
307pub struct Link {
308    /// The span context of the linked span.
309    pub span_context: SpanContext,
310
311    /// Attributes that describe this link.
312    pub attributes: Vec<KeyValue>,
313
314    /// The number of attributes that were above the configured limit, and thus
315    /// dropped.
316    pub dropped_attributes_count: u32,
317}
318
319impl Link {
320    /// Create new `Link`
321    pub fn new(
322        span_context: SpanContext,
323        attributes: Vec<KeyValue>,
324        dropped_attributes_count: u32,
325    ) -> Self {
326        Link {
327            span_context,
328            attributes,
329            dropped_attributes_count,
330        }
331    }
332
333    /// Create new `Link` with given context
334    pub fn with_context(span_context: SpanContext) -> Self {
335        Link {
336            span_context,
337            attributes: Vec::new(),
338            dropped_attributes_count: 0,
339        }
340    }
341}