provide_telemetry/
tracing.rs1use std::collections::BTreeMap;
7use std::sync::atomic::{AtomicU64, Ordering};
8
9use crate::context::{set_trace_context_internal, trace_snapshot, ContextGuard};
10
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct Tracer {
13 name: String,
14}
15
16pub static tracer: std::sync::LazyLock<Tracer> = std::sync::LazyLock::new(|| Tracer::new(None));
17
18impl Tracer {
19 pub fn new(name: Option<&str>) -> Self {
20 Self {
21 name: name.unwrap_or("provide.telemetry").to_string(),
22 }
23 }
24
25 pub fn name(&self) -> &str {
26 &self.name
27 }
28}
29
30static TRACE_COUNTER: AtomicU64 = AtomicU64::new(1);
31
32fn next_hex(len: usize) -> String {
33 let seed = TRACE_COUNTER.fetch_add(1, Ordering::Relaxed);
34 let mut value = format!("{seed:016x}");
35 while value.len() < len {
36 let snapshot = TRACE_COUNTER.fetch_add(1, Ordering::Relaxed);
37 value.push_str(&format!("{snapshot:016x}"));
38 }
39 value[..len].to_string()
40}
41
42pub fn get_tracer(name: Option<&str>) -> Tracer {
43 Tracer::new(name)
44}
45
46pub fn set_trace_context(trace_id: Option<String>, span_id: Option<String>) -> ContextGuard {
47 set_trace_context_internal(trace_id, span_id)
48}
49
50pub fn get_trace_context() -> BTreeMap<String, Option<String>> {
51 let snapshot = trace_snapshot();
52 BTreeMap::from([
53 ("trace_id".to_string(), snapshot.trace_id),
54 ("span_id".to_string(), snapshot.span_id),
55 ])
56}
57
58pub fn trace<T, F>(name: &str, callback: F) -> T
59where
60 F: FnOnce() -> T,
61{
62 let _span_name = name;
63 let _guard = set_trace_context(Some(next_hex(32)), Some(next_hex(16)));
64 callback()
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn tracing_test_tracer_names_match_contract() {
73 assert_eq!(tracer.name(), "provide.telemetry");
74 assert_eq!(get_tracer(Some("custom.tracer")).name(), "custom.tracer");
75 }
76
77 #[test]
78 fn tracing_test_next_hex_respects_requested_length_and_advances() {
79 let first = next_hex(16);
80 let second = next_hex(16);
81 let long = next_hex(32);
82
83 assert_eq!(first.len(), 16);
84 assert_eq!(second.len(), 16);
85 assert_eq!(long.len(), 32);
86 assert_ne!(first, second);
87 assert!(first.chars().all(|ch| ch.is_ascii_hexdigit()));
88 assert!(long.chars().all(|ch| ch.is_ascii_hexdigit()));
89 }
90}