telemetry_rust/
propagation.rs1use opentelemetry::{
4 Context,
5 propagation::{
6 Extractor, Injector, TextMapCompositePropagator, TextMapPropagator,
7 text_map_propagator::FieldIter,
8 },
9};
10#[cfg(feature = "xray")]
11use opentelemetry_aws::trace::XrayPropagator;
12use opentelemetry_sdk::{
13 propagation::{BaggagePropagator, TraceContextPropagator},
14 trace::TraceError,
15};
16#[cfg(feature = "zipkin")]
17use opentelemetry_zipkin::{B3Encoding, Propagator as B3Propagator};
18use std::collections::BTreeSet;
19
20use crate::util;
21
22pub type Propagator = Box<dyn TextMapPropagator + Send + Sync>;
27
28#[derive(Debug)]
34pub struct NonePropagator;
35
36impl TextMapPropagator for NonePropagator {
37 fn inject_context(&self, _: &Context, _: &mut dyn Injector) {}
38
39 fn extract_with_context(&self, cx: &Context, _: &dyn Extractor) -> Context {
40 cx.clone()
41 }
42
43 fn fields(&self) -> FieldIter<'_> {
44 FieldIter::new(&[])
45 }
46}
47
48#[derive(Debug)]
61pub struct TextMapSplitPropagator {
62 extract_propagator: Propagator,
63 inject_propagator: Propagator,
64 fields: Vec<String>,
65}
66
67impl TextMapSplitPropagator {
68 pub fn new(extract_propagator: Propagator, inject_propagator: Propagator) -> Self {
79 let mut fields = BTreeSet::from_iter(extract_propagator.fields());
80 fields.extend(inject_propagator.fields());
81 let fields = fields.into_iter().map(String::from).collect();
82
83 Self {
84 extract_propagator,
85 inject_propagator,
86 fields,
87 }
88 }
89
90 pub fn from_env() -> Result<Self, TraceError> {
124 let value_from_env = match util::env_var("OTEL_PROPAGATORS") {
125 Some(value) => value,
126 None => {
127 return Ok(Self::default());
128 }
129 };
130 let propagators: Vec<String> = value_from_env
131 .split(',')
132 .map(|s| s.trim().to_lowercase())
133 .filter(|s| !s.is_empty())
134 .collect();
135 tracing::info!(target: "otel::setup", propagators = propagators.join(","));
136
137 let inject_propagator = match propagators.first() {
138 Some(s) => propagator_from_string(s)?,
139 None => Box::new(NonePropagator),
140 };
141 let propagators = propagators
142 .iter()
143 .map(|s| propagator_from_string(s))
144 .collect::<Result<Vec<_>, _>>()?;
145 let extract_propagator = Box::new(TextMapCompositePropagator::new(propagators));
146
147 Ok(Self::new(extract_propagator, inject_propagator))
148 }
149}
150
151impl TextMapPropagator for TextMapSplitPropagator {
152 fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) {
153 self.inject_propagator.inject_context(cx, injector)
154 }
155
156 fn extract_with_context(&self, cx: &Context, extractor: &dyn Extractor) -> Context {
157 self.extract_propagator.extract_with_context(cx, extractor)
158 }
159
160 fn fields(&self) -> FieldIter<'_> {
161 FieldIter::new(self.fields.as_slice())
162 }
163}
164
165impl Default for TextMapSplitPropagator {
166 fn default() -> Self {
167 let trace_context_propagator = Box::new(TraceContextPropagator::new());
168 #[cfg(feature = "zipkin")]
169 let b3_propagator = Box::new(B3Propagator::with_encoding(
170 B3Encoding::SingleAndMultiHeader,
171 ));
172 let composite_propagator = Box::new(TextMapCompositePropagator::new(vec![
173 trace_context_propagator.clone(),
174 #[cfg(feature = "zipkin")]
175 b3_propagator,
176 ]));
177
178 Self::new(composite_propagator, trace_context_propagator)
179 }
180}
181
182fn propagator_from_string(v: &str) -> Result<Propagator, TraceError> {
183 match v.trim() {
184 "tracecontext" => Ok(Box::new(TraceContextPropagator::new())),
185 "baggage" => Ok(Box::new(BaggagePropagator::new())),
186 "none" => Ok(Box::new(NonePropagator)),
187 #[cfg(feature = "zipkin")]
188 "b3" => Ok(Box::new(B3Propagator::with_encoding(
189 B3Encoding::SingleHeader,
190 ))),
191 #[cfg(not(feature = "zipkin"))]
192 "b3" => Err(TraceError::from(
193 "unsupported propagator from env OTEL_PROPAGATORS: 'b3', try to enable compile feature 'zipkin'",
194 )),
195 #[cfg(feature = "zipkin")]
196 "b3multi" => Ok(Box::new(B3Propagator::with_encoding(
197 B3Encoding::MultipleHeader,
198 ))),
199 #[cfg(not(feature = "zipkin"))]
200 "b3multi" => Err(TraceError::from(
201 "unsupported propagator from env OTEL_PROPAGATORS: 'b3multi', try to enable compile feature 'zipkin'",
202 )),
203 #[cfg(feature = "xray")]
204 "xray" => Ok(Box::new(XrayPropagator::new())),
205 #[cfg(not(feature = "xray"))]
206 "xray" => Err(TraceError::from(
207 "unsupported propagator from env OTEL_PROPAGATORS: 'xray', try to enable compile feature 'xray'",
208 )),
209 unknown => Err(TraceError::from(format!(
210 "unsupported propagator from env OTEL_PROPAGATORS: {unknown:?}"
211 ))),
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use assert2::let_assert;
218
219 #[test]
220 fn init_tracing_failed_on_invalid_propagator() {
221 let_assert!(Err(_) = super::propagator_from_string("xxxxxx"));
222 }
223}