eaze_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
90/// A `Span` holds ready-to-publish information gathered during the lifetime of a `tracing::Span`.
91#[derive(Debug, Clone)]
92pub struct Span<Visitor, SpanId, TraceId> {
93    /// id identifying this span
94    pub id: SpanId,
95    /// `TraceId` identifying the trace to which this span belongs
96    pub trace_id: TraceId,
97    /// optional parent span id
98    pub parent_id: Option<SpanId>,
99    /// UTC time at which this span was initialized
100    pub initialized_at: SystemTime,
101    /// `chrono::Duration` elapsed between the time this span was initialized and the time it was completed
102    pub completed_at: SystemTime,
103    /// `tracing::Metadata` for this span
104    pub meta: &'static tracing::Metadata<'static>,
105    /// name of the service on which this span occured
106    pub service_name: &'static str,
107    /// values accumulated by visiting fields observed by the `tracing::Span` this span was derived from
108    pub values: Visitor,
109}
110
111/// An `Event` holds ready-to-publish information derived from a `tracing::Event`.
112#[derive(Clone, Debug)]
113pub struct Event<Visitor, SpanId, TraceId> {
114    /// `TraceId` identifying the trace to which this event belongs
115    pub trace_id: TraceId,
116    /// optional parent span id
117    pub parent_id: Option<SpanId>,
118    /// UTC time at which this event was initialized
119    pub initialized_at: SystemTime,
120    /// `tracing::Metadata` for this event
121    pub meta: &'static tracing::Metadata<'static>,
122    /// name of the service on which this event occured
123    pub service_name: &'static str,
124    /// values accumulated by visiting the fields of the `tracing::Event` this event was derived from
125    pub values: Visitor,
126}