opentelemetry_spanprocessor_any/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/v1.3.0/specification/trace/api.md
11//!
12//! ## Getting Started
13//!
14//! In application code:
15//!
16//! ```no_run
17//! # #[cfg(feature = "trace")]
18//! # {
19//! use opentelemetry::{global, sdk::export::trace::stdout, trace::Tracer};
20//!
21//! fn main() {
22//! // Create a new trace pipeline that prints to stdout
23//! let tracer = stdout::new_pipeline().install_simple();
24//!
25//! tracer.in_span("doing_work", |cx| {
26//! // Traced app logic here...
27//! });
28//!
29//! // Shutdown trace pipeline
30//! global::shutdown_tracer_provider();
31//! }
32//! # }
33//! ```
34//!
35//! In library code:
36//!
37//! ```
38//! # #[cfg(feature = "trace")]
39//! # {
40//! use opentelemetry::{global, trace::{Span, Tracer, TracerProvider}};
41//!
42//! fn my_library_function() {
43//! // Use the global tracer provider to get access to the user-specified
44//! // tracer configuration
45//! let tracer_provider = global::tracer_provider();
46//!
47//! // Get a tracer for this library
48//! let tracer = tracer_provider.versioned_tracer(
49//! "my_name",
50//! Some(env!("CARGO_PKG_VERSION")),
51//! None
52//! );
53//!
54//! // Create spans
55//! let mut span = tracer.start("doing_work");
56//!
57//! // Do work...
58//!
59//! // End the span
60//! span.end();
61//! }
62//! # }
63//! ```
64//!
65//! ## Overview
66//!
67//! The tracing API consists of a three main traits:
68//!
69//! * [`TracerProvider`]s are the entry point of the API. They provide access to
70//! `Tracer`s.
71//! * [`Tracer`]s are types responsible for creating `Span`s.
72//! * [`Span`]s provide the API to trace an operation.
73//!
74//! ## Working with Async Runtimes
75//!
76//! Exporting spans often involves sending data over a network or performing
77//! other I/O tasks. OpenTelemetry allows you to schedule these tasks using
78//! whichever runtime you area already using such as [Tokio] or [async-std].
79//! When using an async runtime it's best to use the [`BatchSpanProcessor`]
80//! where the spans will be sent in batches as opposed to being sent once ended,
81//! which often ends up being more efficient.
82//!
83//! [`BatchSpanProcessor`]: crate::sdk::trace::BatchSpanProcessor
84//! [Tokio]: https://tokio.rs
85//! [async-std]: https://async.rs
86//!
87//! ## Managing Active Spans
88//!
89//! Spans can be marked as "active" for a given [`Context`], and all newly
90//! created spans will automatically be children of the currently active span.
91//!
92//! The active span for a given thread can be managed via [`get_active_span`]
93//! and [`mark_span_as_active`].
94//!
95//! [`Context`]: crate::Context
96//!
97//! ```
98//! # #[cfg(feature = "trace")]
99//! # {
100//! use opentelemetry::{global, trace::{self, Span, StatusCode, Tracer, TracerProvider}};
101//!
102//! fn may_error(rand: f32) {
103//! if rand < 0.5 {
104//! // Get the currently active span to record additional attributes,
105//! // status, etc.
106//! trace::get_active_span(|span| {
107//! span.set_status(StatusCode::Error, "value too small".into());
108//! });
109//! }
110//! }
111//!
112//! // Get a tracer
113//! let tracer = global::tracer("my_tracer");
114//!
115//! // Create a span
116//! let span = tracer.start("parent_span");
117//!
118//! // Mark the span as active
119//! let active = trace::mark_span_as_active(span);
120//!
121//! // Any span created here will be a child of `parent_span`...
122//!
123//! // Drop the guard and the span will no longer be active
124//! drop(active)
125//! # }
126//! ```
127//!
128//! Additionally [`Tracer::with_span`] and [`Tracer::in_span`] can be used as shorthand to
129//! simplify managing the parent context.
130//!
131//! ```
132//! # #[cfg(feature = "trace")]
133//! # {
134//! use opentelemetry::{global, trace::Tracer};
135//!
136//! // Get a tracer
137//! let tracer = global::tracer("my_tracer");
138//!
139//! // Use `in_span` to create a new span and mark it as the parent, dropping it
140//! // at the end of the block.
141//! tracer.in_span("parent_span", |cx| {
142//! // spans created here will be children of `parent_span`
143//! });
144//!
145//! // Use `with_span` to mark a span as active for a given period.
146//! let span = tracer.start("parent_span");
147//! tracer.with_span(span, |cx| {
148//! // spans created here will be children of `parent_span`
149//! });
150//! # }
151//! ```
152//!
153//! #### Async active spans
154//!
155//! Async spans can be propagated with [`TraceContextExt`] and [`FutureExt`].
156//!
157//! ```
158//! # #[cfg(feature = "trace")]
159//! # {
160//! use opentelemetry::{Context, global, trace::{FutureExt, TraceContextExt, Tracer}};
161//!
162//! async fn some_work() { }
163//!
164//! // Get a tracer
165//! let tracer = global::tracer("my_tracer");
166//!
167//! // Start a span
168//! let span = tracer.start("my_span");
169//!
170//! // Perform some async work with this span as the currently active parent.
171//! some_work().with_context(Context::current_with_span(span));
172//! # }
173//! ```
174
175use futures_channel::{mpsc::TrySendError, oneshot::Canceled};
176#[cfg(feature = "serialize")]
177use serde::{Deserialize, Serialize};
178use std::borrow::Cow;
179use std::fmt;
180use std::time;
181use thiserror::Error;
182
183mod context;
184pub mod noop;
185mod span;
186mod span_context;
187mod tracer;
188mod tracer_provider;
189
190pub use self::{
191 context::{get_active_span, mark_span_as_active, FutureExt, SpanRef, TraceContextExt},
192 span::{Span, SpanKind, StatusCode},
193 span_context::{SpanContext, SpanId, TraceFlags, TraceId, TraceState, TraceStateError},
194 tracer::{SpanBuilder, Tracer},
195 tracer_provider::TracerProvider,
196};
197use crate::{sdk::export::ExportError, KeyValue};
198
199/// Describe the result of operations in tracing API.
200pub type TraceResult<T> = Result<T, TraceError>;
201
202/// Errors returned by the trace API.
203#[derive(Error, Debug)]
204#[non_exhaustive]
205pub enum TraceError {
206 /// Export failed with the error returned by the exporter
207 #[error("Exporter {} encountered the following error(s): {0}", .0.exporter_name())]
208 ExportFailed(Box<dyn ExportError>),
209
210 /// Export failed to finish after certain period and processor stopped the export.
211 #[error("Exporting timed out after {} seconds", .0.as_secs())]
212 ExportTimedOut(time::Duration),
213
214 /// Other errors propagated from trace SDK that weren't covered above
215 #[error(transparent)]
216 Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
217}
218
219impl<T> From<T> for TraceError
220where
221 T: ExportError,
222{
223 fn from(err: T) -> Self {
224 TraceError::ExportFailed(Box::new(err))
225 }
226}
227
228impl<T> From<TrySendError<T>> for TraceError {
229 fn from(err: TrySendError<T>) -> Self {
230 TraceError::Other(Box::new(err.into_send_error()))
231 }
232}
233
234impl From<Canceled> for TraceError {
235 fn from(err: Canceled) -> Self {
236 TraceError::Other(Box::new(err))
237 }
238}
239
240impl From<String> for TraceError {
241 fn from(err_msg: String) -> Self {
242 TraceError::Other(Box::new(Custom(err_msg)))
243 }
244}
245
246impl From<&'static str> for TraceError {
247 fn from(err_msg: &'static str) -> Self {
248 TraceError::Other(Box::new(Custom(err_msg.into())))
249 }
250}
251
252/// Wrap type for string
253#[derive(Error, Debug)]
254#[error("{0}")]
255struct Custom(String);
256
257/// Interface for generating IDs
258pub trait IdGenerator: Send + Sync + fmt::Debug {
259 /// Generate a new `TraceId`
260 fn new_trace_id(&self) -> TraceId;
261
262 /// Generate a new `SpanId`
263 fn new_span_id(&self) -> SpanId;
264}
265
266/// A `Span` has the ability to add events. Events have a time associated
267/// with the moment when they are added to the `Span`.
268#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
269#[derive(Clone, Debug, PartialEq)]
270pub struct Event {
271 /// Event name
272 pub name: Cow<'static, str>,
273 /// Event timestamp
274 pub timestamp: time::SystemTime,
275 /// Event attributes
276 pub attributes: Vec<KeyValue>,
277 /// Number of dropped attributes
278 pub dropped_attributes_count: u32,
279}
280
281impl Event {
282 /// Create new `Event`
283 pub fn new<T: Into<Cow<'static, str>>>(
284 name: T,
285 timestamp: time::SystemTime,
286 attributes: Vec<KeyValue>,
287 dropped_attributes_count: u32,
288 ) -> Self {
289 Event {
290 name: name.into(),
291 timestamp,
292 attributes,
293 dropped_attributes_count,
294 }
295 }
296
297 /// Create new `Event` with a given name.
298 pub fn with_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
299 Event {
300 name: name.into(),
301 timestamp: crate::time::now(),
302 attributes: Vec::new(),
303 dropped_attributes_count: 0,
304 }
305 }
306}
307
308/// During the `Span` creation user MUST have the ability to record links to other `Span`s. Linked
309/// `Span`s can be from the same or a different trace.
310#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
311#[derive(Clone, Debug, PartialEq)]
312pub struct Link {
313 span_context: SpanContext,
314 pub(crate) attributes: Vec<KeyValue>,
315 pub(crate) dropped_attributes_count: u32,
316}
317
318impl Link {
319 /// Create a new link
320 pub fn new(span_context: SpanContext, attributes: Vec<KeyValue>) -> Self {
321 Link {
322 span_context,
323 attributes,
324 dropped_attributes_count: 0,
325 }
326 }
327
328 /// The span context of the linked span
329 pub fn span_context(&self) -> &SpanContext {
330 &self.span_context
331 }
332
333 /// Attributes of the span link
334 pub fn attributes(&self) -> &Vec<KeyValue> {
335 &self.attributes
336 }
337
338 /// Dropped attributes count
339 pub fn dropped_attributes_count(&self) -> u32 {
340 self.dropped_attributes_count
341 }
342}