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