1use std::collections::hash_map::RandomState;
7use std::hash::{BuildHasher, Hasher};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10use sha2::{Digest, Sha256};
11
12pub trait IdSource: Send {
14 fn trace_id(&mut self) -> [u8; 16];
16 fn span_id(&mut self) -> [u8; 8];
18}
19
20#[derive(Debug, Clone)]
23pub struct SeededIds {
24 seed: [u8; 32],
25 counter: u64,
26}
27
28impl SeededIds {
29 pub fn new(seed: &[u8]) -> Self {
30 SeededIds {
31 seed: Sha256::digest(seed).into(),
32 counter: 0,
33 }
34 }
35
36 fn next(&mut self) -> [u8; 32] {
37 loop {
38 self.counter += 1;
39 let mut h = Sha256::new();
40 h.update(b"rustev-otel.ids/1");
41 h.update(self.seed);
42 h.update(self.counter.to_be_bytes());
43 let out: [u8; 32] = h.finalize().into();
44 if out[..16].iter().any(|b| *b != 0) && out[..8].iter().any(|b| *b != 0) {
45 return out;
46 }
47 }
48 }
49}
50
51impl IdSource for SeededIds {
52 fn trace_id(&mut self) -> [u8; 16] {
53 let mut id = [0u8; 16];
54 id.copy_from_slice(&self.next()[..16]);
55 id
56 }
57
58 fn span_id(&mut self) -> [u8; 8] {
59 let mut id = [0u8; 8];
60 id.copy_from_slice(&self.next()[..8]);
61 id
62 }
63}
64
65#[derive(Debug, Clone)]
69pub struct RandomIds(SeededIds);
70
71impl Default for RandomIds {
72 fn default() -> Self {
73 let mut h = RandomState::new().build_hasher();
74 h.write_u128(
75 SystemTime::now()
76 .duration_since(UNIX_EPOCH)
77 .map(|d| d.as_nanos())
78 .unwrap_or(0),
79 );
80 h.write_u32(std::process::id());
81 let a = h.finish();
82 let mut h2 = RandomState::new().build_hasher();
83 h2.write_u64(a);
84 let b = h2.finish();
85 let mut seed = [0u8; 16];
86 seed[..8].copy_from_slice(&a.to_be_bytes());
87 seed[8..].copy_from_slice(&b.to_be_bytes());
88 RandomIds(SeededIds::new(&seed))
89 }
90}
91
92impl IdSource for RandomIds {
93 fn trace_id(&mut self) -> [u8; 16] {
94 self.0.trace_id()
95 }
96
97 fn span_id(&mut self) -> [u8; 8] {
98 self.0.span_id()
99 }
100}
101
102pub fn hex(bytes: &[u8]) -> String {
104 let mut s = String::with_capacity(bytes.len() * 2);
105 for b in bytes {
106 s.push(char::from_digit(u32::from(b >> 4), 16).unwrap_or('0'));
107 s.push(char::from_digit(u32::from(b & 0xf), 16).unwrap_or('0'));
108 }
109 s
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn seeded_ids_repeat_and_random_ids_differ() {
118 let mut a = SeededIds::new(b"x");
119 let mut b = SeededIds::new(b"x");
120 assert_eq!(a.trace_id(), b.trace_id());
121 assert_eq!(a.span_id(), b.span_id());
122 let mut r1 = RandomIds::default();
123 let mut r2 = RandomIds::default();
124 assert_ne!(r1.trace_id(), r2.trace_id());
125 assert_eq!(hex(&[0x0a, 0xff]), "0aff");
126 }
127}