opentelemetry/
trace_context.rs

1use std::fmt;
2use std::hash::Hash;
3use std::num::ParseIntError;
4use std::ops::{BitAnd, BitOr, Not};
5
6/// Flags that can be set on a `SpanContext`.
7///
8/// The current version of the specification only supports a single flag
9/// [`TraceFlags::SAMPLED`].
10///
11/// See the W3C TraceContext specification's [trace-flags] section for more
12/// details.
13///
14/// [trace-flags]: https://www.w3.org/TR/trace-context/#trace-flags
15#[derive(Clone, Debug, Default, PartialEq, Eq, Copy, Hash)]
16pub struct TraceFlags(u8);
17
18impl TraceFlags {
19    /// Trace flags with the `sampled` flag set to `0`.
20    ///
21    /// Spans that are not sampled will be ignored by most tracing tools.
22    /// See the `sampled` section of the [W3C TraceContext specification] for details.
23    ///
24    /// [W3C TraceContext specification]: https://www.w3.org/TR/trace-context/#sampled-flag
25    pub const NOT_SAMPLED: TraceFlags = TraceFlags(0x00);
26
27    /// Trace flags with the `sampled` flag set to `1`.
28    ///
29    /// Spans that are not sampled will be ignored by most tracing tools.
30    /// See the `sampled` section of the [W3C TraceContext specification] for details.
31    ///
32    /// [W3C TraceContext specification]: https://www.w3.org/TR/trace-context/#sampled-flag
33    pub const SAMPLED: TraceFlags = TraceFlags(0x01);
34
35    /// Construct new trace flags
36    pub const fn new(flags: u8) -> Self {
37        TraceFlags(flags)
38    }
39
40    /// Returns `true` if the `sampled` flag is set
41    pub fn is_sampled(&self) -> bool {
42        (*self & TraceFlags::SAMPLED) == TraceFlags::SAMPLED
43    }
44
45    /// Returns copy of the current flags with the `sampled` flag set.
46    pub fn with_sampled(&self, sampled: bool) -> Self {
47        if sampled {
48            *self | TraceFlags::SAMPLED
49        } else {
50            *self & !TraceFlags::SAMPLED
51        }
52    }
53
54    /// Returns the flags as a `u8`
55    pub fn to_u8(self) -> u8 {
56        self.0
57    }
58}
59
60impl BitAnd for TraceFlags {
61    type Output = Self;
62
63    fn bitand(self, rhs: Self) -> Self::Output {
64        Self(self.0 & rhs.0)
65    }
66}
67
68impl BitOr for TraceFlags {
69    type Output = Self;
70
71    fn bitor(self, rhs: Self) -> Self::Output {
72        Self(self.0 | rhs.0)
73    }
74}
75
76impl Not for TraceFlags {
77    type Output = Self;
78
79    fn not(self) -> Self::Output {
80        Self(!self.0)
81    }
82}
83
84impl fmt::LowerHex for TraceFlags {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        fmt::LowerHex::fmt(&self.0, f)
87    }
88}
89
90/// A 16-byte value which identifies a given trace.
91///
92/// The id is valid if it contains at least one non-zero byte.
93#[derive(Clone, PartialEq, Eq, Copy, Hash)]
94pub struct TraceId(u128);
95
96impl TraceId {
97    /// Invalid trace id
98    pub const INVALID: TraceId = TraceId(0);
99
100    /// Create a trace id from its representation as a byte array.
101    pub const fn from_bytes(bytes: [u8; 16]) -> Self {
102        TraceId(u128::from_be_bytes(bytes))
103    }
104
105    /// Return the representation of this trace id as a byte array.
106    pub const fn to_bytes(self) -> [u8; 16] {
107        self.0.to_be_bytes()
108    }
109
110    /// Converts a string in base 16 to a trace id.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// use opentelemetry::trace::TraceId;
116    ///
117    /// assert!(TraceId::from_hex("42").is_ok());
118    /// assert!(TraceId::from_hex("58406520a006649127e371903a2de979").is_ok());
119    ///
120    /// assert!(TraceId::from_hex("not_hex").is_err());
121    /// ```
122    pub fn from_hex(hex: &str) -> Result<Self, ParseIntError> {
123        u128::from_str_radix(hex, 16).map(TraceId)
124    }
125}
126
127impl From<u128> for TraceId {
128    fn from(value: u128) -> Self {
129        TraceId(value)
130    }
131}
132
133impl fmt::Debug for TraceId {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.write_fmt(format_args!("{:032x}", self.0))
136    }
137}
138
139impl fmt::Display for TraceId {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        f.write_fmt(format_args!("{:032x}", self.0))
142    }
143}
144
145impl fmt::LowerHex for TraceId {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        fmt::LowerHex::fmt(&self.0, f)
148    }
149}
150
151/// An 8-byte value which identifies a given span.
152///
153/// The id is valid if it contains at least one non-zero byte.
154#[derive(Clone, PartialEq, Eq, Copy, Hash)]
155pub struct SpanId(u64);
156
157impl SpanId {
158    /// Invalid span id
159    pub const INVALID: SpanId = SpanId(0);
160
161    /// Create a span id from its representation as a byte array.
162    pub const fn from_bytes(bytes: [u8; 8]) -> Self {
163        SpanId(u64::from_be_bytes(bytes))
164    }
165
166    /// Return the representation of this span id as a byte array.
167    pub const fn to_bytes(self) -> [u8; 8] {
168        self.0.to_be_bytes()
169    }
170
171    /// Converts a string in base 16 to a span id.
172    ///
173    /// # Examples
174    ///
175    /// ```
176    /// use opentelemetry::trace::SpanId;
177    ///
178    /// assert!(SpanId::from_hex("42").is_ok());
179    /// assert!(SpanId::from_hex("58406520a0066491").is_ok());
180    ///
181    /// assert!(SpanId::from_hex("not_hex").is_err());
182    /// ```
183    pub fn from_hex(hex: &str) -> Result<Self, ParseIntError> {
184        u64::from_str_radix(hex, 16).map(SpanId)
185    }
186}
187
188impl From<u64> for SpanId {
189    fn from(value: u64) -> Self {
190        SpanId(value)
191    }
192}
193
194impl fmt::Debug for SpanId {
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        f.write_fmt(format_args!("{:016x}", self.0))
197    }
198}
199
200impl fmt::Display for SpanId {
201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        f.write_fmt(format_args!("{:016x}", self.0))
203    }
204}
205
206impl fmt::LowerHex for SpanId {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        fmt::LowerHex::fmt(&self.0, f)
209    }
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215
216    #[rustfmt::skip]
217    fn trace_id_test_data() -> Vec<(TraceId, &'static str, [u8; 16])> {
218        vec![
219            (TraceId(0), "00000000000000000000000000000000", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
220            (TraceId(42), "0000000000000000000000000000002a", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42]),
221            (TraceId(126642714606581564793456114182061442190), "5f467fe7bf42676c05e20ba4a90e448e", [95, 70, 127, 231, 191, 66, 103, 108, 5, 226, 11, 164, 169, 14, 68, 142])
222        ]
223    }
224
225    #[rustfmt::skip]
226    fn span_id_test_data() -> Vec<(SpanId, &'static str, [u8; 8])> {
227        vec![
228            (SpanId(0), "0000000000000000", [0, 0, 0, 0, 0, 0, 0, 0]),
229            (SpanId(42), "000000000000002a", [0, 0, 0, 0, 0, 0, 0, 42]),
230            (SpanId(5508496025762705295), "4c721bf33e3caf8f", [76, 114, 27, 243, 62, 60, 175, 143])
231        ]
232    }
233
234    #[test]
235    fn test_trace_id() {
236        for test_case in trace_id_test_data() {
237            assert_eq!(format!("{}", test_case.0), test_case.1);
238            assert_eq!(format!("{:032x}", test_case.0), test_case.1);
239            assert_eq!(test_case.0.to_bytes(), test_case.2);
240
241            assert_eq!(test_case.0, TraceId::from_hex(test_case.1).unwrap());
242            assert_eq!(test_case.0, TraceId::from_bytes(test_case.2));
243        }
244    }
245
246    #[test]
247    fn test_span_id() {
248        for test_case in span_id_test_data() {
249            assert_eq!(format!("{}", test_case.0), test_case.1);
250            assert_eq!(format!("{:016x}", test_case.0), test_case.1);
251            assert_eq!(test_case.0.to_bytes(), test_case.2);
252
253            assert_eq!(test_case.0, SpanId::from_hex(test_case.1).unwrap());
254            assert_eq!(test_case.0, SpanId::from_bytes(test_case.2));
255        }
256    }
257}