Skip to main content

cf_rustracing/
span.rs

1//! Span.
2use crate::carrier;
3use crate::convert::MaybeAsRef;
4use crate::log::{Log, LogBuilder, StdErrorLogFieldsBuilder};
5use crate::sampler::{AllSampler, Sampler};
6use crate::tag::{StdTag, Tag, TagValue};
7use crate::Result;
8use std::borrow::Cow;
9use std::fmt;
10use std::io::{Read, Write};
11use std::sync::Arc;
12use std::time::SystemTime;
13use tokio::sync::mpsc;
14
15/// Generic interface to receive [`FinishedSpan`]s from rustracing.
16pub trait SpanConsumer<T>: Send + Sync {
17    /// Consumes a [`FinishedSpan`] when the application closes a span.
18    ///
19    /// This should not block the caller for any significant amount of time.
20    /// It is better to drop spans if the consumer is overloaded.
21    fn consume_span(&self, span: FinishedSpan<T>);
22}
23
24impl<T: Send> SpanConsumer<T> for mpsc::UnboundedSender<FinishedSpan<T>> {
25    fn consume_span(&self, span: FinishedSpan<T>) {
26        let _ = self.send(span);
27    }
28}
29
30impl<T: Send> SpanConsumer<T> for mpsc::Sender<FinishedSpan<T>> {
31    fn consume_span(&self, span: FinishedSpan<T>) {
32        let _ = self.try_send(span);
33    }
34}
35
36impl<T: Send> SpanConsumer<T> for std::sync::mpsc::Sender<FinishedSpan<T>> {
37    fn consume_span(&self, span: FinishedSpan<T>) {
38        let _ = self.send(span);
39    }
40}
41
42impl<T: Send> SpanConsumer<T> for std::sync::mpsc::SyncSender<FinishedSpan<T>> {
43    fn consume_span(&self, span: FinishedSpan<T>) {
44        let _ = self.try_send(span);
45    }
46}
47
48/// Unbounded [`tokio::sync::mpsc`] receiver for finished spans.
49pub type SpanReceiver<T> = mpsc::UnboundedReceiver<FinishedSpan<T>>;
50/// Deprecated: alias for default [`SpanConsumer`] implementation.
51#[deprecated = "SpanSender is an implementation detail of rustracing. It should not be public."]
52pub type SpanSender<T> = mpsc::UnboundedSender<FinishedSpan<T>>;
53
54/// An `Arc<dyn SpanConsumer>` wrapper to implement `Debug` on.
55pub(crate) struct SharedSpanConsumer<T>(Arc<dyn SpanConsumer<T>>);
56
57impl<T> SharedSpanConsumer<T> {
58    pub(crate) fn new(consumer: impl SpanConsumer<T> + 'static) -> Self {
59        Self(Arc::new(consumer))
60    }
61}
62
63impl<T> fmt::Debug for SharedSpanConsumer<T> {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        f.write_str("SharedSpanConsumer")
66    }
67}
68
69impl<T> Clone for SharedSpanConsumer<T> {
70    fn clone(&self) -> Self {
71        Self(Arc::clone(&self.0))
72    }
73}
74
75/// Callback to execute before a [`Span`] is finalized.
76pub struct FinishSpanCallback<T>(FinishCallbackInner<T>);
77type FinishCallbackInner<T> = Arc<dyn Fn(&mut Span<T>) + Send + Sync>;
78
79impl<T> fmt::Debug for FinishSpanCallback<T> {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        f.write_str("FinishSpanCallback")
82    }
83}
84
85impl<T> Clone for FinishSpanCallback<T> {
86    fn clone(&self) -> Self {
87        Self(self.0.clone())
88    }
89}
90
91impl<T> From<FinishSpanCallback<T>> for FinishCallbackInner<T> {
92    fn from(v: FinishSpanCallback<T>) -> Self {
93        v.0
94    }
95}
96
97impl<T> From<FinishCallbackInner<T>> for FinishSpanCallback<T> {
98    fn from(v: FinishCallbackInner<T>) -> Self {
99        Self(v)
100    }
101}
102
103impl<T, F: Fn(&mut Span<T>) + Send + Sync + 'static> From<F> for FinishSpanCallback<T> {
104    fn from(v: F) -> Self {
105        Self(Arc::new(v))
106    }
107}
108
109/// Caller-defined routing attached to a span, inherited by children, and read by
110/// the exporter to route the resulting [`FinishedSpan`].
111pub trait RoutingMetadata: fmt::Debug + Send + Sync {
112    /// Batching key: spans sharing it are exported together. Must differ
113    /// whenever [`encode`](RoutingMetadata::encode) would.
114    fn group_key(&self) -> String;
115
116    /// The value the exporter transmits for this routing.
117    fn encode(&self) -> String;
118}
119
120/// Span.
121///
122/// When this span is dropped, it will be converted to `FinishedSpan` and
123/// it will be sent to the associated `SpanReceiver`.
124#[derive(Debug)]
125pub struct Span<T>(Option<SpanInner<T>>);
126impl<T> Span<T> {
127    /// Makes an inactive span.
128    ///
129    /// This span is never traced.
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// use cf_rustracing::span::Span;
135    ///
136    /// let span = Span::<()>::inactive();
137    /// assert!(! span.is_sampled());
138    /// ```
139    pub const fn inactive() -> Self {
140        Span(None)
141    }
142
143    /// Returns a handle of this span.
144    pub fn handle(&self) -> SpanHandle<T>
145    where
146        T: Clone,
147    {
148        SpanHandle(
149            self.0
150                .as_ref()
151                .map(|inner| (inner.context.clone(), inner.span_tx.clone())),
152        )
153    }
154
155    /// Returns `true` if this span is sampled (i.e., being traced).
156    pub fn is_sampled(&self) -> bool {
157        self.0.is_some()
158    }
159
160    /// Returns the context of this span.
161    pub fn context(&self) -> Option<&SpanContext<T>> {
162        self.0.as_ref().map(|x| &x.context)
163    }
164
165    /// Sets the operation name of this span.
166    pub fn set_operation_name<F, N>(&mut self, f: F)
167    where
168        F: FnOnce() -> N,
169        N: Into<Cow<'static, str>>,
170    {
171        if let Some(inner) = self.0.as_mut() {
172            inner.operation_name = f().into();
173        }
174    }
175
176    /// Sets the start time of this span.
177    pub fn set_start_time<F>(&mut self, f: F)
178    where
179        F: FnOnce() -> SystemTime,
180    {
181        if let Some(inner) = self.0.as_mut() {
182            inner.start_time = f();
183        }
184    }
185
186    /// Sets the finish time of this span.
187    pub fn set_finish_time<F>(&mut self, f: F)
188    where
189        F: FnOnce() -> SystemTime,
190    {
191        if let Some(inner) = self.0.as_mut() {
192            inner.finish_time = Some(f());
193        }
194    }
195
196    /// Sets the finish callback for this span.
197    pub fn set_finish_callback<C>(&mut self, cb: C)
198    where
199        C: Into<FinishSpanCallback<T>>,
200    {
201        if let Some(inner) = &mut self.0 {
202            inner.finish_cb = Some(cb.into());
203        }
204    }
205
206    /// Extracts any inherited or explicitly added finish callback from this span.
207    ///
208    /// This can be used either to unset the callback, by discarding the returned value,
209    /// or to wrap it in a new callback.
210    #[doc(alias = "remove_finish_callback")]
211    pub fn take_finish_callback(&mut self) -> Option<FinishSpanCallback<T>> {
212        self.0.as_mut().and_then(|s| s.finish_cb.take())
213    }
214
215    /// Discards this span, so it is never sent to the associated `SpanReceiver`.
216    ///
217    /// The finish callback, if any, is dropped without being called. Afterwards the span behaves
218    /// like an [inactive](Self::inactive) one.
219    ///
220    /// Children of this span that were already finished, and contexts propagated from it, keep
221    /// referencing this span, which will never be received.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use cf_rustracing::sampler::AllSampler;
227    /// use cf_rustracing::Tracer;
228    ///
229    /// let (tracer, mut span_rx) = Tracer::new(AllSampler);
230    /// let mut span = tracer.span("discarded").start_with_state(());
231    /// span.discard();
232    /// assert!(!span.is_sampled());
233    /// drop(span);
234    /// assert!(span_rx.try_recv().is_err());
235    /// ```
236    pub fn discard(&mut self) {
237        self.take_finish_callback();
238        self.0 = None;
239    }
240
241    /// Sets the tag to this span.
242    pub fn set_tag<F>(&mut self, f: F)
243    where
244        F: FnOnce() -> Tag,
245    {
246        use std::iter::once;
247        self.set_tags(|| once(f()));
248    }
249
250    /// Sets the tags to this span.
251    pub fn set_tags<F, I>(&mut self, f: F)
252    where
253        F: FnOnce() -> I,
254        I: IntoIterator<Item = Tag>,
255    {
256        if let Some(inner) = self.0.as_mut() {
257            for tag in f() {
258                inner.tags.retain(|x| x.name() != tag.name());
259                inner.tags.push(tag);
260            }
261        }
262    }
263
264    /// Sets the baggage item to this span.
265    pub fn set_baggage_item<F>(&mut self, f: F)
266    where
267        F: FnOnce() -> BaggageItem,
268    {
269        if let Some(inner) = self.0.as_mut() {
270            let item = f();
271            inner.context.baggage_items.retain(|x| x.name != item.name);
272            inner.context.baggage_items.push(item);
273        }
274    }
275
276    /// Gets the baggage item that has the name `name`.
277    pub fn get_baggage_item(&self, name: &str) -> Option<&BaggageItem> {
278        if let Some(inner) = self.0.as_ref() {
279            inner.context.baggage_items.iter().find(|x| x.name == name)
280        } else {
281            None
282        }
283    }
284
285    /// Logs structured data.
286    pub fn log<F>(&mut self, f: F)
287    where
288        F: FnOnce(&mut LogBuilder),
289    {
290        if let Some(inner) = self.0.as_mut() {
291            let mut builder = LogBuilder::new();
292            f(&mut builder);
293            if let Some(log) = builder.finish() {
294                inner.logs.push(log);
295            }
296        }
297    }
298
299    /// Logs an error.
300    ///
301    /// This is a simple wrapper of `log` method
302    /// except that the `StdTag::error()` tag will be set in this method.
303    pub fn error_log<F>(&mut self, f: F)
304    where
305        F: FnOnce(&mut StdErrorLogFieldsBuilder),
306    {
307        if let Some(inner) = self.0.as_mut() {
308            let mut builder = LogBuilder::new();
309            f(&mut builder.error());
310            if let Some(log) = builder.finish() {
311                inner.logs.push(log);
312            }
313            if !inner.tags.iter().any(|x| x.name() == "error") {
314                inner.tags.push(StdTag::error());
315            }
316        }
317    }
318
319    /// Starts a `ChildOf` span if this span is sampled.
320    ///
321    /// The child will inherit this span's finish callback and routing metadata,
322    /// if set. To avoid this kind of inheritance, you can use
323    /// `span.handle().child(...)` instead.
324    pub fn child<N, F>(&self, operation_name: N, f: F) -> Span<T>
325    where
326        N: Into<Cow<'static, str>>,
327        T: Clone,
328        F: FnOnce(StartSpanOptions<AllSampler, T>) -> Span<T>,
329    {
330        self.handle().child(operation_name, move |mut opts| {
331            if let Some(finish_cb) = self.0.as_ref().and_then(|s| s.finish_cb.clone()) {
332                opts = opts.finish_callback(finish_cb);
333            }
334            if let Some(routing) = self.0.as_ref().and_then(|s| s.routing.clone()) {
335                opts = opts.routing(routing);
336            }
337            f(opts)
338        })
339    }
340
341    /// Starts a `FollowsFrom` span if this span is sampled.
342    pub fn follower<N, F>(&self, operation_name: N, f: F) -> Span<T>
343    where
344        N: Into<Cow<'static, str>>,
345        T: Clone,
346        F: FnOnce(StartSpanOptions<AllSampler, T>) -> Span<T>,
347    {
348        self.handle().follower(operation_name, f)
349    }
350
351    pub(crate) fn new<S>(state: T, opts: StartSpanOptions<S, T>) -> Self {
352        let context = SpanContext::new(state, opts.baggage_items);
353        let inner = SpanInner {
354            operation_name: opts.operation_name,
355            start_time: opts.start_time.unwrap_or_else(SystemTime::now),
356            finish_time: None,
357            references: opts.references,
358            tags: opts.tags,
359            logs: Vec::new(),
360            context,
361            finish_cb: opts.finish_cb,
362            span_tx: opts.span_tx.clone(),
363            routing: opts.routing,
364        };
365        Span(Some(inner))
366    }
367}
368impl<T> Drop for Span<T> {
369    fn drop(&mut self) {
370        if let Some(finish_cb) = self.take_finish_callback() {
371            finish_cb.0(self);
372        }
373
374        if let Some(inner) = self.0.take() {
375            let finished = FinishedSpan {
376                operation_name: inner.operation_name,
377                start_time: inner.start_time,
378                finish_time: inner.finish_time.unwrap_or_else(SystemTime::now),
379                references: inner.references,
380                tags: inner.tags,
381                logs: inner.logs,
382                context: inner.context,
383                routing: inner.routing,
384            };
385            inner.span_tx.0.consume_span(finished);
386        }
387    }
388}
389impl<T> MaybeAsRef<SpanContext<T>> for Span<T> {
390    fn maybe_as_ref(&self) -> Option<&SpanContext<T>> {
391        self.context()
392    }
393}
394
395#[derive(Debug)]
396struct SpanInner<T> {
397    operation_name: Cow<'static, str>,
398    start_time: SystemTime,
399    finish_time: Option<SystemTime>,
400    references: Vec<SpanReference<T>>,
401    tags: Vec<Tag>,
402    logs: Vec<Log>,
403    context: SpanContext<T>,
404    finish_cb: Option<FinishSpanCallback<T>>,
405    span_tx: SharedSpanConsumer<T>,
406    routing: Option<Arc<dyn RoutingMetadata>>,
407}
408
409/// Finished span.
410#[derive(Debug)]
411pub struct FinishedSpan<T> {
412    operation_name: Cow<'static, str>,
413    start_time: SystemTime,
414    finish_time: SystemTime,
415    references: Vec<SpanReference<T>>,
416    tags: Vec<Tag>,
417    logs: Vec<Log>,
418    context: SpanContext<T>,
419    routing: Option<Arc<dyn RoutingMetadata>>,
420}
421impl<T> FinishedSpan<T> {
422    /// Returns the operation name of this span.
423    pub fn operation_name(&self) -> &str {
424        self.operation_name.as_ref()
425    }
426
427    /// Returns the start time of this span.
428    pub fn start_time(&self) -> SystemTime {
429        self.start_time
430    }
431
432    /// Returns the finish time of this span.
433    pub fn finish_time(&self) -> SystemTime {
434        self.finish_time
435    }
436
437    /// Returns the logs recorded during this span.
438    pub fn logs(&self) -> &[Log] {
439        &self.logs
440    }
441
442    /// Returns the tags of this span.
443    pub fn tags(&self) -> &[Tag] {
444        &self.tags
445    }
446
447    /// Returns the references of this span.
448    pub fn references(&self) -> &[SpanReference<T>] {
449        &self.references
450    }
451
452    /// Returns the context of this span.
453    pub fn context(&self) -> &SpanContext<T> {
454        &self.context
455    }
456
457    /// Returns the routing metadata of this span, if any was set.
458    pub fn routing(&self) -> Option<&dyn RoutingMetadata> {
459        self.routing.as_deref()
460    }
461}
462
463/// Span context.
464///
465/// Each `SpanContext` encapsulates the following state:
466///
467/// - `T`: OpenTracing-implementation-dependent state (for example, trace and span ids) needed to refer to a distinct `Span` across a process boundary
468/// - `BaggageItems`: These are just key:value pairs that cross process boundaries
469#[derive(Debug, Clone)]
470pub struct SpanContext<T> {
471    state: T,
472    baggage_items: Vec<BaggageItem>,
473}
474impl<T> SpanContext<T> {
475    /// Makes a new `SpanContext` instance.
476    pub fn new(state: T, mut baggage_items: Vec<BaggageItem>) -> Self {
477        baggage_items.reverse();
478        baggage_items.sort_by(|a, b| a.name().cmp(b.name()));
479        baggage_items.dedup_by(|a, b| a.name() == b.name());
480        SpanContext {
481            state,
482            baggage_items,
483        }
484    }
485
486    /// Returns the implementation-dependent state of this context.
487    pub fn state(&self) -> &T {
488        &self.state
489    }
490
491    /// Returns the baggage items associated with this context.
492    pub fn baggage_items(&self) -> &[BaggageItem] {
493        &self.baggage_items
494    }
495
496    /// Injects this context to the **Text Map** `carrier`.
497    pub fn inject_to_text_map<C>(&self, carrier: &mut C) -> Result<()>
498    where
499        C: carrier::TextMap,
500        T: carrier::InjectToTextMap<C>,
501    {
502        track!(T::inject_to_text_map(self, carrier))
503    }
504
505    /// Injects this context to the **HTTP Header** `carrier`.
506    pub fn inject_to_http_header<C>(&self, carrier: &mut C) -> Result<()>
507    where
508        C: carrier::SetHttpHeaderField,
509        T: carrier::InjectToHttpHeader<C>,
510    {
511        track!(T::inject_to_http_header(self, carrier))
512    }
513
514    /// Injects this context to the **Binary** `carrier`.
515    pub fn inject_to_binary<C>(&self, carrier: &mut C) -> Result<()>
516    where
517        C: Write,
518        T: carrier::InjectToBinary<C>,
519    {
520        track!(T::inject_to_binary(self, carrier))
521    }
522
523    /// Extracts a context from the **Text Map** `carrier`.
524    pub fn extract_from_text_map<C>(carrier: &C) -> Result<Option<Self>>
525    where
526        C: carrier::TextMap,
527        T: carrier::ExtractFromTextMap<C>,
528    {
529        track!(T::extract_from_text_map(carrier))
530    }
531
532    /// Extracts a context from the **HTTP Header** `carrier`.
533    pub fn extract_from_http_header<'a, C>(carrier: &'a C) -> Result<Option<Self>>
534    where
535        C: carrier::IterHttpHeaderFields<'a>,
536        T: carrier::ExtractFromHttpHeader<'a, C>,
537    {
538        track!(T::extract_from_http_header(carrier))
539    }
540
541    /// Extracts a context from the **Binary** `carrier`.
542    pub fn extract_from_binary<C>(carrier: &mut C) -> Result<Option<Self>>
543    where
544        C: Read,
545        T: carrier::ExtractFromBinary<C>,
546    {
547        track!(T::extract_from_binary(carrier))
548    }
549}
550impl<T> MaybeAsRef<SpanContext<T>> for SpanContext<T> {
551    fn maybe_as_ref(&self) -> Option<&Self> {
552        Some(self)
553    }
554}
555
556/// Baggage item.
557///
558/// `BaggageItem`s are key:value string pairs that apply to a `Span`, its `SpanContext`,
559/// and all `Span`s which directly or transitively reference the local `Span`.
560/// That is, `BaggageItem`s propagate in-band along with the trace itself.
561///
562/// `BaggageItem`s enable powerful functionality given a full-stack OpenTracing integration
563/// (for example, arbitrary application data from a mobile app can make it, transparently,
564/// all the way into the depths of a storage system),
565/// and with it some powerful costs: use this feature with care.
566///
567/// Use this feature thoughtfully and with care.
568/// Every key and value is copied into every local and remote child of the associated `Span`,
569/// and that can add up to a lot of network and cpu overhead.
570#[derive(Debug, Clone)]
571pub struct BaggageItem {
572    name: String,
573    value: String,
574}
575impl BaggageItem {
576    /// Makes a new `BaggageItem` instance.
577    pub fn new(name: &str, value: &str) -> Self {
578        BaggageItem {
579            name: name.to_owned(),
580            value: value.to_owned(),
581        }
582    }
583
584    /// Returns the name of this item.
585    pub fn name(&self) -> &str {
586        &self.name
587    }
588
589    /// Returns the value of this item.
590    pub fn value(&self) -> &str {
591        &self.value
592    }
593}
594
595/// Span reference.
596#[derive(Debug, Clone)]
597#[allow(missing_docs)]
598pub enum SpanReference<T> {
599    ChildOf(T),
600    FollowsFrom(T),
601}
602impl<T> SpanReference<T> {
603    /// Returns the span context state of this reference.
604    pub fn span(&self) -> &T {
605        match *self {
606            SpanReference::ChildOf(ref x) | SpanReference::FollowsFrom(ref x) => x,
607        }
608    }
609
610    /// Returns `true` if this is a `ChildOf` reference.
611    pub fn is_child_of(&self) -> bool {
612        matches!(*self, SpanReference::ChildOf(_))
613    }
614
615    /// Returns `true` if this is a `FollowsFrom` reference.
616    pub fn is_follows_from(&self) -> bool {
617        matches!(*self, SpanReference::FollowsFrom(_))
618    }
619}
620
621/// Candidate span for tracing.
622#[derive(Debug)]
623pub struct CandidateSpan<'a, T: 'a> {
624    tags: &'a [Tag],
625    references: &'a [SpanReference<T>],
626    baggage_items: &'a [BaggageItem],
627}
628impl<'a, T: 'a> CandidateSpan<'a, T> {
629    /// Returns the tags of this span.
630    pub fn tags(&self) -> &[Tag] {
631        self.tags
632    }
633
634    /// Returns the references of this span.
635    pub fn references(&self) -> &[SpanReference<T>] {
636        self.references
637    }
638
639    /// Returns the baggage items of this span.
640    pub fn baggage_items(&self) -> &[BaggageItem] {
641        self.baggage_items
642    }
643}
644
645/// Options for starting a span.
646#[derive(Debug)]
647pub struct StartSpanOptions<'a, S: 'a, T: 'a> {
648    operation_name: Cow<'static, str>,
649    start_time: Option<SystemTime>,
650    tags: Vec<Tag>,
651    references: Vec<SpanReference<T>>,
652    baggage_items: Vec<BaggageItem>,
653    finish_cb: Option<FinishSpanCallback<T>>,
654    routing: Option<Arc<dyn RoutingMetadata>>,
655    span_tx: &'a SharedSpanConsumer<T>,
656    sampler: &'a S,
657}
658impl<'a, S: 'a, T: 'a> StartSpanOptions<'a, S, T>
659where
660    S: Sampler<T>,
661{
662    /// Sets the start time of this span.
663    pub fn start_time(mut self, time: SystemTime) -> Self {
664        self.start_time = Some(time);
665        self
666    }
667
668    /// Sets the tag to this span.
669    pub fn tag(mut self, tag: Tag) -> Self {
670        self.tags.push(tag);
671        self
672    }
673
674    /// Sets the finish callback for this span.
675    pub fn finish_callback<C>(mut self, cb: C) -> Self
676    where
677        C: Into<FinishSpanCallback<T>>,
678    {
679        self.finish_cb = Some(cb.into());
680        self
681    }
682
683    /// Attaches routing metadata to the span being built.
684    ///
685    /// The metadata is carried into the resulting [`FinishedSpan`] for the
686    /// exporter to read, and is inherited by child spans (see [`Span::child`]).
687    /// This is the only way to set routing — there is no live setter, so routing
688    /// cannot be changed or cleared after the span has started.
689    pub fn routing(mut self, routing: Arc<dyn RoutingMetadata>) -> Self {
690        self.routing = Some(routing);
691        self
692    }
693
694    /// Adds the `ChildOf` reference to this span.
695    pub fn child_of<C>(mut self, context: &C) -> Self
696    where
697        C: MaybeAsRef<SpanContext<T>>,
698        T: Clone,
699    {
700        if let Some(context) = context.maybe_as_ref() {
701            let reference = SpanReference::ChildOf(context.state().clone());
702            self.references.push(reference);
703            self.baggage_items
704                .extend(context.baggage_items().iter().cloned());
705        }
706        self
707    }
708
709    /// Adds the `FollowsFrom` reference to this span.
710    pub fn follows_from<C>(mut self, context: &C) -> Self
711    where
712        C: MaybeAsRef<SpanContext<T>>,
713        T: Clone,
714    {
715        if let Some(context) = context.maybe_as_ref() {
716            let reference = SpanReference::FollowsFrom(context.state().clone());
717            self.references.push(reference);
718            self.baggage_items
719                .extend(context.baggage_items().iter().cloned());
720        }
721        self
722    }
723
724    /// Starts a new span.
725    pub fn start(mut self) -> Span<T>
726    where
727        T: for<'b> From<CandidateSpan<'b, T>>,
728    {
729        self.normalize();
730        if !self.is_sampled() {
731            return Span(None);
732        }
733        let state = T::from(self.span());
734        Span::new(state, self)
735    }
736
737    /// Starts a new span with the explicit `state`.
738    pub fn start_with_state(mut self, state: T) -> Span<T> {
739        self.normalize();
740        if !self.is_sampled() {
741            return Span(None);
742        }
743        Span::new(state, self)
744    }
745
746    pub(crate) fn new<N>(
747        operation_name: N,
748        span_tx: &'a SharedSpanConsumer<T>,
749        sampler: &'a S,
750    ) -> Self
751    where
752        N: Into<Cow<'static, str>>,
753    {
754        StartSpanOptions {
755            operation_name: operation_name.into(),
756            start_time: None,
757            tags: Vec::new(),
758            references: Vec::new(),
759            baggage_items: Vec::new(),
760            finish_cb: None,
761            routing: None,
762            span_tx,
763            sampler,
764        }
765    }
766
767    fn normalize(&mut self) {
768        self.tags.reverse();
769        self.tags.sort_by(|a, b| a.name().cmp(b.name()));
770        self.tags.dedup_by(|a, b| a.name() == b.name());
771
772        self.baggage_items.reverse();
773        self.baggage_items.sort_by(|a, b| a.name().cmp(b.name()));
774        self.baggage_items.dedup_by(|a, b| a.name() == b.name());
775    }
776
777    fn span(&self) -> CandidateSpan<'_, T> {
778        CandidateSpan {
779            references: &self.references,
780            tags: &self.tags,
781            baggage_items: &self.baggage_items,
782        }
783    }
784
785    fn is_sampled(&self) -> bool {
786        if let Some(&TagValue::Integer(n)) = self
787            .tags
788            .iter()
789            .find(|t| t.name() == "sampling.priority")
790            .map(|t| t.value())
791        {
792            n > 0
793        } else {
794            self.sampler.is_sampled(&self.span())
795        }
796    }
797}
798
799/// Immutable handle of `Span`.
800#[derive(Debug, Clone)]
801pub struct SpanHandle<T>(Option<(SpanContext<T>, SharedSpanConsumer<T>)>);
802impl<T> SpanHandle<T> {
803    /// Returns `true` if this span is sampled (i.e., being traced).
804    pub fn is_sampled(&self) -> bool {
805        self.0.is_some()
806    }
807
808    /// Returns the context of this span.
809    pub fn context(&self) -> Option<&SpanContext<T>> {
810        self.0.as_ref().map(|(context, _)| context)
811    }
812
813    /// Gets the baggage item that has the name `name`.
814    pub fn get_baggage_item(&self, name: &str) -> Option<&BaggageItem> {
815        if let Some(context) = self.context() {
816            context.baggage_items.iter().find(|x| x.name == name)
817        } else {
818            None
819        }
820    }
821
822    /// Starts a `ChildOf` span if this span is sampled.
823    pub fn child<N, F>(&self, operation_name: N, f: F) -> Span<T>
824    where
825        N: Into<Cow<'static, str>>,
826        T: Clone,
827        F: FnOnce(StartSpanOptions<AllSampler, T>) -> Span<T>,
828    {
829        if let Some((context, span_tx)) = self.0.as_ref() {
830            let options =
831                StartSpanOptions::new(operation_name, span_tx, &AllSampler).child_of(context);
832            f(options)
833        } else {
834            Span::inactive()
835        }
836    }
837
838    /// Starts a `FollowsFrom` span if this span is sampled.
839    pub fn follower<N, F>(&self, operation_name: N, f: F) -> Span<T>
840    where
841        N: Into<Cow<'static, str>>,
842        T: Clone,
843        F: FnOnce(StartSpanOptions<AllSampler, T>) -> Span<T>,
844    {
845        if let Some((context, span_tx)) = self.0.as_ref() {
846            let options =
847                StartSpanOptions::new(operation_name, span_tx, &AllSampler).follows_from(context);
848            f(options)
849        } else {
850            Span::inactive()
851        }
852    }
853}
854
855/// Extension trait for inspecting an in-progress `Span`.
856pub trait InspectableSpan<T> {
857    /// Returns the operation name of this span.
858    fn operation_name(&self) -> &str;
859
860    /// Returns the start time of this span.
861    fn start_time(&self) -> SystemTime;
862
863    /// Returns the finish time of this span, if it has finished.
864    fn finish_time(&self) -> Option<SystemTime>;
865
866    /// Returns the logs recorded during this span.
867    fn logs(&self) -> &[Log];
868
869    /// Returns the tags of this span.
870    fn tags(&self) -> &[Tag];
871
872    /// Returns the references of this span.
873    fn references(&self) -> &[SpanReference<T>];
874}
875
876impl<T> InspectableSpan<T> for Span<T> {
877    /// Returns the operation name of this span.
878    fn operation_name(&self) -> &str {
879        self.0
880            .as_ref()
881            .map(|inner| inner.operation_name.as_ref())
882            .unwrap_or("")
883    }
884
885    /// Returns the start time of this span.
886    fn start_time(&self) -> SystemTime {
887        self.0
888            .as_ref()
889            .map(|inner| inner.start_time)
890            .unwrap_or_else(SystemTime::now)
891    }
892
893    /// Returns the finish time of this span.
894    fn finish_time(&self) -> Option<SystemTime> {
895        self.0.as_ref().and_then(|inner| inner.finish_time)
896    }
897
898    /// Returns the logs recorded during this span.
899    fn logs(&self) -> &[Log] {
900        self.0
901            .as_ref()
902            .map(|inner| inner.logs.as_ref())
903            .unwrap_or(&[])
904    }
905
906    /// Returns the tags of this span.
907    fn tags(&self) -> &[Tag] {
908        self.0
909            .as_ref()
910            .map(|inner| inner.tags.as_ref())
911            .unwrap_or(&[])
912    }
913
914    /// Returns the references of this span.
915    fn references(&self) -> &[SpanReference<T>] {
916        self.0
917            .as_ref()
918            .map(|inner| inner.references.as_ref())
919            .unwrap_or(&[])
920    }
921}