hyperi_rustlib/transport/
propagation.rs1pub const TRACEPARENT_HEADER: &str = "traceparent";
20
21#[cfg(feature = "transport-trace")]
26#[must_use]
27pub fn current_traceparent() -> Option<String> {
28 use opentelemetry::trace::TraceContextExt;
29
30 let cx = opentelemetry::Context::current();
31 let span = cx.span();
32 let sc = span.span_context();
33
34 if sc.is_valid() {
35 Some(format_traceparent(sc))
36 } else {
37 None
38 }
39}
40
41#[cfg(feature = "transport-trace")]
46fn format_traceparent(sc: &opentelemetry::trace::SpanContext) -> String {
47 format!(
48 "00-{}-{}-{:02x}",
49 sc.trace_id(),
50 sc.span_id(),
51 sc.trace_flags().to_u8()
52 )
53}
54
55#[must_use]
57pub fn format_traceparent_raw(trace_id: u128, span_id: u64, flags: u8) -> String {
58 format!("00-{trace_id:032x}-{span_id:016x}-{flags:02x}")
59}
60
61#[must_use]
66pub fn is_valid_traceparent(value: &str) -> bool {
67 if value.len() != 55 {
69 return false;
70 }
71
72 let bytes = value.as_bytes();
73
74 if bytes[0] != b'0' || bytes[1] != b'0' {
76 return false;
77 }
78
79 if bytes[2] != b'-' || bytes[35] != b'-' || bytes[52] != b'-' {
81 return false;
82 }
83
84 let hex_ranges = [3..35, 36..52, 53..55];
86 for range in &hex_ranges {
87 for &b in &bytes[range.clone()] {
88 if !b.is_ascii_hexdigit() {
89 return false;
90 }
91 }
92 }
93
94 true
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn traceparent_format_raw() {
103 let tp = format_traceparent_raw(
104 0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736,
105 0x00f0_67aa_0ba9_02b7,
106 0x01,
107 );
108 assert_eq!(
109 tp,
110 "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
111 );
112 assert_eq!(tp.len(), 55);
113 }
114
115 #[test]
116 fn traceparent_format_zero_padded() {
117 let tp = format_traceparent_raw(123, 456, 1);
119 assert!(tp.starts_with("00-"));
120 assert_eq!(tp.len(), 55);
121 assert_eq!(
122 tp,
123 "00-0000000000000000000000000000007b-00000000000001c8-01"
124 );
125 }
126
127 #[test]
128 fn traceparent_format_flags_zero() {
129 let tp = format_traceparent_raw(1, 1, 0);
130 assert!(tp.ends_with("-00"));
131 }
132
133 #[test]
134 fn valid_traceparent() {
135 assert!(is_valid_traceparent(
136 "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
137 ));
138 }
139
140 #[test]
141 fn invalid_traceparent_too_short() {
142 assert!(!is_valid_traceparent("00-abc-def-01"));
143 }
144
145 #[test]
146 fn invalid_traceparent_bad_version() {
147 assert!(!is_valid_traceparent(
148 "ff-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
149 ));
150 }
151
152 #[test]
153 fn invalid_traceparent_non_hex() {
154 assert!(!is_valid_traceparent(
155 "00-4bf92f3577b34da6a3ce929d0e0eXXXX-00f067aa0ba902b7-01"
156 ));
157 }
158
159 #[test]
160 fn invalid_traceparent_wrong_separators() {
161 assert!(!is_valid_traceparent(
162 "00_4bf92f3577b34da6a3ce929d0e0e4736_00f067aa0ba902b7_01"
163 ));
164 }
165}