1use 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
15pub trait SpanConsumer<T>: Send + Sync {
17 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
48pub type SpanReceiver<T> = mpsc::UnboundedReceiver<FinishedSpan<T>>;
50#[deprecated = "SpanSender is an implementation detail of rustracing. It should not be public."]
52pub type SpanSender<T> = mpsc::UnboundedSender<FinishedSpan<T>>;
53
54pub(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
75pub 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
109pub trait RoutingMetadata: fmt::Debug + Send + Sync {
112 fn group_key(&self) -> String;
115
116 fn encode(&self) -> String;
118}
119
120#[derive(Debug)]
125pub struct Span<T>(Option<SpanInner<T>>);
126impl<T> Span<T> {
127 pub const fn inactive() -> Self {
140 Span(None)
141 }
142
143 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 pub fn is_sampled(&self) -> bool {
157 self.0.is_some()
158 }
159
160 pub fn context(&self) -> Option<&SpanContext<T>> {
162 self.0.as_ref().map(|x| &x.context)
163 }
164
165 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 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 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 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 #[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 pub fn discard(&mut self) {
237 self.take_finish_callback();
238 self.0 = None;
239 }
240
241 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 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 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 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 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 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 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 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#[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 pub fn operation_name(&self) -> &str {
424 self.operation_name.as_ref()
425 }
426
427 pub fn start_time(&self) -> SystemTime {
429 self.start_time
430 }
431
432 pub fn finish_time(&self) -> SystemTime {
434 self.finish_time
435 }
436
437 pub fn logs(&self) -> &[Log] {
439 &self.logs
440 }
441
442 pub fn tags(&self) -> &[Tag] {
444 &self.tags
445 }
446
447 pub fn references(&self) -> &[SpanReference<T>] {
449 &self.references
450 }
451
452 pub fn context(&self) -> &SpanContext<T> {
454 &self.context
455 }
456
457 pub fn routing(&self) -> Option<&dyn RoutingMetadata> {
459 self.routing.as_deref()
460 }
461}
462
463#[derive(Debug, Clone)]
470pub struct SpanContext<T> {
471 state: T,
472 baggage_items: Vec<BaggageItem>,
473}
474impl<T> SpanContext<T> {
475 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 pub fn state(&self) -> &T {
488 &self.state
489 }
490
491 pub fn baggage_items(&self) -> &[BaggageItem] {
493 &self.baggage_items
494 }
495
496 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 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 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 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 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 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#[derive(Debug, Clone)]
571pub struct BaggageItem {
572 name: String,
573 value: String,
574}
575impl BaggageItem {
576 pub fn new(name: &str, value: &str) -> Self {
578 BaggageItem {
579 name: name.to_owned(),
580 value: value.to_owned(),
581 }
582 }
583
584 pub fn name(&self) -> &str {
586 &self.name
587 }
588
589 pub fn value(&self) -> &str {
591 &self.value
592 }
593}
594
595#[derive(Debug, Clone)]
597#[allow(missing_docs)]
598pub enum SpanReference<T> {
599 ChildOf(T),
600 FollowsFrom(T),
601}
602impl<T> SpanReference<T> {
603 pub fn span(&self) -> &T {
605 match *self {
606 SpanReference::ChildOf(ref x) | SpanReference::FollowsFrom(ref x) => x,
607 }
608 }
609
610 pub fn is_child_of(&self) -> bool {
612 matches!(*self, SpanReference::ChildOf(_))
613 }
614
615 pub fn is_follows_from(&self) -> bool {
617 matches!(*self, SpanReference::FollowsFrom(_))
618 }
619}
620
621#[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 pub fn tags(&self) -> &[Tag] {
631 self.tags
632 }
633
634 pub fn references(&self) -> &[SpanReference<T>] {
636 self.references
637 }
638
639 pub fn baggage_items(&self) -> &[BaggageItem] {
641 self.baggage_items
642 }
643}
644
645#[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 pub fn start_time(mut self, time: SystemTime) -> Self {
664 self.start_time = Some(time);
665 self
666 }
667
668 pub fn tag(mut self, tag: Tag) -> Self {
670 self.tags.push(tag);
671 self
672 }
673
674 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 pub fn routing(mut self, routing: Arc<dyn RoutingMetadata>) -> Self {
690 self.routing = Some(routing);
691 self
692 }
693
694 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 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 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 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#[derive(Debug, Clone)]
801pub struct SpanHandle<T>(Option<(SpanContext<T>, SharedSpanConsumer<T>)>);
802impl<T> SpanHandle<T> {
803 pub fn is_sampled(&self) -> bool {
805 self.0.is_some()
806 }
807
808 pub fn context(&self) -> Option<&SpanContext<T>> {
810 self.0.as_ref().map(|(context, _)| context)
811 }
812
813 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 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 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
855pub trait InspectableSpan<T> {
857 fn operation_name(&self) -> &str;
859
860 fn start_time(&self) -> SystemTime;
862
863 fn finish_time(&self) -> Option<SystemTime>;
865
866 fn logs(&self) -> &[Log];
868
869 fn tags(&self) -> &[Tag];
871
872 fn references(&self) -> &[SpanReference<T>];
874}
875
876impl<T> InspectableSpan<T> for Span<T> {
877 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 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 fn finish_time(&self) -> Option<SystemTime> {
895 self.0.as_ref().and_then(|inner| inner.finish_time)
896 }
897
898 fn logs(&self) -> &[Log] {
900 self.0
901 .as_ref()
902 .map(|inner| inner.logs.as_ref())
903 .unwrap_or(&[])
904 }
905
906 fn tags(&self) -> &[Tag] {
908 self.0
909 .as_ref()
910 .map(|inner| inner.tags.as_ref())
911 .unwrap_or(&[])
912 }
913
914 fn references(&self) -> &[SpanReference<T>] {
916 self.0
917 .as_ref()
918 .map(|inner| inner.references.as_ref())
919 .unwrap_or(&[])
920 }
921}