use http::HeaderMap;
use opentelemetry::{Context, global, propagation::Injector};
struct HeaderMapInjector<'a>(&'a mut HeaderMap);
impl Injector for HeaderMapInjector<'_> {
fn set(&mut self, key: &str, value: String) {
if let (Ok(name), Ok(val)) = (
http::header::HeaderName::try_from(key),
http::header::HeaderValue::try_from(value),
) {
self.0.insert(name, val);
}
}
}
pub fn inject_current(headers: &mut HeaderMap) {
global::get_text_map_propagator(|propagator| {
propagator.inject_context(&Context::current(), &mut HeaderMapInjector(headers));
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_traceparent_without_active_span() {
let mut headers = HeaderMap::new();
inject_current(&mut headers);
assert!(
!headers.contains_key("traceparent"),
"expected no traceparent header when no span is active"
);
}
#[test]
fn traceparent_injected_with_propagator_and_active_span() {
use opentelemetry::trace::{TraceContextExt, Tracer, TracerProvider};
use opentelemetry_sdk::propagation::TraceContextPropagator;
use opentelemetry_sdk::trace::TracerProvider as SdkTracerProvider;
global::set_text_map_propagator(TraceContextPropagator::new());
let provider = SdkTracerProvider::builder().build();
let tracer = provider.tracer("test");
let span = tracer.start("test-span");
let cx = Context::current_with_span(span);
let _guard = cx.attach();
let mut headers = HeaderMap::new();
inject_current(&mut headers);
assert!(
headers.contains_key("traceparent"),
"expected traceparent header when span is active, got: {headers:?}"
);
}
}