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].
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//!
93//! ## Managing Active Spans
94//!
95//! Spans can be marked as "active" for a given [`Context`], and all newly
96//! created spans will automatically be children of the currently active span.
97//!
98//! The active span for a given thread can be managed via [`get_active_span`]
99//! and [`mark_span_as_active`].
100//!
101//! [`Context`]: crate::Context
102//!
103//! ```
104//! use opentelemetry::{global, trace::{self, Span, Status, Tracer, TracerProvider}};
105//!
106//! fn may_error(rand: f32) {
107//!     if rand < 0.5 {
108//!         // Get the currently active span to record additional attributes,
109//!         // status, etc.
110//!         trace::get_active_span(|span| {
111//!             span.set_status(Status::error("value too small"));
112//!         });
113//!     }
114//! }
115//!
116//! // Get a tracer
117//! let tracer = global::tracer("my_tracer");
118//!
119//! // Create a span
120//! let span = tracer.start("parent_span");
121//!
122//! // Mark the span as active
123//! let active = trace::mark_span_as_active(span);
124//!
125//! // Any span created here will be a child of `parent_span`...
126//!
127//! // Drop the guard and the span will no longer be active
128//! drop(active)
129//! ```
130//!
131//! Additionally [`Tracer::in_span`] can be used as shorthand to simplify
132//! managing the parent context.
133//!
134//! ```
135//! use opentelemetry::{global, trace::Tracer};
136//!
137//! // Get a tracer
138//! let tracer = global::tracer("my_tracer");
139//!
140//! // Use `in_span` to create a new span and mark it as the parent, dropping it
141//! // at the end of the block.
142//! tracer.in_span("parent_span", |cx| {
143//!     // spans created here will be children of `parent_span`
144//! });
145//! ```
146//!
147//! #### Async active spans
148//!
149//! Async spans can be propagated with [`TraceContextExt`] and [`FutureExt`].
150//!
151//! ```
152//! use opentelemetry::{Context, global, trace::{FutureExt, TraceContextExt, Tracer}};
153//!
154//! async fn some_work() { }
155//! # async fn in_an_async_context() {
156//!
157//! // Get a tracer
158//! let tracer = global::tracer("my_tracer");
159//!
160//! // Start a span
161//! let span = tracer.start("my_span");
162//!
163//! // Perform some async work with this span as the currently active parent.
164//! some_work().with_context(Context::current_with_span(span)).await;
165//! # }
166//! ```
167
168use std::borrow::Cow;
169use std::time;
170
171pub(crate) mod context;
172pub mod noop;
173mod span;
174mod span_context;
175mod tracer;
176mod tracer_provider;
177
178pub use self::{
179    context::{
180        get_active_span, mark_span_as_active, FutureExt, SpanRef, TraceContextExt, WithContext,
181    },
182    span::{Span, SpanKind, Status},
183    span_context::{SpanContext, TraceState},
184    tracer::{SamplingDecision, SamplingResult, SpanBuilder, Tracer},
185    tracer_provider::TracerProvider,
186};
187use crate::KeyValue;
188pub use crate::{SpanId, TraceFlags, TraceId};
189
190/// Events record things that happened during a [`Span`]'s lifetime.
191#[non_exhaustive]
192#[derive(Clone, Debug, PartialEq)]
193pub struct Event {
194    /// The name of this event.
195    pub name: Cow<'static, str>,
196
197    /// The time at which this event occurred.
198    pub timestamp: time::SystemTime,
199
200    /// Attributes that describe this event.
201    pub attributes: Vec<KeyValue>,
202
203    /// The number of attributes that were above the configured limit, and thus
204    /// dropped.
205    pub dropped_attributes_count: u32,
206}
207
208impl Event {
209    /// Create new `Event`
210    pub fn new<T: Into<Cow<'static, str>>>(
211        name: T,
212        timestamp: time::SystemTime,
213        attributes: Vec<KeyValue>,
214        dropped_attributes_count: u32,
215    ) -> Self {
216        Event {
217            name: name.into(),
218            timestamp,
219            attributes,
220            dropped_attributes_count,
221        }
222    }
223
224    /// Create new `Event` with a given name.
225    pub fn with_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
226        Event {
227            name: name.into(),
228            timestamp: crate::time::now(),
229            attributes: Vec::new(),
230            dropped_attributes_count: 0,
231        }
232    }
233}
234
235/// Link is the relationship between two Spans.
236///
237/// The relationship can be within the same trace or across different traces.
238#[non_exhaustive]
239#[derive(Clone, Debug, PartialEq)]
240pub struct Link {
241    /// The span context of the linked span.
242    pub span_context: SpanContext,
243
244    /// Attributes that describe this link.
245    pub attributes: Vec<KeyValue>,
246
247    /// The number of attributes that were above the configured limit, and thus
248    /// dropped.
249    pub dropped_attributes_count: u32,
250}
251
252impl Link {
253    /// Create new `Link`
254    pub fn new(
255        span_context: SpanContext,
256        attributes: Vec<KeyValue>,
257        dropped_attributes_count: u32,
258    ) -> Self {
259        Link {
260            span_context,
261            attributes,
262            dropped_attributes_count,
263        }
264    }
265
266    /// Create new `Link` with given context
267    pub fn with_context(span_context: SpanContext) -> Self {
268        Link {
269            span_context,
270            attributes: Vec::new(),
271            dropped_attributes_count: 0,
272        }
273    }
274}