tracing_honeycomb/
span_id.rs

1use std::convert::TryFrom;
2use std::fmt::{self, Display};
3use std::num::{NonZeroU64, ParseIntError, TryFromIntError};
4use std::str::FromStr;
5/// Unique Span identifier.
6///
7/// Wraps a `tracing::span::Id` with a suitable parser.
8///
9/// `Display` and `FromStr` are guaranteed to round-trip.
10#[derive(Clone, Debug, Eq, Hash, PartialEq)]
11pub struct SpanId {
12    pub(crate) tracing_id: tracing::span::Id,
13}
14
15impl SpanId {
16    /// Metadata field name associated with `SpanId` values.
17    pub fn meta_field_name() -> &'static str {
18        "span-id"
19    }
20}
21
22#[derive(Clone, Debug, Eq, PartialEq)]
23pub enum ParseSpanIdError {
24    ParseIntError(ParseIntError),
25    TryFromIntError(TryFromIntError),
26}
27
28impl Display for ParseSpanIdError {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Self::ParseIntError(e) => write!(f, "{}", e),
32            Self::TryFromIntError(e) => write!(f, "{}", e),
33        }
34    }
35}
36
37impl From<ParseIntError> for ParseSpanIdError {
38    fn from(err: ParseIntError) -> Self {
39        Self::ParseIntError(err)
40    }
41}
42
43impl From<TryFromIntError> for ParseSpanIdError {
44    fn from(err: TryFromIntError) -> Self {
45        Self::TryFromIntError(err)
46    }
47}
48
49impl std::error::Error for ParseSpanIdError {}
50
51impl FromStr for SpanId {
52    type Err = ParseSpanIdError;
53
54    /// Parses a Span Id from a hex value.
55    fn from_str(s: &str) -> Result<Self, Self::Err> {
56        let raw_id = u64::from_str_radix(s, 16)?;
57        let id = NonZeroU64::try_from(raw_id)?;
58
59        Ok(SpanId {
60            tracing_id: tracing::Id::from_non_zero_u64(id),
61        })
62    }
63}
64
65impl Display for SpanId {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "{:x}", self.tracing_id.into_u64())
68    }
69}
70
71#[cfg(test)]
72mod test {
73    use super::*;
74    use proptest::prelude::*;
75
76    use crate::SpanId;
77
78    proptest! {
79        #[test]
80        // ua is [1..] and not [0..] because 0 is not a valid tracing::Id (tracing::from_u64 throws on 0)
81        fn span_id_round_trip(ua in 1u64..) {
82            let span_id = SpanId {
83                tracing_id: tracing::Id::from_u64(ua),
84            };
85            let s = span_id.to_string();
86            let res = SpanId::from_str(&s);
87            assert_eq!(Ok(span_id), res);
88        }
89    }
90}