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 context propagation
148//!
149//! OpenTelemetry [`Context`] carries request-scoped information, including the
150//! active span. It does not propagate across async boundaries automatically.
151//! Use [`FutureExt::with_context`] to wrap a future when it should run with a
152//! particular context. Spans created inside that future will then be children
153//! of the active span.
154//!
155//! For common HTTP, database, and messaging libraries, use OpenTelemetry
156//! instrumentation when available. It can propagate context into outgoing
157//! calls as well.
158//!
159//! This example creates a request span and a child span for loading data.
160//!
161//! ```
162//! use opentelemetry::{
163//! global,
164//! trace::{FutureExt, TraceContextExt, Tracer},
165//! Context,
166//! };
167//!
168//! async fn load_data() {
169//! // Load data here.
170//! }
171//!
172//! async fn handle_request() {
173//! let tracer = global::tracer("my-component");
174//! async {
175//! let child = tracer.start("load_data");
176//! load_data()
177//! .with_context(Context::current_with_span(child))
178//! .await;
179//! }
180//! .with_context(Context::current_with_span(tracer.start("request")))
181//! .await;
182//! }
183//! ```
184//!
185//! [`Context::current_with_span`]: TraceContextExt::current_with_span
186
187use std::borrow::Cow;
188use std::time;
189
190pub(crate) mod context;
191pub mod noop;
192mod span;
193mod span_context;
194mod tracer;
195mod tracer_provider;
196
197pub use self::{
198 context::{
199 get_active_span, mark_span_as_active, FutureExt, SpanRef, TraceContextExt, WithContext,
200 },
201 span::{Span, SpanKind, Status},
202 span_context::{SpanContext, TraceState},
203 tracer::{SpanBuilder, Tracer},
204 tracer_provider::TracerProvider,
205};
206use crate::KeyValue;
207pub use crate::{SpanId, TraceFlags, TraceId};
208
209/// Events record things that happened during a [`Span`]'s lifetime.
210#[non_exhaustive]
211#[derive(Clone, Debug, PartialEq)]
212pub struct Event {
213 /// The name of this event.
214 pub name: Cow<'static, str>,
215
216 /// The time at which this event occurred.
217 pub timestamp: time::SystemTime,
218
219 /// Attributes that describe this event.
220 pub attributes: Vec<KeyValue>,
221
222 /// The number of attributes that were above the configured limit, and thus
223 /// dropped.
224 pub dropped_attributes_count: u32,
225}
226
227impl Event {
228 /// Create new `Event`
229 pub fn new<T: Into<Cow<'static, str>>>(
230 name: T,
231 timestamp: time::SystemTime,
232 attributes: Vec<KeyValue>,
233 dropped_attributes_count: u32,
234 ) -> Self {
235 Event {
236 name: name.into(),
237 timestamp,
238 attributes,
239 dropped_attributes_count,
240 }
241 }
242
243 /// Create new `Event` with a given name.
244 pub fn with_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
245 Event {
246 name: name.into(),
247 timestamp: crate::time::now(),
248 attributes: Vec::new(),
249 dropped_attributes_count: 0,
250 }
251 }
252}
253
254/// Link is the relationship between two Spans.
255///
256/// The relationship can be within the same trace or across different traces.
257#[non_exhaustive]
258#[derive(Clone, Debug, PartialEq)]
259pub struct Link {
260 /// The span context of the linked span.
261 pub span_context: SpanContext,
262
263 /// Attributes that describe this link.
264 pub attributes: Vec<KeyValue>,
265
266 /// The number of attributes that were above the configured limit, and thus
267 /// dropped.
268 pub dropped_attributes_count: u32,
269}
270
271impl Link {
272 /// Create new `Link`
273 pub fn new(
274 span_context: SpanContext,
275 attributes: Vec<KeyValue>,
276 dropped_attributes_count: u32,
277 ) -> Self {
278 Link {
279 span_context,
280 attributes,
281 dropped_attributes_count,
282 }
283 }
284
285 /// Create new `Link` with given context
286 pub fn with_context(span_context: SpanContext) -> Self {
287 Link {
288 span_context,
289 attributes: Vec::new(),
290 dropped_attributes_count: 0,
291 }
292 }
293}