spin_telemetry/
propagation.rs1use opentelemetry::{
2 global,
3 propagation::{Extractor, Injector},
4};
5use tracing_opentelemetry::OpenTelemetrySpanExt;
6
7pub fn inject_trace_context<'a>(req: impl Into<HeaderInjector<'a>>) {
9 let mut injector = req.into();
10 global::get_text_map_propagator(|propagator| {
11 let context = tracing::Span::current().context();
12 propagator.inject_context(&context, &mut injector);
13 });
14}
15
16pub fn extract_trace_context<'a>(req: impl Into<HeaderExtractor<'a>>) {
19 let extractor = req.into();
20 let parent_context =
21 global::get_text_map_propagator(|propagator| propagator.extract(&extractor));
22 tracing::Span::current().set_parent(parent_context);
23}
24
25pub enum HeaderInjector<'a> {
26 Http0(&'a mut http0::HeaderMap),
27 Http1(&'a mut http1::HeaderMap),
28}
29
30impl Injector for HeaderInjector<'_> {
31 fn set(&mut self, key: &str, value: String) {
32 match self {
33 HeaderInjector::Http0(headers) => {
34 if let Ok(name) = http0::header::HeaderName::from_bytes(key.as_bytes()) {
35 if let Ok(val) = http0::header::HeaderValue::from_str(&value) {
36 headers.insert(name, val);
37 }
38 }
39 }
40 HeaderInjector::Http1(headers) => {
41 if let Ok(name) = http1::header::HeaderName::from_bytes(key.as_bytes()) {
42 if let Ok(val) = http1::header::HeaderValue::from_str(&value) {
43 headers.insert(name, val);
44 }
45 }
46 }
47 }
48 }
49}
50
51impl<'a, T> From<&'a mut http0::Request<T>> for HeaderInjector<'a> {
52 fn from(req: &'a mut http0::Request<T>) -> Self {
53 Self::Http0(req.headers_mut())
54 }
55}
56
57impl<'a, T> From<&'a mut http1::Request<T>> for HeaderInjector<'a> {
58 fn from(req: &'a mut http1::Request<T>) -> Self {
59 Self::Http1(req.headers_mut())
60 }
61}
62
63impl<'a> From<&'a mut http0::HeaderMap> for HeaderInjector<'a> {
64 fn from(headers: &'a mut http0::HeaderMap) -> Self {
65 Self::Http0(headers)
66 }
67}
68
69impl<'a> From<&'a mut http1::HeaderMap> for HeaderInjector<'a> {
70 fn from(headers: &'a mut http1::HeaderMap) -> Self {
71 Self::Http1(headers)
72 }
73}
74
75pub enum HeaderExtractor<'a> {
76 Http0(&'a http0::HeaderMap),
77 Http1(&'a http1::HeaderMap),
78}
79
80impl Extractor for HeaderExtractor<'_> {
81 fn get(&self, key: &str) -> Option<&str> {
82 match self {
83 HeaderExtractor::Http0(headers) => {
84 headers.get(key).map(|v| v.to_str().unwrap_or_default())
85 }
86 HeaderExtractor::Http1(headers) => {
87 headers.get(key).map(|v| v.to_str().unwrap_or_default())
88 }
89 }
90 }
91
92 fn keys(&self) -> Vec<&str> {
93 match self {
94 HeaderExtractor::Http0(headers) => headers.keys().map(|k| k.as_str()).collect(),
95 HeaderExtractor::Http1(headers) => headers.keys().map(|k| k.as_str()).collect(),
96 }
97 }
98}
99
100impl<'a, T> From<&'a http0::Request<T>> for HeaderExtractor<'a> {
101 fn from(req: &'a http0::Request<T>) -> Self {
102 Self::Http0(req.headers())
103 }
104}
105
106impl<'a, T> From<&'a http1::Request<T>> for HeaderExtractor<'a> {
107 fn from(req: &'a http1::Request<T>) -> Self {
108 Self::Http1(req.headers())
109 }
110}