wasmcloud_tracing/
context.rs1use std::collections::HashMap;
6use std::ops::Deref;
7
8use opentelemetry::propagation::{Extractor, Injector, TextMapPropagator};
9use opentelemetry::trace::TraceContextExt;
10use opentelemetry_sdk::propagation::TraceContextPropagator;
11use tracing::span::Span;
12use tracing_opentelemetry::OpenTelemetrySpanExt;
13use wasmcloud_core::TraceContext;
14
15#[derive(Debug)]
17pub struct TraceContextExtractor<'a> {
18 inner: &'a TraceContext,
19}
20
21impl<'a> TraceContextExtractor<'a> {
22 #[must_use]
24 pub fn new(context: &'a TraceContext) -> Self {
25 TraceContextExtractor { inner: context }
26 }
27}
28
29impl Extractor for TraceContextExtractor<'_> {
30 fn get(&self, key: &str) -> Option<&str> {
31 self.inner
35 .iter()
36 .find_map(|(k, v)| (k == key).then_some(v.as_str()))
37 }
38
39 fn keys(&self) -> Vec<&str> {
40 self.inner.iter().map(|(k, _)| k.as_str()).collect()
41 }
42}
43
44#[derive(Clone, Debug, Default)]
46pub struct TraceContextInjector {
47 inner: HashMap<String, String>,
48}
49
50impl TraceContextInjector {
51 #[must_use]
53 pub fn new(headers: TraceContext) -> Self {
54 let mut inner = HashMap::with_capacity(headers.len());
57 inner.extend(headers);
58 TraceContextInjector { inner }
59 }
60
61 #[must_use]
64 pub fn new_with_span(headers: TraceContext) -> Self {
65 let mut header_map = Self::new(headers);
66 header_map.inject_context();
67 header_map
68 }
69
70 pub fn new_with_extractor(extractor: &dyn Extractor) -> Self {
72 let mut header_map = Self::default();
73 let ctx_propagator = TraceContextPropagator::new();
74 let context = ctx_propagator.extract(extractor);
75
76 if !context.span().span_context().is_valid() {
78 ctx_propagator.inject_context(&Span::current().context(), &mut header_map);
79 } else {
80 ctx_propagator.inject_context(&context, &mut header_map);
81 }
82
83 header_map
84 }
85
86 #[must_use]
89 pub fn default_with_span() -> Self {
90 let mut header_map = Self::default();
91 header_map.inject_context();
92 header_map
93 }
94
95 pub fn inject_context(&mut self) {
97 let ctx_propagator = TraceContextPropagator::new();
98 ctx_propagator.inject_context(&Span::current().context(), self);
99 }
100
101 pub fn inject_context_from_span(&mut self, span: &Span) {
103 let ctx_propagator = TraceContextPropagator::new();
104 ctx_propagator.inject_context(&span.context(), self);
105 }
106}
107
108impl Injector for TraceContextInjector {
109 fn set(&mut self, key: &str, value: String) {
110 self.inner.insert(key.to_owned(), value);
111 }
112}
113
114impl AsRef<HashMap<String, String>> for TraceContextInjector {
115 fn as_ref(&self) -> &HashMap<String, String> {
116 &self.inner
117 }
118}
119
120impl Deref for TraceContextInjector {
121 type Target = HashMap<String, String>;
122
123 fn deref(&self) -> &Self::Target {
124 &self.inner
125 }
126}
127
128impl From<TraceContext> for TraceContextInjector {
129 fn from(context: TraceContext) -> Self {
130 TraceContextInjector::new(context)
131 }
132}
133
134impl From<TraceContextInjector> for TraceContext {
135 fn from(inj: TraceContextInjector) -> Self {
136 inj.inner.into_iter().collect()
137 }
138}
139
140pub fn get_span_context(trace_context: &TraceContext) -> opentelemetry::Context {
143 let ctx_propagator = TraceContextPropagator::new();
144 let extractor = TraceContextExtractor::new(trace_context);
145 ctx_propagator.extract(&extractor)
146}
147
148#[allow(clippy::module_name_repetitions)]
156pub fn attach_span_context(trace_context: &TraceContext) {
157 let parent_ctx = get_span_context(trace_context);
158 Span::current().set_parent(parent_ctx);
159}