Skip to main content

opentelemetry/trace/
tracer.rs

1use crate::{
2    trace::{Event, Link, Span, SpanKind, TraceContextExt},
3    Context, KeyValue,
4};
5use std::borrow::Cow;
6use std::time::SystemTime;
7
8/// The interface for constructing [`Span`]s.
9///
10/// ## In Synchronous Code
11///
12/// Spans can be created and nested manually:
13///
14/// ```
15/// use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context};
16///
17/// let tracer = global::tracer("my-component");
18///
19/// let parent = tracer.start("foo");
20/// let parent_cx = Context::current_with_span(parent);
21/// let mut child = tracer.start_with_context("bar", &parent_cx);
22///
23/// // ...
24///
25/// child.end(); // explicitly end
26/// drop(parent_cx) // or implicitly end on drop
27/// ```
28///
29/// Spans can also use the current thread's [`Context`] to track which span is active:
30///
31/// ```
32/// use opentelemetry::{global, trace::{SpanKind, Tracer}};
33///
34/// let tracer = global::tracer("my-component");
35///
36/// // Create simple spans with `in_span`
37/// tracer.in_span("foo", |_foo_cx| {
38///     // parent span is active
39///     tracer.in_span("bar", |_bar_cx| {
40///         // child span is now the active span and associated with the parent span
41///     });
42///     // child has ended, parent now the active span again
43/// });
44/// // parent has ended, no active spans
45/// ```
46///
47/// Spans can also be marked as active, and the resulting guard allows for
48/// greater control over when the span is no longer considered active.
49///
50/// ```
51/// use opentelemetry::{global, trace::{Span, Tracer, mark_span_as_active}};
52/// let tracer = global::tracer("my-component");
53///
54/// let parent_span = tracer.start("foo");
55/// let parent_active = mark_span_as_active(parent_span);
56///
57/// {
58///     let child = tracer.start("bar");
59///     let _child_active = mark_span_as_active(child);
60///
61///     // do work in the context of the child span...
62///
63///     // exiting the scope drops the guard, child is no longer active
64/// }
65/// // Parent is active span again
66///
67/// // Parent can be dropped manually, or allowed to go out of scope as well.
68/// drop(parent_active);
69///
70/// // no active span
71/// ```
72///
73/// ## In Asynchronous Code
74///
75/// Pass a [`Context`] explicitly to [`Tracer::start_with_context`] when you
76/// want to choose a span's parent. To make a context current within async
77/// code, use [`FutureExt::with_context`]. Do not hold a [`Context::attach`]
78/// guard or a [`mark_span_as_active`] guard across an `.await`: while the
79/// task is suspended, unrelated code on the same thread could see that
80/// context as current.
81///
82/// ```
83/// # async fn run() -> Result<(), ()> {
84/// use opentelemetry::{trace::FutureExt, Context};
85/// let cx = Context::current();
86///
87/// let my_future = async {
88///     // ...
89/// };
90///
91/// my_future
92///     .with_context(cx)
93///     .await;
94/// # Ok(())
95/// # }
96/// ```
97///
98/// The wrapper makes the context current for each poll and restores the
99/// previous context when that poll returns. Creating a span, making it current,
100/// and ending it are separate operations. See [Async context
101/// propagation](crate::trace#async-context-propagation) for an example that
102/// creates a child span inside a future.
103///
104/// [`FutureExt::with_context`]: crate::trace::FutureExt::with_context
105/// [`mark_span_as_active`]: crate::trace::mark_span_as_active
106/// [`Context`]: crate::Context
107pub trait Tracer {
108    /// The [`Span`] type used by this tracer.
109    type Span: Span;
110
111    /// Starts a new [`Span`].
112    ///
113    /// By default the currently active `Span` is set as the new `Span`'s parent.
114    ///
115    /// Each span has zero or one parent span and zero or more child spans, which
116    /// represent causally related operations. A tree of related spans comprises a
117    /// trace. A span is said to be a root span if it does not have a parent. Each
118    /// trace includes a single root span, which is the shared ancestor of all other
119    /// spans in the trace.
120    fn start<T>(&self, name: T) -> Self::Span
121    where
122        T: Into<Cow<'static, str>>,
123    {
124        Context::map_current(|cx| self.start_with_context(name, cx))
125    }
126
127    /// Starts a new [`Span`] with a given context.
128    ///
129    /// If this context contains a span, the newly created span will be a child of
130    /// that span.
131    ///
132    /// Each span has zero or one parent span and zero or more child spans, which
133    /// represent causally related operations. A tree of related spans comprises a
134    /// trace. A span is said to be a root span if it does not have a parent. Each
135    /// trace includes a single root span, which is the shared ancestor of all other
136    /// spans in the trace.
137    fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
138    where
139        T: Into<Cow<'static, str>>,
140    {
141        self.build_with_context(SpanBuilder::from_name(name), parent_cx)
142    }
143
144    /// Creates a span builder.
145    ///
146    /// [`SpanBuilder`]s allow you to specify all attributes of a [`Span`] before
147    /// the span is started.
148    fn span_builder<T>(&self, name: T) -> SpanBuilder
149    where
150        T: Into<Cow<'static, str>>,
151    {
152        SpanBuilder::from_name(name)
153    }
154
155    /// Start a [`Span`] from a [`SpanBuilder`].
156    fn build(&self, builder: SpanBuilder) -> Self::Span {
157        Context::map_current(|cx| self.build_with_context(builder, cx))
158    }
159
160    /// Start a span from a [`SpanBuilder`] with a parent context.
161    fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
162
163    /// Start a new span and execute the given closure with reference to the context
164    /// in which the span is active.
165    ///
166    /// This method starts a new span and sets it as the active span for the given
167    /// function. It then executes the body. It ends the span before returning the
168    /// execution result.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// use opentelemetry::{global, trace::{Span, Tracer, get_active_span}, KeyValue};
174    ///
175    /// fn my_function() {
176    ///     // start an active span in one function
177    ///     global::tracer("my-component").in_span("span-name", |_cx| {
178    ///         // anything happening in functions we call can still access the active span...
179    ///         my_other_function();
180    ///     })
181    /// }
182    ///
183    /// fn my_other_function() {
184    ///     // call methods on the current span from
185    ///     get_active_span(|span| {
186    ///         span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
187    ///     })
188    /// }
189    /// ```
190    fn in_span<T, F, N>(&self, name: N, f: F) -> T
191    where
192        F: FnOnce(Context) -> T,
193        N: Into<Cow<'static, str>>,
194        Self::Span: Send + Sync + 'static,
195    {
196        self.in_span_with_builder(self.span_builder(name), f)
197    }
198
199    /// Start a new span with a given parent context and execute the given closure with
200    /// reference to the context in which the span is active.
201    ///
202    /// This method starts a new span as a child of the provided parent context and sets
203    /// it as the active span for the given function. It then executes the body. It ends
204    /// the span before returning the execution result.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context, KeyValue};
210    ///
211    /// fn my_function() {
212    ///     let tracer = global::tracer("my-component");
213    ///
214    ///     // Create a parent context
215    ///     let parent = tracer.start("parent-span");
216    ///     let parent_cx = Context::current_with_span(parent);
217    ///
218    ///     // start an active span with explicit parent context
219    ///     tracer.in_span_with_context("child-span", &parent_cx, |_cx| {
220    ///         // child span is active here
221    ///     })
222    /// }
223    /// ```
224    fn in_span_with_context<T, F, N>(&self, name: N, parent_cx: &Context, f: F) -> T
225    where
226        F: FnOnce(Context) -> T,
227        N: Into<Cow<'static, str>>,
228        Self::Span: Send + Sync + 'static,
229    {
230        self.in_span_with_builder_and_context(self.span_builder(name), parent_cx, f)
231    }
232
233    /// Start a new span from a [`SpanBuilder`] and execute the given closure with
234    /// reference to the context in which the span is active.
235    ///
236    /// This method builds and starts a new span from a [`SpanBuilder`] using the current
237    /// context and sets it as the active span for the given function. It then executes
238    /// the body. It ends the span before returning the execution result.
239    ///
240    /// # Examples
241    ///
242    /// ```
243    /// use opentelemetry::{global, trace::{Span, SpanKind, Tracer}, KeyValue};
244    ///
245    /// fn my_function() {
246    ///     let tracer = global::tracer("my-component");
247    ///
248    ///     // start an active span with span configuration
249    ///     tracer.in_span_with_builder(
250    ///         tracer.span_builder("span-name")
251    ///             .with_kind(SpanKind::Client)
252    ///             .with_attributes(vec![KeyValue::new("key", "value")]),
253    ///         |_cx| {
254    ///             // span is active here with configured attributes
255    ///         }
256    ///     )
257    /// }
258    /// ```
259    fn in_span_with_builder<T, F>(&self, builder: SpanBuilder, f: F) -> T
260    where
261        F: FnOnce(Context) -> T,
262        Self::Span: Send + Sync + 'static,
263    {
264        let span = self.build(builder);
265        let cx = Context::current_with_span(span);
266        let _guard = cx.clone().attach();
267        f(cx)
268    }
269
270    /// Start a new span from a [`SpanBuilder`] with a given parent context and execute the
271    /// given closure with reference to the context in which the span is active.
272    ///
273    /// This method builds and starts a new span from a [`SpanBuilder`] as a child of the
274    /// provided parent context and sets it as the active span for the given function. It
275    /// then executes the body. It ends the span before returning the execution result.
276    ///
277    /// # Examples
278    ///
279    /// ```
280    /// use opentelemetry::{global, trace::{Span, SpanKind, Tracer, TraceContextExt}, Context, KeyValue};
281    ///
282    /// fn my_function() {
283    ///     let tracer = global::tracer("my-component");
284    ///
285    ///     // Create a parent context
286    ///     let parent = tracer.start("parent-span");
287    ///     let parent_cx = Context::current_with_span(parent);
288    ///
289    ///     // start an active span with explicit parent context and span configuration
290    ///     tracer.in_span_with_builder_and_context(
291    ///         tracer.span_builder("child-span")
292    ///             .with_kind(SpanKind::Client)
293    ///             .with_attributes(vec![KeyValue::new("key", "value")]),
294    ///         &parent_cx,
295    ///         |_cx| {
296    ///             // child span is active here with configured attributes
297    ///         }
298    ///     )
299    /// }
300    /// ```
301    fn in_span_with_builder_and_context<T, F>(
302        &self,
303        builder: SpanBuilder,
304        parent_cx: &Context,
305        f: F,
306    ) -> T
307    where
308        F: FnOnce(Context) -> T,
309        Self::Span: Send + Sync + 'static,
310    {
311        let span = self.build_with_context(builder, parent_cx);
312        let cx = parent_cx.with_span(span);
313        let _guard = cx.clone().attach();
314        f(cx)
315    }
316}
317
318/// `SpanBuilder` allows span attributes to be configured before the span
319/// has started.
320///
321/// ```
322/// use opentelemetry::{
323///     global,
324///     trace::{TracerProvider, SpanBuilder, SpanKind, Tracer},
325/// };
326///
327/// let tracer = global::tracer("example-tracer");
328///
329/// // The builder can be used to create a span directly with the tracer
330/// let _span = tracer.build(SpanBuilder {
331///     name: "example-span-name".into(),
332///     span_kind: Some(SpanKind::Server),
333///     ..Default::default()
334/// });
335///
336/// // Or used with builder pattern
337/// let _span = tracer
338///     .span_builder("example-span-name")
339///     .with_kind(SpanKind::Server)
340///     .start(&tracer);
341/// ```
342#[derive(Clone, Debug, Default)]
343pub struct SpanBuilder {
344    /// Span kind
345    pub span_kind: Option<SpanKind>,
346
347    /// Span name
348    pub name: Cow<'static, str>,
349
350    /// Span start time
351    pub start_time: Option<SystemTime>,
352
353    /// Span attributes that are provided at the span creation time.
354    /// More attributes can be added afterwards.
355    /// Providing duplicate keys will result in multiple attributes
356    /// with the same key, as there is no de-duplication performed.
357    pub attributes: Option<Vec<KeyValue>>,
358
359    /// Span events
360    pub events: Option<Vec<Event>>,
361
362    /// Span Links
363    pub links: Option<Vec<Link>>,
364}
365
366/// SpanBuilder methods
367impl SpanBuilder {
368    /// Create a new span builder from a span name
369    pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
370        SpanBuilder {
371            name: name.into(),
372            ..Default::default()
373        }
374    }
375
376    /// Assign span kind
377    pub fn with_kind(self, span_kind: SpanKind) -> Self {
378        SpanBuilder {
379            span_kind: Some(span_kind),
380            ..self
381        }
382    }
383
384    /// Assign span start time
385    pub fn with_start_time<T: Into<SystemTime>>(self, start_time: T) -> Self {
386        SpanBuilder {
387            start_time: Some(start_time.into()),
388            ..self
389        }
390    }
391
392    /// Assign span attributes from an iterable.
393    /// Providing duplicate keys will result in multiple attributes
394    /// with the same key, as there is no de-duplication performed.    
395    pub fn with_attributes<I>(self, attributes: I) -> Self
396    where
397        I: IntoIterator<Item = KeyValue>,
398    {
399        SpanBuilder {
400            attributes: Some(attributes.into_iter().collect()),
401            ..self
402        }
403    }
404
405    /// Assign events
406    pub fn with_events(self, events: Vec<Event>) -> Self {
407        SpanBuilder {
408            events: Some(events),
409            ..self
410        }
411    }
412
413    /// Assign links
414    pub fn with_links(self, mut links: Vec<Link>) -> Self {
415        links.retain(|l| l.span_context.is_valid());
416        SpanBuilder {
417            links: Some(links),
418            ..self
419        }
420    }
421
422    /// Builds a span with the given tracer from this configuration.
423    pub fn start<T: Tracer>(self, tracer: &T) -> T::Span {
424        Context::map_current(|cx| tracer.build_with_context(self, cx))
425    }
426
427    /// Builds a span with the given tracer from this configuration and parent.
428    pub fn start_with_context<T: Tracer>(self, tracer: &T, parent_cx: &Context) -> T::Span {
429        tracer.build_with_context(self, parent_cx)
430    }
431}