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 .rev()
144 .map(|s| propagator_from_string(s))
145 .collect::<Result<Vec<_>, _>>()?;
146 let extract_propagator = Box::new(TextMapCompositePropagator::new(propagators));
147
148 Ok(Self::new(extract_propagator, inject_propagator))
149 }
150}
151
152impl TextMapPropagator for TextMapSplitPropagator {
153 fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) {
154 self.inject_propagator.inject_context(cx, injector)
155 }
156
157 fn extract_with_context(&self, cx: &Context, extractor: &dyn Extractor) -> Context {
158 self.extract_propagator.extract_with_context(cx, extractor)
159 }
160
161 fn fields(&self) -> FieldIter<'_> {
162 FieldIter::new(self.fields.as_slice())
163 }
164}
165
166impl Default for TextMapSplitPropagator {
167 fn default() -> Self {
168 let trace_context_propagator = Box::new(TraceContextPropagator::new());
169 #[cfg(feature = "zipkin")]
170 let b3_propagator = Box::new(B3Propagator::with_encoding(
171 B3Encoding::SingleAndMultiHeader,
172 ));
173 let composite_propagator = Box::new(TextMapCompositePropagator::new(vec![
174 trace_context_propagator.clone(),
175 #[cfg(feature = "zipkin")]
176 b3_propagator,
177 ]));
178
179 Self::new(composite_propagator, trace_context_propagator)
180 }
181}
182
183fn propagator_from_string(v: &str) -> Result<Propagator, TraceError> {
184 match v.trim() {
185 "tracecontext" => Ok(Box::new(TraceContextPropagator::new())),
186 "baggage" => Ok(Box::new(BaggagePropagator::new())),
187 "none" => Ok(Box::new(NonePropagator)),
188 #[cfg(feature = "zipkin")]
189 "b3" => Ok(Box::new(B3Propagator::with_encoding(
190 B3Encoding::SingleHeader,
191 ))),
192 #[cfg(not(feature = "zipkin"))]
193 "b3" => Err(TraceError::from(
194 "unsupported propagator from env OTEL_PROPAGATORS: 'b3', try to enable compile feature 'zipkin'",
195 )),
196 #[cfg(feature = "zipkin")]
197 "b3multi" => Ok(Box::new(B3Propagator::with_encoding(
198 B3Encoding::MultipleHeader,
199 ))),
200 #[cfg(not(feature = "zipkin"))]
201 "b3multi" => Err(TraceError::from(
202 "unsupported propagator from env OTEL_PROPAGATORS: 'b3multi', try to enable compile feature 'zipkin'",
203 )),
204 #[cfg(feature = "xray")]
205 "xray" => Ok(Box::new(XrayPropagator::new())),
206 #[cfg(not(feature = "xray"))]
207 "xray" => Err(TraceError::from(
208 "unsupported propagator from env OTEL_PROPAGATORS: 'xray', try to enable compile feature 'xray'",
209 )),
210 unknown => Err(TraceError::from(format!(
211 "unsupported propagator from env OTEL_PROPAGATORS: {unknown:?}"
212 ))),
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use assert2::let_assert;
219
220 #[test]
221 fn init_tracing_failed_on_invalid_propagator() {
222 let_assert!(Err(_) = super::propagator_from_string("xxxxxx"));
223 }
224}