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