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