1use crate::{SpanId, TraceFlags, TraceId};
2use std::collections::VecDeque;
3use std::hash::Hash;
4use std::str::FromStr;
5use thiserror::Error;
6
7#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
15pub struct TraceState(Option<VecDeque<(String, String)>>);
16
17impl TraceState {
18 pub const NONE: TraceState = TraceState(None);
20
21 fn valid_key(key: &str) -> bool {
25 if key.len() > 256 {
26 return false;
27 }
28
29 let allowed_special = |b: u8| b == b'_' || b == b'-' || b == b'*' || b == b'/';
30 let mut vendor_start = None;
31 for (i, &b) in key.as_bytes().iter().enumerate() {
32 if !(b.is_ascii_lowercase() || b.is_ascii_digit() || allowed_special(b) || b == b'@') {
33 return false;
34 }
35
36 if i == 0 && (!b.is_ascii_lowercase() && !b.is_ascii_digit()) {
37 return false;
38 } else if b == b'@' {
39 if vendor_start.is_some() || i + 14 < key.len() {
40 return false;
41 }
42 vendor_start = Some(i);
43 } else if let Some(start) = vendor_start {
44 if i == start + 1 && !(b.is_ascii_lowercase() || b.is_ascii_digit()) {
45 return false;
46 }
47 }
48 }
49
50 true
51 }
52
53 fn valid_value(value: &str) -> bool {
57 if value.len() > 256 {
58 return false;
59 }
60
61 !(value.contains(',') || value.contains('='))
62 }
63
64 pub fn from_key_value<T, K, V>(trace_state: T) -> TraceStateResult<Self>
78 where
79 T: IntoIterator<Item = (K, V)>,
80 K: ToString,
81 V: ToString,
82 {
83 let ordered_data = trace_state
84 .into_iter()
85 .map(|(key, value)| {
86 let (key, value) = (key.to_string(), value.to_string());
87 if !TraceState::valid_key(key.as_str()) {
88 return Err(TraceStateError::Key(key));
89 }
90 if !TraceState::valid_value(value.as_str()) {
91 return Err(TraceStateError::Value(value));
92 }
93
94 Ok((key, value))
95 })
96 .collect::<Result<VecDeque<_>, TraceStateError>>()?;
97
98 if ordered_data.is_empty() {
99 Ok(TraceState(None))
100 } else {
101 Ok(TraceState(Some(ordered_data)))
102 }
103 }
104
105 pub fn get(&self, key: &str) -> Option<&str> {
107 self.0.as_ref().and_then(|kvs| {
108 kvs.iter().find_map(|item| {
109 if item.0.as_str() == key {
110 Some(item.1.as_str())
111 } else {
112 None
113 }
114 })
115 })
116 }
117
118 pub fn insert<K, V>(&self, key: K, value: V) -> TraceStateResult<TraceState>
125 where
126 K: Into<String>,
127 V: Into<String>,
128 {
129 let (key, value) = (key.into(), value.into());
130 if !TraceState::valid_key(key.as_str()) {
131 return Err(TraceStateError::Key(key));
132 }
133 if !TraceState::valid_value(value.as_str()) {
134 return Err(TraceStateError::Value(value));
135 }
136
137 let mut trace_state = self.delete_from_deque(&key);
138 let kvs = trace_state.0.get_or_insert(VecDeque::with_capacity(1));
139
140 kvs.push_front((key, value));
141
142 Ok(trace_state)
143 }
144
145 pub fn delete<K: Into<String>>(&self, key: K) -> TraceStateResult<TraceState> {
153 let key = key.into();
154 if !TraceState::valid_key(key.as_str()) {
155 return Err(TraceStateError::Key(key));
156 }
157
158 Ok(self.delete_from_deque(&key))
159 }
160
161 fn delete_from_deque(&self, key: &str) -> TraceState {
163 let mut owned = self.clone();
164 if let Some(kvs) = owned.0.as_mut() {
165 if let Some(index) = kvs.iter().position(|x| x.0 == key) {
166 kvs.remove(index);
167 }
168 }
169 owned
170 }
171
172 pub fn header(&self) -> String {
175 self.header_delimited("=", ",")
176 }
177
178 pub fn header_delimited(&self, entry_delimiter: &str, list_delimiter: &str) -> String {
180 self.0
181 .as_ref()
182 .map(|kvs| {
183 kvs.iter()
184 .map(|(key, value)| format!("{key}{entry_delimiter}{value}"))
185 .collect::<Vec<String>>()
186 .join(list_delimiter)
187 })
188 .unwrap_or_default()
189 }
190}
191
192impl FromStr for TraceState {
193 type Err = TraceStateError;
194
195 fn from_str(s: &str) -> Result<Self, Self::Err> {
196 let list_members: Vec<&str> = s.split_terminator(',').collect();
197 let mut key_value_pairs: Vec<(String, String)> = Vec::with_capacity(list_members.len());
198
199 for list_member in list_members {
200 match list_member.find('=') {
201 None => return Err(TraceStateError::List(list_member.to_string())),
202 Some(separator_index) => {
203 let (key, value) = list_member.split_at(separator_index);
204 key_value_pairs
205 .push((key.to_string(), value.trim_start_matches('=').to_string()));
206 }
207 }
208 }
209
210 TraceState::from_key_value(key_value_pairs)
211 }
212}
213
214#[derive(Debug)]
216pub struct TraceStateIter<'a> {
217 inner: Option<std::collections::vec_deque::Iter<'a, (String, String)>>,
218}
219
220impl<'a> Iterator for TraceStateIter<'a> {
221 type Item = (&'a str, &'a str);
222
223 fn next(&mut self) -> Option<Self::Item> {
224 self.inner
225 .as_mut()?
226 .next()
227 .map(|(key, value)| (key.as_str(), value.as_str()))
228 }
229
230 fn size_hint(&self) -> (usize, Option<usize>) {
231 match &self.inner {
232 Some(iter) => iter.size_hint(),
233 None => (0, Some(0)),
234 }
235 }
236}
237
238impl ExactSizeIterator for TraceStateIter<'_> {
239 fn len(&self) -> usize {
240 match &self.inner {
241 Some(iter) => iter.len(),
242 None => 0,
243 }
244 }
245}
246
247impl<'a> IntoIterator for &'a TraceState {
248 type Item = (&'a str, &'a str);
249 type IntoIter = TraceStateIter<'a>;
250
251 fn into_iter(self) -> Self::IntoIter {
252 TraceStateIter {
253 inner: self.0.as_ref().map(|deque| deque.iter()),
254 }
255 }
256}
257
258type TraceStateResult<T> = Result<T, TraceStateError>;
260
261#[derive(Error, Debug)]
263#[non_exhaustive]
264pub enum TraceStateError {
265 #[error("{0} is not a valid key in TraceState, see https://www.w3.org/TR/trace-context/#key for more details")]
269 Key(String),
270
271 #[error("{0} is not a valid value in TraceState, see https://www.w3.org/TR/trace-context/#value for more details")]
275 Value(String),
276
277 #[error("{0} is not a valid list member in TraceState, see https://www.w3.org/TR/trace-context/#list for more details")]
281 List(String),
282}
283
284#[derive(Clone, Debug, PartialEq, Hash, Eq)]
294pub struct SpanContext {
295 trace_id: TraceId,
296 span_id: SpanId,
297 trace_flags: TraceFlags,
298 is_remote: bool,
299 trace_state: TraceState,
300}
301
302impl SpanContext {
303 pub const NONE: SpanContext = SpanContext {
305 trace_id: TraceId::INVALID,
306 span_id: SpanId::INVALID,
307 trace_flags: TraceFlags::NOT_SAMPLED,
308 is_remote: false,
309 trace_state: TraceState::NONE,
310 };
311
312 pub fn empty_context() -> Self {
314 SpanContext::NONE
315 }
316
317 pub fn new(
319 trace_id: TraceId,
320 span_id: SpanId,
321 trace_flags: TraceFlags,
322 is_remote: bool,
323 trace_state: TraceState,
324 ) -> Self {
325 SpanContext {
326 trace_id,
327 span_id,
328 trace_flags,
329 is_remote,
330 trace_state,
331 }
332 }
333
334 pub fn trace_id(&self) -> TraceId {
336 self.trace_id
337 }
338
339 pub fn span_id(&self) -> SpanId {
341 self.span_id
342 }
343
344 pub fn trace_flags(&self) -> TraceFlags {
349 self.trace_flags
350 }
351
352 pub fn is_valid(&self) -> bool {
355 self.trace_id != TraceId::INVALID && self.span_id != SpanId::INVALID
356 }
357
358 pub fn is_remote(&self) -> bool {
360 self.is_remote
361 }
362
363 pub fn is_sampled(&self) -> bool {
367 self.trace_flags.is_sampled()
368 }
369
370 pub fn trace_state(&self) -> &TraceState {
372 &self.trace_state
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use crate::{trace::TraceContextExt, Context};
380
381 #[rustfmt::skip]
382 fn trace_state_test_data() -> Vec<(TraceState, &'static str, &'static str)> {
383 vec![
384 (TraceState::from_key_value(vec![("foo", "bar")]).unwrap(), "foo=bar", "foo"),
385 (TraceState::from_key_value(vec![("foo", ""), ("apple", "banana")]).unwrap(), "foo=,apple=banana", "apple"),
386 (TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap(), "foo=bar,apple=banana", "apple"),
387 ]
388 }
389
390 #[test]
391 fn test_trace_state() {
392 for test_case in trace_state_test_data() {
393 assert_eq!(test_case.0.clone().header(), test_case.1);
394
395 let new_key = format!("{}-{}", test_case.0.get(test_case.2).unwrap(), "test");
396
397 let updated_trace_state = test_case.0.insert(test_case.2, new_key.clone());
398 assert!(updated_trace_state.is_ok());
399 let updated_trace_state = updated_trace_state.unwrap();
400
401 let updated = format!("{}={}", test_case.2, new_key);
402
403 let index = updated_trace_state.clone().header().find(&updated);
404
405 assert!(index.is_some());
406 assert_eq!(index.unwrap(), 0);
407
408 let deleted_trace_state = updated_trace_state.delete(test_case.2.to_string());
409 assert!(deleted_trace_state.is_ok());
410
411 let deleted_trace_state = deleted_trace_state.unwrap();
412
413 assert!(deleted_trace_state.get(test_case.2).is_none());
414 }
415 }
416
417 #[test]
418 fn test_trace_state_key() {
419 let test_data: Vec<(&'static str, bool)> = vec![
420 ("123", true),
421 ("bar", true),
422 ("foo@bar", true),
423 ("foo@0123456789abcdef", false),
424 ("foo@012345678", true),
425 ("FOO@BAR", false),
426 ("你好", false),
427 ];
428
429 for (key, expected) in test_data {
430 assert_eq!(TraceState::valid_key(key), expected, "test key: {key:?}");
431 }
432 }
433
434 #[test]
435 fn test_trace_state_insert() {
436 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
437 let inserted_trace_state = trace_state.insert("testkey", "testvalue").unwrap();
438 assert!(trace_state.get("testkey").is_none()); assert_eq!(inserted_trace_state.get("testkey").unwrap(), "testvalue"); }
441
442 #[test]
443 fn test_context_span_debug() {
444 let cx = Context::current();
445 assert_eq!(
446 format!("{cx:?}"),
447 "Context { span: \"None\", entries count: 0, suppress_telemetry: false }"
448 );
449 let cx = Context::current().with_remote_span_context(SpanContext::NONE);
450 assert_eq!(
451 format!("{cx:?}"),
452 "Context { \
453 span: SpanContext { \
454 trace_id: 00000000000000000000000000000000, \
455 span_id: 0000000000000000, \
456 trace_flags: TraceFlags(0), \
457 is_remote: false, \
458 trace_state: TraceState(None) \
459 }, \
460 entries count: 1, suppress_telemetry: false \
461 }"
462 );
463 }
464
465 #[test]
466 fn test_tracestate_iter_empty() {
467 let ts = TraceState::NONE;
468 let mut iter = ts.into_iter();
469 assert_eq!(iter.next(), None);
470 assert_eq!(iter.size_hint(), (0, Some(0)));
471 assert_eq!(iter.len(), 0);
472 }
473
474 #[test]
475 fn test_tracestate_iter_single() {
476 let ts = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
477 let mut iter = ts.into_iter();
478 assert_eq!(iter.next(), Some(("foo", "bar")));
479 assert_eq!(iter.next(), None);
480 assert_eq!(iter.size_hint(), (0, Some(0)));
481 }
482
483 #[test]
484 fn test_tracestate_iter_multiple() {
485 let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
486 let mut iter = ts.into_iter();
487 assert_eq!(iter.next(), Some(("foo", "bar")));
488 assert_eq!(iter.next(), Some(("apple", "banana")));
489 assert_eq!(iter.next(), None);
490 }
491
492 #[test]
493 fn test_tracestate_iter_size_hint_and_len() {
494 let ts = TraceState::from_key_value(vec![("foo", "bar"), ("apple", "banana")]).unwrap();
495 let iter = ts.into_iter();
496 assert_eq!(iter.size_hint(), (2, Some(2)));
497 assert_eq!(iter.len(), 2);
498 }
499}