1use core::fmt;
18use core::str::FromStr;
19
20use serde::{Deserialize, Serialize};
21
22use crate::collector::get_collector;
23#[cfg(feature = "enable")]
24use crate::span::CURRENT_SPAN;
25
26#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
28pub struct TraceId(pub u128);
29
30impl TraceId {
31 #[inline]
35 pub fn generate() -> Self {
36 get_collector().generate_trace_id()
37 }
38}
39
40impl fmt::Display for TraceId {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 write!(f, "{:032x}", self.0)
43 }
44}
45
46impl FromStr for TraceId {
47 type Err = core::num::ParseIntError;
48
49 fn from_str(s: &str) -> Result<Self, Self::Err> {
50 u128::from_str_radix(s, 16).map(TraceId)
51 }
52}
53
54impl serde::Serialize for TraceId {
55 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56 where
57 S: serde::Serializer,
58 {
59 let mut hex_bytes = [0u8; size_of::<u128>() * 2];
60 hex::encode_to_slice(self.0.to_le_bytes(), &mut hex_bytes).unwrap();
61
62 serializer.serialize_str(str::from_utf8(&hex_bytes).unwrap())
63 }
64}
65
66impl<'de> serde::Deserialize<'de> for TraceId {
67 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68 where
69 D: serde::Deserializer<'de>,
70 {
71 let bytes: [u8; size_of::<u128>()] = hex::serde::deserialize(deserializer)?;
72
73 Ok(TraceId(u128::from_le_bytes(bytes)))
74 }
75}
76
77#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
79pub struct SpanId(pub u64);
80
81#[cfg(feature = "enable")]
82impl SpanId {
83 #[inline]
84 #[doc(hidden)]
85 pub fn next_id() -> SpanId {
87 #[cfg(feature = "std")]
88 {
89 std::thread_local! {
90 static LOCAL_ID_GENERATOR: core::cell::Cell<u64> = core::cell::Cell::new(rand::random::<u64>() & 0xffffffff00000000);
91 }
92
93 LOCAL_ID_GENERATOR
94 .try_with(|g| {
95 let id = g.get().wrapping_add(1);
96 g.set(id);
97
98 SpanId(id)
99 })
100 .unwrap_or({
101 SpanId(0)
104 })
105 }
106
107 #[cfg(not(feature = "std"))]
108 {
109 use core::sync::atomic;
110 static COUNTER: atomic::AtomicU64 = atomic::AtomicU64::new(1);
112 SpanId(COUNTER.fetch_add(1, atomic::Ordering::Relaxed))
113 }
114 }
115}
116
117impl fmt::Display for SpanId {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(f, "{:016x}", self.0)
120 }
121}
122
123impl FromStr for SpanId {
124 type Err = core::num::ParseIntError;
125
126 fn from_str(s: &str) -> Result<Self, Self::Err> {
127 u64::from_str_radix(s, 16).map(SpanId)
128 }
129}
130
131impl serde::Serialize for SpanId {
132 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
133 where
134 S: serde::Serializer,
135 {
136 let mut hex_bytes = [0u8; size_of::<u64>() * 2];
137 hex::encode_to_slice(self.0.to_le_bytes(), &mut hex_bytes).unwrap();
138
139 serializer.serialize_str(str::from_utf8(&hex_bytes).unwrap())
140 }
141}
142
143impl<'de> serde::Deserialize<'de> for SpanId {
144 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
145 where
146 D: serde::Deserializer<'de>,
147 {
148 let bytes: [u8; size_of::<u64>()] = hex::serde::deserialize(deserializer)?;
149
150 Ok(SpanId(u64::from_le_bytes(bytes)))
151 }
152}
153
154#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
159pub struct SpanContext {
160 pub trace_id: TraceId,
162 pub span_id: SpanId,
164}
165
166impl SpanContext {
167 pub fn new(trace_id: TraceId, span_id: SpanId) -> Self {
180 Self { trace_id, span_id }
181 }
182
183 pub fn generate() -> Self {
195 Self {
196 trace_id: TraceId::generate(),
197 span_id: SpanId(0),
198 }
199 }
200
201 pub fn current() -> Option<Self> {
216 #[cfg(not(feature = "enable"))]
217 {
218 None
219 }
220
221 #[cfg(feature = "enable")]
222 {
223 CURRENT_SPAN.get()
224 }
225 }
226}
227
228#[cfg(all(test, feature = "std"))]
229mod tests {
230 use std::collections::HashSet;
231 use std::format;
232 use std::string::String;
233 use std::vec::Vec;
234
235 use super::*;
236
237 #[test]
238 #[cfg(not(miri))] #[allow(clippy::needless_collect)]
240 fn unique_id() {
241 let handles = std::iter::repeat_with(|| {
242 std::thread::spawn(|| {
243 std::iter::repeat_with(SpanId::next_id)
244 .take(1000)
245 .collect::<Vec<_>>()
246 })
247 })
248 .take(32)
249 .collect::<Vec<_>>();
250
251 let k = handles
252 .into_iter()
253 .flat_map(|h| h.join().unwrap())
254 .collect::<HashSet<_>>();
255
256 assert_eq!(k.len(), 32 * 1000);
257 }
258
259 #[test]
260 fn trace_id_formatting() {
261 assert_eq!(
262 format!("{}", TraceId(0)),
263 "00000000000000000000000000000000"
264 );
265 assert_eq!(
266 format!("{}", TraceId(u128::MAX)),
267 "ffffffffffffffffffffffffffffffff"
268 );
269 assert_eq!(
270 format!("{}", TraceId(0x123456789ABCDEF0FEDCBA9876543210)),
271 "123456789abcdef0fedcba9876543210"
272 );
273 assert_eq!(
274 format!("{}", TraceId(0x123)),
275 "00000000000000000000000000000123"
276 );
277 }
278
279 #[test]
280 fn span_id_formatting() {
281 assert_eq!(format!("{}", SpanId(0)), "0000000000000000");
282 assert_eq!(format!("{}", SpanId(u64::MAX)), "ffffffffffffffff");
283 assert_eq!(
284 format!("{}", SpanId(0xFEDCBA9876543210)),
285 "fedcba9876543210"
286 );
287 assert_eq!(format!("{}", SpanId(0x123)), "0000000000000123");
288 }
289
290 #[test]
291 fn trace_id_from_str() {
292 assert_eq!(
293 "123456789abcdef0fedcba9876543210"
294 .parse::<TraceId>()
295 .unwrap(),
296 TraceId(0x123456789ABCDEF0FEDCBA9876543210)
297 );
298 assert_eq!(
299 "123456789ABCDEF0FEDCBA9876543210"
300 .parse::<TraceId>()
301 .unwrap(),
302 TraceId(0x123456789ABCDEF0FEDCBA9876543210)
303 );
304 assert_eq!(
305 "00000000000000000000000000000000"
306 .parse::<TraceId>()
307 .unwrap(),
308 TraceId(0)
309 );
310 assert_eq!(
311 "ffffffffffffffffffffffffffffffff"
312 .parse::<TraceId>()
313 .unwrap(),
314 TraceId(u128::MAX)
315 );
316 assert_eq!("123".parse::<TraceId>().unwrap(), TraceId(0x123));
318
319 assert!("xyz".parse::<TraceId>().is_err());
320 assert!("".parse::<TraceId>().is_err());
321 }
322
323 #[test]
324 fn span_id_from_str() {
325 assert_eq!(
326 "fedcba9876543210".parse::<SpanId>().unwrap(),
327 SpanId(0xFEDCBA9876543210)
328 );
329 assert_eq!(
330 "FEDCBA9876543210".parse::<SpanId>().unwrap(),
331 SpanId(0xFEDCBA9876543210)
332 );
333 assert_eq!("0000000000000000".parse::<SpanId>().unwrap(), SpanId(0));
334 assert_eq!(
335 "ffffffffffffffff".parse::<SpanId>().unwrap(),
336 SpanId(u64::MAX)
337 );
338 assert_eq!("123".parse::<SpanId>().unwrap(), SpanId(0x123));
339
340 assert!("xyz".parse::<SpanId>().is_err());
341 assert!("".parse::<SpanId>().is_err());
342 }
343
344 #[test]
345 fn trace_id_format_from_str_roundtrip() {
346 let test_cases = [
347 0u128,
348 1,
349 0x123,
350 0x123456789ABCDEF0FEDCBA9876543210,
351 u128::MAX,
352 u128::MAX - 1,
353 ];
354
355 for value in test_cases {
356 let trace_id = TraceId(value);
357 let formatted = format!("{trace_id}");
358 let parsed = formatted.parse::<TraceId>().unwrap();
359 assert_eq!(trace_id, parsed, "Failed roundtrip for value {value:#x}");
360 }
361 }
362
363 #[test]
364 fn span_id_format_from_str_roundtrip() {
365 let test_cases = [0u64, 1, 0x123, 0xFEDCBA9876543210, u64::MAX, u64::MAX - 1];
366
367 for value in test_cases {
368 let span_id = SpanId(value);
369 let formatted = format!("{span_id}");
370 let parsed = formatted.parse::<SpanId>().unwrap();
371 assert_eq!(span_id, parsed, "Failed roundtrip for value {value:#x}");
372 }
373 }
374
375 #[test]
376 fn trace_id_serde_roundtrip() {
377 let test_cases = [
378 TraceId(0),
379 TraceId(1),
380 TraceId(0x123),
381 TraceId(0x123456789ABCDEF0FEDCBA9876543210),
382 TraceId(u128::MAX),
383 TraceId(u128::MAX - 1),
384 ];
385
386 for original in test_cases {
387 let json = serde_json::to_string(&original).unwrap();
388 let deserialized: TraceId = serde_json::from_str(&json).unwrap();
389 assert_eq!(
390 original, deserialized,
391 "JSON roundtrip failed for {:#x}",
392 original.0
393 );
394 }
395 }
396
397 #[test]
398 fn span_id_serde_roundtrip() {
399 let test_cases = [
400 SpanId(0),
401 SpanId(1),
402 SpanId(0x123),
403 SpanId(0xFEDCBA9876543210),
404 SpanId(u64::MAX),
405 SpanId(u64::MAX - 1),
406 ];
407
408 for original in test_cases {
409 let json = serde_json::to_string(&original).unwrap();
410 let deserialized: SpanId = serde_json::from_str(&json).unwrap();
411 assert_eq!(
412 original, deserialized,
413 "JSON roundtrip failed for {:#x}",
414 original.0
415 );
416 }
417 }
418
419 #[test]
420 fn span_context_serde_roundtrip() {
421 let test_cases = [
422 SpanContext::new(TraceId(0), SpanId(0)),
423 SpanContext::new(
424 TraceId(0x123456789ABCDEF0FEDCBA9876543210),
425 SpanId(0xFEDCBA9876543210),
426 ),
427 SpanContext::new(TraceId(u128::MAX), SpanId(u64::MAX)),
428 SpanContext::new(TraceId(1), SpanId(1)),
429 ];
430
431 for original in test_cases {
432 let json = serde_json::to_string(&original).unwrap();
433 let deserialized: SpanContext = serde_json::from_str(&json).unwrap();
434 assert_eq!(
435 original.trace_id, deserialized.trace_id,
436 "JSON roundtrip failed for trace_id"
437 );
438 assert_eq!(
439 original.span_id, deserialized.span_id,
440 "JSON roundtrip failed for span_id"
441 );
442 }
443 }
444
445 #[test]
446 fn trace_id_serialization_format() {
447 let trace_id = TraceId(0x123456789ABCDEF0FEDCBA9876543210);
448 let json = serde_json::to_string(&trace_id).unwrap();
449
450 let expected_le_bytes = 0x123456789ABCDEF0FEDCBA9876543210u128.to_le_bytes();
452 let mut expected_hex = String::new();
453 for byte in &expected_le_bytes {
454 expected_hex.push_str(&format!("{byte:02x}"));
455 }
456 let expected_json = format!("\"{expected_hex}\"");
457
458 assert_eq!(json, expected_json);
459 }
460
461 #[test]
462 fn span_id_serialization_format() {
463 let span_id = SpanId(0xFEDCBA9876543210);
464 let json = serde_json::to_string(&span_id).unwrap();
465
466 let expected_le_bytes = 0xFEDCBA9876543210u64.to_le_bytes();
467 let mut expected_hex = String::new();
468 for byte in &expected_le_bytes {
469 expected_hex.push_str(&format!("{byte:02x}"));
470 }
471 let expected_json = format!("\"{expected_hex}\"");
472
473 assert_eq!(json, expected_json);
474 }
475
476 #[test]
477 fn span_context_new_and_fields() {
478 let trace_id = TraceId(0x123);
479 let span_id = SpanId(0x456);
480 let context = SpanContext::new(trace_id, span_id);
481
482 assert_eq!(context.trace_id, trace_id);
483 assert_eq!(context.span_id, span_id);
484 }
485
486 #[test]
487 fn span_context_generate_produces_non_zero_trace_id() {
488 let context = SpanContext::generate();
489 assert_eq!(context.span_id, SpanId(0));
491 }
493
494 #[test]
495 fn span_id_next_id_produces_non_zero_values() {
496 let ids: Vec<SpanId> = (0..100).map(|_| SpanId::next_id()).collect();
497
498 for id in &ids {
499 assert_ne!(id.0, 0, "SpanId::next_id() should not produce zero values");
500 }
501
502 let mut unique_ids = HashSet::new();
503 for id in &ids {
504 assert!(
505 unique_ids.insert(id.0),
506 "SpanId::next_id() should produce unique values"
507 );
508 }
509 }
510}