tracing_distributed/
trace.rs

1use crate::telemetry_layer::TraceCtxRegistry;
2use std::time::SystemTime;
3use tracing_subscriber::registry::LookupSpan;
4
5/// Register the current span as the local root of a distributed trace.
6pub fn register_dist_tracing_root<SpanId, TraceId>(
7    trace_id: TraceId,
8    remote_parent_span: Option<SpanId>,
9) -> Result<(), TraceCtxError>
10where
11    SpanId: 'static + Clone + Send + Sync,
12    TraceId: 'static + Clone + Send + Sync,
13{
14    let span = tracing::Span::current();
15    span.with_subscriber(|(current_span_id, dispatch)| {
16        if let Some(trace_ctx_registry) =
17            dispatch.downcast_ref::<TraceCtxRegistry<SpanId, TraceId>>()
18        {
19            trace_ctx_registry.record_trace_ctx(
20                trace_id,
21                remote_parent_span,
22                current_span_id.clone(),
23            );
24            Ok(())
25        } else {
26            Err(TraceCtxError::TelemetryLayerNotRegistered)
27        }
28    })
29    .ok_or(TraceCtxError::NoEnabledSpan)?
30}
31
32/// Retrieve the distributed trace context associated with the current span. Returns the
33/// `TraceId`, if any, that the current span is associated with along with the `SpanId`
34/// belonging to the current span.
35pub fn current_dist_trace_ctx<SpanId, TraceId>() -> Result<(TraceId, SpanId), TraceCtxError>
36where
37    SpanId: 'static + Clone + Send + Sync,
38    TraceId: 'static + Clone + Send + Sync,
39{
40    let span = tracing::Span::current();
41    span.with_subscriber(|(current_span_id, dispatch)| {
42        let trace_ctx_registry = dispatch
43            .downcast_ref::<TraceCtxRegistry<SpanId, TraceId>>()
44            .ok_or(TraceCtxError::TelemetryLayerNotRegistered)?;
45
46        let registry = dispatch
47            .downcast_ref::<tracing_subscriber::Registry>()
48            .ok_or(TraceCtxError::RegistrySubscriberNotRegistered)?;
49
50        let iter = itertools::unfold(Some(current_span_id.clone()), |st| match st {
51            Some(target_id) => {
52                // failure here indicates a broken parent id span link, panic is valid
53                let res = registry
54                    .span(target_id)
55                    .expect("span data not found during eval_ctx for current_trace_ctx");
56                *st = res.parent().map(|x| x.id());
57                Some(res)
58            }
59            None => None,
60        });
61
62        trace_ctx_registry
63            .eval_ctx(iter)
64            .map(|x| {
65                (
66                    x.trace_id,
67                    trace_ctx_registry.promote_span_id(current_span_id.clone()),
68                )
69            })
70            .ok_or(TraceCtxError::NoParentNodeHasTraceCtx)
71    })
72    .ok_or(TraceCtxError::NoEnabledSpan)?
73}
74
75/// Errors that can occur while registering the current span as a distributed trace root or
76/// attempting to retrieve the current trace context.
77#[derive(PartialEq, Eq, Hash, Clone, Debug)]
78#[non_exhaustive]
79pub enum TraceCtxError {
80    /// Expected a `TelemetryLayer` to be registered as a subscriber associated with the current Span.
81    TelemetryLayerNotRegistered,
82    /// Expected a `tracing_subscriber::Registry` to be registered as a subscriber associated with the current Span.
83    RegistrySubscriberNotRegistered,
84    /// Expected the span returned by `tracing::Span::current()` to be enabled, with an associated subscriber.
85    NoEnabledSpan,
86    /// Attempted to evaluate the current distributed trace context but none was found. If this occurs, you should check to make sure that `register_dist_tracing_root` is called in some parent of the current span.
87    NoParentNodeHasTraceCtx,
88}
89
90impl std::fmt::Display for TraceCtxError {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        use TraceCtxError::*;
93        write!(f, "{}",
94            match self {
95                TelemetryLayerNotRegistered => "`TelemetryLayer` is not a registered subscriber of the current Span",
96                RegistrySubscriberNotRegistered => "no `tracing_subscriber::Registry` is a registered subscriber of the current Span",
97                NoEnabledSpan => "the span is not enabled with an associated subscriber",
98                NoParentNodeHasTraceCtx => "unable to evaluate trace context; assert `register_dist_tracing_root` is called in some parent span",
99            })
100    }
101}
102
103impl std::error::Error for TraceCtxError {}
104
105/// A `Span` holds ready-to-publish information gathered during the lifetime of a `tracing::Span`.
106#[derive(Debug, Clone)]
107pub struct Span<Visitor, SpanId, TraceId> {
108    /// id identifying this span
109    pub id: SpanId,
110    /// `TraceId` identifying the trace to which this span belongs
111    pub trace_id: TraceId,
112    /// optional parent span id
113    pub parent_id: Option<SpanId>,
114    /// UTC time at which this span was initialized
115    pub initialized_at: SystemTime,
116    /// `chrono::Duration` elapsed between the time this span was initialized and the time it was completed
117    pub completed_at: SystemTime,
118    /// `tracing::Metadata` for this span
119    pub meta: &'static tracing::Metadata<'static>,
120    /// name of the service on which this span occured
121    pub service_name: &'static str,
122    /// values accumulated by visiting fields observed by the `tracing::Span` this span was derived from
123    pub values: Visitor,
124}
125
126/// An `Event` holds ready-to-publish information derived from a `tracing::Event`.
127#[derive(Clone, Debug)]
128pub struct Event<Visitor, SpanId, TraceId> {
129    /// `TraceId` identifying the trace to which this event belongs
130    pub trace_id: TraceId,
131    /// optional parent span id
132    pub parent_id: Option<SpanId>,
133    /// UTC time at which this event was initialized
134    pub initialized_at: SystemTime,
135    /// `tracing::Metadata` for this event
136    pub meta: &'static tracing::Metadata<'static>,
137    /// name of the service on which this event occured
138    pub service_name: &'static str,
139    /// values accumulated by visiting the fields of the `tracing::Event` this event was derived from
140    pub values: Visitor,
141}