1use std::borrow::Cow;
2use std::collections::BTreeMap;
3use std::num::NonZeroU32;
4use std::sync::Arc;
5use std::num::{NonZeroU128, NonZeroU64};
6use crate::sampling::{DynamicTraceDetail, SamplingDecision, SamplingResult};
7use crate::{AttributeValue, Severity};
8
9#[derive(Debug, Clone, Copy)]
10pub struct NoTracerRegistered;
11
12impl std::fmt::Display for NoTracerRegistered {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 f.write_str("operation requires tracer, but no tracer was registered")
15 }
16}
17
18impl std::error::Error for NoTracerRegistered {}
19
20#[derive(Debug, Clone, Copy)]
21pub struct NoCurrentSpan;
22
23impl std::fmt::Display for NoCurrentSpan {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.write_str("operation requires span, but no span has been opened in this context")
26 }
27}
28
29impl std::error::Error for NoCurrentSpan {}
30
31#[derive(Debug)]
45pub struct PrivateMarker(());
46
47#[derive(Debug, Clone, Copy)]
51pub enum Text<'a> {
52 Static(&'static str),
53 Borrowed(&'a str),
54 FormatArgs(std::fmt::Arguments<'a>)
55}
56
57impl<'a> Text<'a> {
58 pub fn as_str(&self) -> Option<&'a str> {
59 match self {
60 Text::Static(s) => Some(s),
61 Text::Borrowed(s) => Some(s),
62 Text::FormatArgs(_) => None,
63 }
64 }
65}
66
67impl From<&'static str> for Text<'static> {
68 fn from(s: &'static str) -> Self { Self::Static(s) }
69}
70
71impl<'a> From<std::fmt::Arguments<'a>> for Text<'a> {
72 fn from(a: std::fmt::Arguments<'a>) -> Self { Self::FormatArgs(a) }
73}
74
75impl<'a> std::fmt::Display for Text<'a> {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 Text::Static(x) => x.fmt(f),
79 Text::Borrowed(x) => x.fmt(f),
80 Text::FormatArgs(x) => x.fmt(f),
81 }
82 }
83}
84
85pub type BaggageKey = Cow<'static, str>;
88pub type BaggageValue = Cow<'static, str>;
89pub type BaggageMap = BTreeMap<BaggageKey, BaggageValue>;
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
95pub struct TraceId(pub NonZeroU128);
96
97impl std::fmt::Display for TraceId {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 write!(f, "{:032x}", self.0.get())
100 }
101}
102
103impl std::str::FromStr for TraceId {
104 type Err = &'static str;
105 fn from_str(hex: &str) -> Result<Self, Self::Err> {
106 let mut bytes = [0; 16];
107 if hex.len() != bytes.len() * 2 {
108 return Err("trace-id string has wrong length")
109 }
110 for (i, byte) in bytes.iter_mut().enumerate() {
111 *byte = match u8::from_str_radix(&hex[i * 2..i * 2 + 2], 16) {
112 Ok(b) => b,
113 Err(_) => return Err("trace-id string contains non-hex letters")
114 }
115 }
116 let int = u128::from_be_bytes(bytes);
117 NonZeroU128::new(int).map(Self).ok_or("trace-id string has no non-zero bytes")
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
122pub struct SpanId(pub NonZeroU64);
123
124impl std::fmt::Display for SpanId {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 write!(f, "{:016x}", self.0.get())
127 }
128}
129
130impl std::str::FromStr for SpanId {
131 type Err = &'static str;
132 fn from_str(hex: &str) -> Result<Self, Self::Err> {
133 let mut bytes = [0; 8];
134 if hex.len() != bytes.len() * 2 {
135 return Err("span-id string has wrong length")
136 }
137 for (i, byte) in bytes.iter_mut().enumerate() {
138 *byte = match u8::from_str_radix(&hex[i * 2..i * 2 + 2], 16) {
139 Ok(b) => b,
140 Err(_) => return Err("span-id string contains non-hex letters")
141 }
142 }
143 let int = u64::from_be_bytes(bytes);
144 NonZeroU64::new(int).map(Self).ok_or("span-id string has no non-zero bytes")
145 }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
151pub struct SpanContext {
152 pub trace_id: TraceId,
153 pub span_id: SpanId,
154 pub trace_flags: u8,
155}
156
157impl SpanContext {
158 pub fn sampled(&self) -> bool {
159 self.trace_flags & 0 != 0
160 }
161}
162
163impl std::fmt::Display for SpanContext {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 write!(f, "00-{}-{}-{:02x}", self.trace_id, self.span_id, self.trace_flags)
166 }
167}
168
169impl std::str::FromStr for SpanContext {
170 type Err = &'static str;
171
172 fn from_str(header: &str) -> Result<Self, Self::Err> {
173 let mut parts = header.split('-');
174
175 let Some(version) = parts.next() else { return Err("missing '-' delimiters") };
176 if version != "00" { return Err("unsupported version") }
177
178 let Some(trace_id_hex) = parts.next() else { return Err("missing trace-id field") };
179 let Some(span_id_hex) = parts.next() else { return Err("missing parent-id field") };
180 let Some(trace_flags_hex) = parts.next() else { return Err("missing trace-flags field") };
181
182 let trace_id = TraceId::from_str(trace_id_hex)?;
183 let span_id = SpanId::from_str(span_id_hex)?;
184
185 if trace_flags_hex.len() != 2 { return Err("trace-flags string has wrong length")}
186 let trace_flags = u8::from_str_radix(trace_flags_hex, 16)
187 .map_err(|_| "trace-flags string contains non-hex letters")?;
188
189 Ok(Self { trace_id, span_id, trace_flags })
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
197pub struct SpanCollectionIndex(pub NonZeroU32, pub u32);
198
199#[derive(Default, Clone)]
200pub struct TracingContext {
201 pub baggage: BaggageMap,
202 pub on_start: Option<Arc<dyn Fn(&SpanRef) + Send + Sync>>,
203 pub on_ending: Option<Arc<dyn Fn(&SpanRef) + Send + Sync>>,
204}
205
206#[derive(Debug, Clone, Copy)]
207pub struct RecordingSpanContext {
208 pub span_context: SpanContext,
209 pub collect_idx: SpanCollectionIndex,
210}
211
212#[derive(Default, Clone)]
213pub struct SpanRef {
214 span_context: Option<SpanContext>,
215 collect_idx: Option<SpanCollectionIndex>,
216 references_ancestor: bool,
217 dyn_trace_detail: Option<DynamicTraceDetail>,
218 tracing_context: Option<Arc<TracingContext>>,
219}
220
221impl SpanRef {
222 pub fn disabled() -> Self { Self::default() }
223
224 pub fn remote(span_context: SpanContext) -> Self {
225 Self{ span_context: Some(span_context), ..Self::disabled() }
226 }
227
228 #[doc(hidden)]
229 pub fn recording(span_context: RecordingSpanContext) -> Self {
230 Self{ collect_idx: Some(span_context.collect_idx), ..Self::remote(span_context.span_context) }
231 }
232
233 pub fn as_ancestor(&self) -> Self {
234 let mut this = self.clone();
235 this.references_ancestor = true;
236 this
237 }
238
239 pub fn as_recording_self_or_ancestor(&self) -> Option<RecordingSpanContext> {
240 Some(RecordingSpanContext{ span_context: self.span_context?, collect_idx: self.collect_idx? })
241 }
242 pub fn as_recording_self(&self) -> Option<RecordingSpanContext> {
243 if self.references_ancestor { None } else { self.as_recording_self_or_ancestor() }
244 }
245
246 pub fn is_recording_self_or_ancestor(&self) -> bool {
247 self.collect_idx.is_some()
248 }
249 pub fn is_recording_self(&self) -> bool {
250 !self.references_ancestor && self.collect_idx.is_some()
251 }
252 pub fn span_context(&self) -> Option<SpanContext> {
253 self.span_context
254 }
255 pub fn tracing_context(&self) -> Option<&Arc<TracingContext>> {
256 self.tracing_context.as_ref()
257 }
258
259 }
278
279#[derive(Debug, Clone, Copy)]
282pub struct AttributeList<'a>(pub &'a [(Text<'a>, AttributeValue<'a>)]);
283
284impl<'a> AttributeList<'a> {
285 pub fn get(&self, key: &str) -> Option<AttributeValue<'a>> {
286 self.0.iter()
287 .find(|(k, _)| k.as_str() == Some(key))
288 .map(|(_, v)| *v)
289 }
290}
291
292#[derive(Debug, Clone)]
293pub enum SpanStatus<'a> {
294 Ok,
295 Error(Text<'a>),
296}
297
298impl<'a> SpanStatus<'a> {
299 pub fn error(s: impl Into<Text<'a>>) -> Self {
300 Self::Error(s.into())
301 }
302}
303
304#[derive(Debug, Clone, Copy, PartialEq, Eq)]
305pub enum SpanKind {
306 Internal,
307 Client,
308 Server,
309 Producer,
310 Consumer,
311}
312
313#[non_exhaustive]
314#[derive(Debug)]
315pub struct SpanArgs<'a> {
316 pub name: Text<'a>,
317 pub target: Option<&'static str>,
318 pub severity: Option<Severity>,
319
320 pub parent: Option<SpanContext>,
321 pub status: Option<SpanStatus<'a>>,
322 pub kind: Option<SpanKind>,
323
324 pub attributes: AttributeList<'a>,
325
326 _private: PrivateMarker,
327}
328
329pub struct SpanBuilder<'a> {
330 args: SpanArgs<'a>,
331 parent: Option<Option<&'a SpanRef>>,
332 on_start: Option<Arc<dyn Fn(&SpanRef) + Send + Sync>>,
333 on_ending: Option<Arc<dyn Fn(&SpanRef) + Send + Sync>>,
334 baggage_entries: Vec<(BaggageKey, BaggageValue)>,
335}
336
337impl<'a> SpanBuilder<'a> {
338 pub fn new(name: impl Into<Text<'a>>, target: Option<&'static str>, severity: Option<Severity>) -> Self {
339 let name = name.into();
340 Self{
341 args: SpanArgs{
342 name,
343 target,
344 severity,
345 parent: None,
346 kind: None,
347 status: None,
348 attributes: AttributeList(&[]),
349 _private: PrivateMarker(()),
350 },
351 parent: None,
352 on_start: None,
353 on_ending: None,
354 baggage_entries: vec![],
355 }
356 }
357
358 pub fn no_parent(self) -> Self {
359 Self{ parent: Some(None), ..self }
360 }
361 pub fn parent<'b>(self, parent: &'b SpanRef) -> SpanBuilder<'b>
362 where 'a: 'b
363 {
364 SpanBuilder{ parent: Some(Some(parent)), ..self }
365 }
366 pub fn name<'b>(self, name: impl Into<Text<'b>>) -> SpanBuilder<'b>
367 where 'a: 'b
368 {
369 SpanBuilder{ args: SpanArgs{ name: name.into(), ..self.args }, ..self }
370 }
371 pub fn status<'b>(self, status: SpanStatus<'a>) -> SpanBuilder<'b>
372 where 'a: 'b
373 {
374 SpanBuilder{ args: SpanArgs{ status: Some(status), ..self.args }, ..self }
375 }
376 pub fn kind(self, kind: SpanKind) -> Self {
377 Self{ args: SpanArgs{ kind: Some(kind), ..self.args }, ..self }
378 }
379
380 pub fn on_start(self, f: impl Fn(&SpanRef) + Send + Sync + 'static) -> Self {
381 Self{ on_start: Some(Arc::new(f)), ..self }
382 }
383 pub fn on_ending(self, f: impl Fn(&SpanRef) + Send + Sync + 'static) -> Self {
384 Self{ on_ending: Some(Arc::new(f)), ..self }
385 }
386 pub fn baggage_entry(mut self, key: impl Into<BaggageKey>, value: impl Into<BaggageValue>) -> Self {
387 self.baggage_entries.push((key.into(), value.into()));
388 self
389 }
390
391 fn _start<'b>(mut self, tracer: &dyn Tracer, parent: Option<&SpanRef>, attributes: AttributeList<'b>) -> OwnedSpanRef {
392 if let Some(parent) = parent {
393 match (parent.dyn_trace_detail, self.args.severity) {
394 (Some(min), Some(sev)) if sev < min.recording_level => {
395 return OwnedSpanRef(SpanRef{ references_ancestor: true, ..parent.clone() })
396 }
397 _ => {}
398 }
399
400 self.args.parent = parent.span_context;
402 }
403
404 if self.args.status.is_none() && self.args.severity >= Some(Severity::Error) {
406 self.args.status = Some(SpanStatus::error(self.args.name))
407 }
408
409 let mut new_span = match tracer.start_span(SpanArgs{ attributes, ..self.args }, &mut PrivateMarker(())) {
411 Some((new_span, sampling)) => {
412 debug_assert_ne!(sampling.decision, SamplingDecision::Drop);
413 let dyn_trace_detail = sampling.dyn_trace_detail.or(parent.as_ref().and_then(|p| p.dyn_trace_detail));
414 SpanRef{ dyn_trace_detail, ..SpanRef::recording(new_span) }
415 }
416 None => match parent {
417 Some(parent) => SpanRef{ references_ancestor: true, ..parent.clone() },
418 None => SpanRef::disabled()
419 }
420 };
421
422 if self.on_start.is_some() || self.on_ending.is_some() || !self.baggage_entries.is_empty() {
424 let mut tracing_ctx = new_span.tracing_context.as_ref()
425 .map(|t| (**t).clone())
426 .unwrap_or_default();
427 tracing_ctx.on_start = self.on_start.or(tracing_ctx.on_start);
428 tracing_ctx.on_ending = self.on_ending.or(tracing_ctx.on_ending);
429 tracing_ctx.baggage.extend(self.baggage_entries);
430 new_span.tracing_context = Some(Arc::new(tracing_ctx));
431 } else {
432 new_span.tracing_context = parent.as_ref().and_then(|p| p.tracing_context.clone());
433 }
434
435 if let Some(on_start) = new_span.tracing_context.as_ref().and_then(|t| t.on_start.as_ref()) {
437 on_start(&new_span);
438 }
439
440 OwnedSpanRef(new_span)
441 }
442
443 #[doc(hidden)]
444 pub fn start<'b>(mut self, tracer: &dyn Tracer, attributes: AttributeList<'b>) -> OwnedSpanRef {
445 match self.parent.take() {
446 Some(parent) => self._start(tracer, parent, attributes),
447 None => {
448 let mut this = Some(self);
449 globals::current_span(|parent| this.take().unwrap()._start(tracer, Some(parent), attributes))
450 .unwrap_or_else(|_| this.take().unwrap()._start(tracer, None, attributes))
451 }
452 }
453 }
454}
455
456pub struct DisabledSpanBuilder<'a> {
458 parent: Option<Option<&'a SpanRef>>,
459}
460
461impl<'a> DisabledSpanBuilder<'a> {
462 pub fn new() -> DisabledSpanBuilder<'static> { DisabledSpanBuilder{ parent: None } }
463
464 pub fn no_parent(self) -> Self {
465 DisabledSpanBuilder{ parent: Some(None) }
466 }
467 pub fn parent<'b>(self, parent: &'b SpanRef) -> DisabledSpanBuilder<'b>
468 where 'a: 'b
469 {
470 DisabledSpanBuilder{ parent: Some(Some(parent)) }
471 }
472
473 pub fn name<'b>(self, _name: impl Into<Text<'b>>) -> Self { self }
474 pub fn status(self, _status: SpanStatus) -> Self { self }
475 pub fn kind(self, _kind: SpanKind) -> Self { self }
476 pub fn on_start(self, _f: impl Fn(&SpanRef) + Send + Sync + 'static) -> Self { self }
477 pub fn on_ending(self, _f: impl Fn(&SpanRef) + Send + Sync + 'static) -> Self { self }
478 pub fn baggage_entry(self, _key: impl Into<BaggageKey>, _value: impl Into<BaggageValue>) -> Self { self }
479
480 fn _start(_tracer: &dyn Tracer, parent: Option<&SpanRef>) -> Option<OwnedSpanRef> {
481 if let Some(parent) = parent {
482 if parent.references_ancestor {
483 None
484 } else {
485 Some(OwnedSpanRef(SpanRef{ references_ancestor: true, ..parent.clone() }))
486 }
487 } else {
488 Some(OwnedSpanRef(SpanRef::disabled()))
489 }
490 }
491
492 #[doc(hidden)]
493 pub fn start<'b>(mut self, tracer: &dyn Tracer) -> Option<OwnedSpanRef> {
494 match self.parent.take() {
495 Some(parent) => Self::_start(tracer, parent),
496 None => {
497 globals::current_span(|parent| Self::_start(tracer, Some(parent)))
498 .unwrap_or_else(|_| Self::_start(tracer, None))
499 }
500 }
501 }
502}
503
504#[non_exhaustive]
507#[derive(Debug)]
508pub enum Exception<'a> {
509 Error{
510 object: &'a (dyn std::error::Error + 'a),
511 type_name: &'static str
512 },
513 Dbgfmt{
514 object: &'a (dyn std::fmt::Debug + 'a),
515 type_name: &'static str
516 }
517}
518
519#[non_exhaustive]
520#[derive(Debug)]
521pub struct EventArgs<'a> {
522 pub name: Text<'a>,
524 pub target: Option<&'a str>,
525 pub severity: Option<Severity>,
526 pub exception: Option<Exception<'a>>,
527 pub attributes: AttributeList<'a>,
528 _private: PrivateMarker,
529}
530
531pub struct EventBuilder<'a>(EventArgs<'a>);
532
533impl<'a> EventBuilder<'a> {
534 pub fn new(name: impl Into<Text<'a>>, target: Option<&'a str>, severity: Option<Severity>) -> Self {
535 Self(EventArgs{
536 name: name.into(),
537 target,
538 severity,
539 exception: None,
540 attributes: AttributeList(&[]),
541 _private: PrivateMarker(()),
542 })
543 }
544
545 pub fn exception<'b>(self, object: &'b (impl std::error::Error + 'b)) -> EventBuilder<'b>
546 where 'a: 'b
547 {
548 let type_name = std::any::type_name_of_val(object);
549 EventBuilder(EventArgs{ exception: Some(Exception::Error{ object, type_name }), ..self.0 })
550 }
551
552 pub fn exception_dbgfmt<'b>(self, object: &'b (impl std::fmt::Debug + 'b)) -> EventBuilder<'b>
553 where 'a: 'b
554 {
555 let type_name = std::any::type_name_of_val(object);
556 EventBuilder(EventArgs{ exception: Some(Exception::Dbgfmt{ object, type_name }), ..self.0 })
557 }
558
559 #[doc(hidden)]
560 pub fn add_to_span<'b>(self, tracer: &dyn Tracer, span: &OwnedSpanRef, attributes: AttributeList<'b>){
561 match (span.dyn_trace_detail, self.0.severity) {
562 (Some(min), Some(sev)) if sev < min.recording_level => {
563 return }
565 _ => {}
566 }
567
568 let Some(recording) = span.as_recording_self_or_ancestor() else {
569 if self.0.severity >= Some(Severity::Error) {
570 let err = InstrumentationError::FailedErrorEventEscalation(span, self.0);
571 tracer.instrumentation_error(err);
572 }
573 return
574 };
575
576 if self.0.severity >= Some(Severity::Error) {
578 tracer.set_status(recording, SpanStatus::Error(self.0.name));
579 }
580
581 tracer.add_event(recording, EventArgs{ attributes, ..self.0 }, &mut PrivateMarker(()));
583 }
584
585 #[doc(hidden)]
586 pub fn add_to_current_span<'b>(self, tracer: &dyn Tracer, attributes: AttributeList<'b>){
587 let mut this = Some(self);
588 globals::current_span(|span| {
589 let this = this.take().unwrap();
590 this.add_to_span(tracer, span, attributes);
591 }).unwrap_or_else(|_| {
592 let this = this.take().unwrap();
593 tracer.instrumentation_error(InstrumentationError::StrayEvent(this.0));
594 });
595 }
596
597
598}
599
600#[non_exhaustive]
603pub enum InstrumentationError<'a> {
604 StrayAttributes(AttributeList<'a>),
605 StrayEvent(EventArgs<'a>),
606 StrayStatus(SpanStatus<'a>),
607 FailedErrorEventEscalation(&'a SpanRef, EventArgs<'a>),
608}
609
610impl<'a> std::fmt::Display for InstrumentationError<'a> {
611 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
612 match self {
613 Self::StrayAttributes(attr) => write!(f, "stray attributes without target span: {:?}", attr),
614 Self::StrayEvent(event_args) => write!(f, "stray event without target span: {:?}", event_args),
615 Self::StrayStatus(span_status) => write!(f, "stray span status without target span: {:?}", span_status),
616 Self::FailedErrorEventEscalation(_span, event_args) => write!(f, "event has escalating severity without any root span: {:?}", event_args),
618 }
619 }
620}
621
622pub trait Tracer: Send + Sync + 'static {
623 fn is_enabled(&self, target: Option<&'static str>, severity: Option<Severity>) -> bool;
624
625 fn start_span(&self, args: SpanArgs, _: &mut PrivateMarker) -> Option<(RecordingSpanContext, SamplingResult)>;
626 fn set_attributes(&self, span: RecordingSpanContext, attrs: AttributeList);
627 fn add_event(&self, span: RecordingSpanContext, args: EventArgs, _: &mut PrivateMarker);
628 fn set_status(&self, span: RecordingSpanContext, status: SpanStatus);
629 fn drop_span(&self, span: RecordingSpanContext, _: &mut PrivateMarker);
630 fn flush(&self);
631
632 fn instrumentation_error(&self, err: InstrumentationError);
633}
634
635pub struct OwnedSpanRef(SpanRef);
636
637impl std::ops::Deref for OwnedSpanRef {
638 type Target = SpanRef;
639 fn deref(&self) -> &Self::Target { &self.0 }
640}
641
642impl Drop for OwnedSpanRef {
643 fn drop(&mut self) {
644 if let Some(recording) = self.0.as_recording_self() {
645 self.0.tracing_context.as_ref()
647 .and_then(|ctx| ctx.on_ending.as_ref())
648 .map(|on_ending| (on_ending)(&self.0));
649
650 let tracer = globals::tracer().unwrap();
651 tracer.drop_span(recording, &mut PrivateMarker(()));
652 }
653 }
654}
655
656impl OwnedSpanRef {
657 pub fn set_attributes<'a>(&self, tracer: &dyn Tracer, attrs: AttributeList<'a>){
658 if attrs.0.is_empty() { return }
659 if let Some(recording) = self.as_recording_self_or_ancestor() {
660 tracer.set_attributes(recording, attrs);
661 }
662 }
663
664 pub fn set_status(&self, tracer: &dyn Tracer, status: SpanStatus){
665 if let Some(recording) = self.as_recording_self_or_ancestor() {
666 tracer.set_status(recording, status);
667 }
668 }
669}
670
671pub mod globals {
672 use super::{AttributeList, InstrumentationError, NoCurrentSpan, NoTracerRegistered, OwnedSpanRef, SpanStatus, Text, Tracer};
673 use tokio::task::futures::TaskLocalFuture;
674 use std::future::Future;
675
676 static TRACER: std::sync::OnceLock<Box<dyn Tracer>> = std::sync::OnceLock::new();
677
678 tokio::task_local! {
679 static CURRENT_SPAN: OwnedSpanRef;
680 }
681
682 pub fn set_tracer(tracer: Box<dyn Tracer>){
683 TRACER.set(tracer).ok()
684 .expect("[FATAL] tracelite: tracer already set");
685 }
686
687 pub fn tracer() -> Result<&'static dyn Tracer, NoTracerRegistered> {
688 TRACER.get().map(|f| &**f).ok_or(NoTracerRegistered)
689 }
690
691 pub fn current_span<T>(f: impl FnOnce(&OwnedSpanRef) -> T) -> Result<T, NoCurrentSpan> {
692 CURRENT_SPAN.try_with(f).map_err(|_| NoCurrentSpan)
693 }
694
695 pub enum MaybeInSpan<F>{
696 InSpan(TaskLocalFuture<OwnedSpanRef, F>),
697 NotInSpan(F),
698 }
699
700 impl<F> std::future::Future for MaybeInSpan<F>
701 where F: std::future::Future
702 {
703 type Output = F::Output;
704 fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
705 match unsafe { std::pin::Pin::get_unchecked_mut(self) } {
707 MaybeInSpan::InSpan(f) => unsafe { std::pin::Pin::new_unchecked(f).poll(cx) },
708 MaybeInSpan::NotInSpan(f) => unsafe { std::pin::Pin::new_unchecked(f).poll(cx) },
709 }
710 }
711 }
712
713 pub trait InSpan: Future + Sized {
714 fn in_span(self, span: impl Into<Option<OwnedSpanRef>>) -> MaybeInSpan<Self> {
715 if let Some(span) = span.into() {
716 MaybeInSpan::InSpan(CURRENT_SPAN.scope(span, self))
717 } else {
718 MaybeInSpan::NotInSpan(self)
719 }
720 }
721 }
722
723 impl<F: Future + Sized> InSpan for F {}
724
725 pub fn sync_in_span<R>(span: impl Into<Option<OwnedSpanRef>>, f: impl FnOnce() -> R) -> R {
726 if let Some(span) = span.into() {
727 CURRENT_SPAN.sync_scope(span, f)
728 } else {
729 f()
730 }
731 }
732
733 pub fn set_attributes<'a>(attrs: AttributeList<'a>) {
735 if attrs.0.is_empty() { return }
736 let Some(tracer) = tracer().ok() else { return };
737 let mut attrs = Some(attrs);
738
739 current_span(|span| {
740 span.set_attributes(tracer, attrs.take().unwrap());
741 }).ok().unwrap_or_else(|| {
742 let attrs = attrs.take().unwrap();
743 let err = InstrumentationError::StrayAttributes(attrs);
744 tracer.instrumentation_error(err);
745 });
746 }
747
748 pub fn set_status(status: SpanStatus<'_>){
749 let Some(tracer) = tracer().ok() else { return };
750 let mut status = Some(status);
751
752 current_span(|span| {
753 span.set_status(tracer, status.take().unwrap());
754 }).ok().unwrap_or_else(|| {
755 let status = status.take().unwrap();
756 let err = InstrumentationError::StrayStatus(status);
757 tracer.instrumentation_error(err);
758 });
759 }
760
761 pub fn set_ok_status(){
762 set_status(SpanStatus::Ok);
763 }
764
765 pub fn set_error_status<'a>(msg: impl Into<Text<'a>>){
766 set_status(SpanStatus::error(msg));
767 }
768
769}