opentelemetry_spanprocessor_any/trace/
tracer.rs

1use crate::{
2    sdk,
3    trace::{Event, Link, Span, SpanId, SpanKind, StatusCode, TraceContextExt, TraceId},
4    Context, KeyValue,
5};
6use std::borrow::Cow;
7use std::time::SystemTime;
8
9/// Interface for constructing `Span`s.
10///
11/// The OpenTelemetry library achieves in-process context propagation of `Span`s
12/// by way of the `Tracer`.
13///
14/// The `Tracer` is responsible for tracking the currently active `Span`, and
15/// exposes methods for creating and activating new `Spans`. The `Tracer` is
16/// configured with `Propagators` which support transferring span context across
17/// process boundaries.
18///
19/// `Tracer`s are generally expected to be used as singletons. Implementations
20/// SHOULD provide a single global default Tracer.
21///
22/// Some applications may require multiple `Tracer` instances, e.g. to create
23/// `Span`s on behalf of other applications. Implementations MAY provide a
24/// global registry of Tracers for such applications.
25///
26/// The `Tracer` SHOULD allow end users to configure other tracing components
27/// that control how `Span`s are passed across process boundaries, including the
28/// binary and text format `Propagator`s used to serialize `Span`s created by
29/// the `Tracer`.
30///
31/// ## In Synchronous Code
32///
33/// Spans can be created and nested manually:
34///
35/// ```
36/// use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context};
37///
38/// let tracer = global::tracer("my-component");
39///
40/// let parent = tracer.start("foo");
41/// let parent_cx = Context::current_with_span(parent);
42/// let mut child = tracer.span_builder("bar").start_with_context(&tracer, &parent_cx);
43///
44/// // ...
45///
46/// child.end();
47/// drop(parent_cx) // end parent
48/// ```
49///
50/// Spans can also use the current thread's [`Context`] to track which span is active:
51///
52/// ```
53/// use opentelemetry::{global, trace::{SpanKind, Tracer}};
54///
55/// let tracer = global::tracer("my-component");
56///
57/// // Create simple spans with `in_span`
58/// tracer.in_span("foo", |_foo_cx| {
59///     // parent span is active
60///     tracer.in_span("bar", |_bar_cx| {
61///         // child span is now the active span and associated with the parent span
62///     });
63///     // child has ended, parent now the active span again
64/// });
65/// // parent has ended, no active spans
66///
67/// // -- OR --
68///
69/// // create complex spans with span builder and `with_span`
70/// let parent_span = tracer.span_builder("foo").with_kind(SpanKind::Server).start(&tracer);
71/// tracer.with_span(parent_span, |_foo_cx| {
72///     // parent span is active
73///     let child_span = tracer.span_builder("bar").with_kind(SpanKind::Client).start(&tracer);
74///     tracer.with_span(child_span, |_bar_cx| {
75///         // child span is now the active span and associated with the parent span
76///     });
77///     // child has ended, parent now the active span again
78/// });
79/// // parent has ended, no active spans
80/// ```
81///
82/// Spans can also be marked as active, and the resulting guard allows for
83/// greater control over when the span is no longer considered active.
84///
85/// ```
86/// use opentelemetry::{global, trace::{Span, Tracer, mark_span_as_active}};
87/// let tracer = global::tracer("my-component");
88///
89/// let parent_span = tracer.start("foo");
90/// let parent_active = mark_span_as_active(parent_span);
91///
92/// {
93///     let child = tracer.start("bar");
94///     let _child_active = mark_span_as_active(child);
95///
96///     // do work in the context of the child span...
97///
98///     // exiting the scope drops the guard, child is no longer active
99/// }
100/// // Parent is active span again
101///
102/// // Parent can be dropped manually, or allowed to go out of scope as well.
103/// drop(parent_active);
104///
105/// // no active span
106/// ```
107///
108/// ## In Asynchronous Code
109///
110/// If you are instrumenting code that make use of [`std::future::Future`] or
111/// async/await, be sure to use the [`FutureExt`] trait. This is needed because
112/// the following example _will not_ work:
113///
114/// ```no_run
115/// # use opentelemetry::{global, trace::{Tracer, mark_span_as_active}};
116/// # let tracer = global::tracer("foo");
117/// # let span = tracer.start("foo-span");
118/// async {
119///     // Does not work
120///     let _g = mark_span_as_active(span);
121///     // ...
122/// };
123/// ```
124///
125/// The context guard `_g` will not exit until the future generated by the
126/// `async` block is complete. Since futures can be entered and exited
127/// _multiple_ times without them completing, the span remains active for as
128/// long as the future exists, rather than only when it is polled, leading to
129/// very confusing and incorrect output.
130///
131/// In order to trace asynchronous code, the [`Future::with_context`] combinator
132/// can be used:
133///
134/// ```
135/// # async fn run() -> Result<(), ()> {
136/// use opentelemetry::{trace::FutureExt, Context};
137/// let cx = Context::current();
138///
139/// let my_future = async {
140///     // ...
141/// };
142///
143/// my_future
144///     .with_context(cx)
145///     .await;
146/// # Ok(())
147/// # }
148/// ```
149///
150/// [`Future::with_context`] attaches a context to the future, ensuring that the
151/// context's lifetime is as long as the future's.
152///
153/// [`FutureExt`]: crate::trace::FutureExt
154/// [`Future::with_context`]: crate::trace::FutureExt::with_context()
155/// [`Context`]: crate::Context
156pub trait Tracer {
157    /// The `Span` type used by this `Tracer`.
158    type Span: Span;
159
160    /// Starts a new `Span`.
161    ///
162    /// By default the currently active `Span` is set as the new `Span`'s
163    /// parent. The `Tracer` MAY provide other default options for newly
164    /// created `Span`s.
165    ///
166    /// `Span` creation MUST NOT set the newly created `Span` as the currently
167    /// active `Span` by default, but this functionality MAY be offered additionally
168    /// as a separate operation.
169    ///
170    /// Each span has zero or one parent spans and zero or more child spans, which
171    /// represent causally related operations. A tree of related spans comprises a
172    /// trace. A span is said to be a _root span_ if it does not have a parent. Each
173    /// trace includes a single root span, which is the shared ancestor of all other
174    /// spans in the trace. Implementations MUST provide an option to create a `Span` as
175    /// a root span, and MUST generate a new `TraceId` for each root span created.
176    /// For a Span with a parent, the `TraceId` MUST be the same as the parent.
177    /// Also, the child span MUST inherit all `TraceState` values of its parent by default.
178    ///
179    /// A `Span` is said to have a _remote parent_ if it is the child of a `Span`
180    /// created in another process. Each propagators' deserialization must set
181    /// `is_remote` to true on a parent `SpanContext` so `Span` creation knows if the
182    /// parent is remote.
183    fn start<T>(&self, name: T) -> Self::Span
184    where
185        T: Into<Cow<'static, str>>,
186    {
187        self.start_with_context(name, &Context::current())
188    }
189
190    /// Starts a new `Span` with a given context
191    ///
192    /// By default the currently active `Span` is set as the new `Span`'s
193    /// parent. The `Tracer` MAY provide other default options for newly
194    /// created `Span`s.
195    ///
196    /// `Span` creation MUST NOT set the newly created `Span` as the currently
197    /// active `Span` by default, but this functionality MAY be offered additionally
198    /// as a separate operation.
199    ///
200    /// Each span has zero or one parent spans and zero or more child spans, which
201    /// represent causally related operations. A tree of related spans comprises a
202    /// trace. A span is said to be a _root span_ if it does not have a parent. Each
203    /// trace includes a single root span, which is the shared ancestor of all other
204    /// spans in the trace. Implementations MUST provide an option to create a `Span` as
205    /// a root span, and MUST generate a new `TraceId` for each root span created.
206    /// For a Span with a parent, the `TraceId` MUST be the same as the parent.
207    /// Also, the child span MUST inherit all `TraceState` values of its parent by default.
208    ///
209    /// A `Span` is said to have a _remote parent_ if it is the child of a `Span`
210    /// created in another process. Each propagators' deserialization must set
211    /// `is_remote` to true on a parent `SpanContext` so `Span` creation knows if the
212    /// parent is remote.
213    fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
214    where
215        T: Into<Cow<'static, str>>;
216
217    /// Creates a span builder
218    ///
219    /// An ergonomic way for attributes to be configured before the `Span` is started.
220    fn span_builder<T>(&self, name: T) -> SpanBuilder
221    where
222        T: Into<Cow<'static, str>>;
223
224    /// Create a span from a [SpanBuilder]
225    fn build(&self, builder: SpanBuilder) -> Self::Span {
226        self.build_with_context(builder, &Context::current())
227    }
228
229    /// Create a span from a [SpanBuilder] with a parent context.
230    fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
231
232    /// Start a new span and execute the given closure with reference to the span's
233    /// context.
234    ///
235    /// This method starts a new span and sets it as the active span for the given
236    /// function. It then executes the body. It closes the span before returning the
237    /// execution result.
238    ///
239    /// # Examples
240    ///
241    /// ```
242    /// use opentelemetry::{global, trace::{Span, Tracer, get_active_span}, KeyValue};
243    ///
244    /// fn my_function() {
245    ///     // start an active span in one function
246    ///     global::tracer("my-component").in_span("span-name", |_cx| {
247    ///         // anything happening in functions we call can still access the active span...
248    ///         my_other_function();
249    ///     })
250    /// }
251    ///
252    /// fn my_other_function() {
253    ///     // call methods on the current span from
254    ///     get_active_span(|span| {
255    ///         span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
256    ///     })
257    /// }
258    /// ```
259    fn in_span<T, F>(&self, name: &'static str, f: F) -> T
260    where
261        F: FnOnce(Context) -> T,
262        Self::Span: Send + Sync + 'static,
263    {
264        let span = self.start(name);
265        let cx = Context::current_with_span(span);
266        let _guard = cx.clone().attach();
267        f(cx)
268    }
269
270    /// Start a new span and execute the given closure with reference to the span's
271    /// context.
272    ///
273    /// This method starts a new span and sets it as the active span for the given
274    /// function. It then executes the body. It closes the span before returning the
275    /// execution result.
276    ///
277    /// # Examples
278    ///
279    /// ```
280    /// use opentelemetry::{global, trace::{Span, SpanKind, Tracer, get_active_span}, KeyValue};
281    ///
282    /// fn my_function() {
283    ///     let tracer = global::tracer("my-component");
284    ///     // start a span with custom attributes via span builder
285    ///     let span = tracer.span_builder("span-name").with_kind(SpanKind::Server).start(&tracer);
286    ///     // Mark the span as active for the duration of the closure
287    ///     global::tracer("my-component").with_span(span, |_cx| {
288    ///         // anything happening in functions we call can still access the active span...
289    ///         my_other_function();
290    ///     })
291    /// }
292    ///
293    /// fn my_other_function() {
294    ///     // call methods on the current span from
295    ///     get_active_span(|span| {
296    ///         span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
297    ///     })
298    /// }
299    /// ```
300    fn with_span<T, F>(&self, span: Self::Span, f: F) -> T
301    where
302        F: FnOnce(Context) -> T,
303        Self::Span: Send + Sync + 'static,
304    {
305        let cx = Context::current_with_span(span);
306        let _guard = cx.clone().attach();
307        f(cx)
308    }
309}
310
311/// `SpanBuilder` allows span attributes to be configured before the span
312/// has started.
313///
314/// ```
315/// use opentelemetry::{
316///     global,
317///     trace::{TracerProvider, SpanBuilder, SpanKind, Tracer},
318/// };
319///
320/// let tracer = global::tracer("example-tracer");
321///
322/// // The builder can be used to create a span directly with the tracer
323/// let _span = tracer.build(SpanBuilder {
324///     name: "example-span-name".into(),
325///     span_kind: Some(SpanKind::Server),
326///     ..Default::default()
327/// });
328///
329/// // Or used with builder pattern
330/// let _span = tracer
331///     .span_builder("example-span-name")
332///     .with_kind(SpanKind::Server)
333///     .start(&tracer);
334/// ```
335#[derive(Clone, Debug, Default)]
336pub struct SpanBuilder {
337    /// Trace id, useful for integrations with external tracing systems.
338    pub trace_id: Option<TraceId>,
339    /// Span id, useful for integrations with external tracing systems.
340    pub span_id: Option<SpanId>,
341    /// Span kind
342    pub span_kind: Option<SpanKind>,
343    /// Span name
344    pub name: Cow<'static, str>,
345    /// Span start time
346    pub start_time: Option<SystemTime>,
347    /// Span end time
348    pub end_time: Option<SystemTime>,
349    /// Span attributes
350    pub attributes: Option<Vec<KeyValue>>,
351    /// Span events
352    pub events: Option<Vec<Event>>,
353    /// Span Links
354    pub links: Option<Vec<Link>>,
355    /// Span status code
356    pub status_code: Option<StatusCode>,
357    /// Span status message
358    pub status_message: Option<Cow<'static, str>>,
359    /// Sampling result
360    pub sampling_result: Option<sdk::trace::SamplingResult>,
361}
362
363/// SpanBuilder methods
364impl SpanBuilder {
365    /// Create a new span builder from a span name
366    pub fn from_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
367        SpanBuilder {
368            name: name.into(),
369            ..Default::default()
370        }
371    }
372
373    /// Specify trace id to use if no parent context exists
374    pub fn with_trace_id(self, trace_id: TraceId) -> Self {
375        SpanBuilder {
376            trace_id: Some(trace_id),
377            ..self
378        }
379    }
380
381    /// Assign span id
382    pub fn with_span_id(self, span_id: SpanId) -> Self {
383        SpanBuilder {
384            span_id: Some(span_id),
385            ..self
386        }
387    }
388
389    /// Assign span kind
390    pub fn with_kind(self, span_kind: SpanKind) -> Self {
391        SpanBuilder {
392            span_kind: Some(span_kind),
393            ..self
394        }
395    }
396
397    /// Assign span start time
398    pub fn with_start_time<T: Into<SystemTime>>(self, start_time: T) -> Self {
399        SpanBuilder {
400            start_time: Some(start_time.into()),
401            ..self
402        }
403    }
404
405    /// Assign span end time
406    pub fn with_end_time<T: Into<SystemTime>>(self, end_time: T) -> Self {
407        SpanBuilder {
408            end_time: Some(end_time.into()),
409            ..self
410        }
411    }
412
413    /// Assign span attributes
414    pub fn with_attributes(self, attributes: Vec<KeyValue>) -> Self {
415        SpanBuilder {
416            attributes: Some(attributes),
417            ..self
418        }
419    }
420
421    /// Assign events
422    pub fn with_events(self, events: Vec<Event>) -> Self {
423        SpanBuilder {
424            events: Some(events),
425            ..self
426        }
427    }
428
429    /// Assign links
430    pub fn with_links(self, mut links: Vec<Link>) -> Self {
431        links.retain(|l| l.span_context().is_valid());
432        SpanBuilder {
433            links: Some(links),
434            ..self
435        }
436    }
437
438    /// Assign status code
439    pub fn with_status_code(self, code: StatusCode) -> Self {
440        SpanBuilder {
441            status_code: Some(code),
442            ..self
443        }
444    }
445
446    /// Assign status message
447    pub fn with_status_message<T: Into<Cow<'static, str>>>(self, message: T) -> Self {
448        SpanBuilder {
449            status_message: Some(message.into()),
450            ..self
451        }
452    }
453
454    /// Assign sampling result
455    pub fn with_sampling_result(self, sampling_result: sdk::trace::SamplingResult) -> Self {
456        SpanBuilder {
457            sampling_result: Some(sampling_result),
458            ..self
459        }
460    }
461
462    /// Builds a span with the given tracer from this configuration.
463    pub fn start<T: Tracer>(self, tracer: &T) -> T::Span {
464        tracer.build_with_context(self, &Context::current())
465    }
466
467    /// Builds a span with the given tracer from this configuration and parent.
468    pub fn start_with_context<T: Tracer>(self, tracer: &T, parent_cx: &Context) -> T::Span {
469        tracer.build_with_context(self, parent_cx)
470    }
471}