snix_tracing/propagate/axum.rs
1#[cfg(feature = "otlp")]
2use opentelemetry::{global, propagation::Extractor};
3#[cfg(feature = "otlp")]
4use tracing_opentelemetry::OpenTelemetrySpanExt;
5
6// TODO: accept_trace can be shared with tonic, as soon as tonic upstream has a release with
7// support for axum07. Latest master already has support for axum07 but there is not release yet:
8// https://github.com/hyperium/tonic/pull/1740
9
10/// Trace context propagation: associate the current span with the otlp trace of the given request,
11/// if any and valid. This only sets the parent trace if the otlp feature is also enabled.
12pub fn accept_trace<B>(request: axum::http::Request<B>) -> axum::http::Request<B> {
13 // we only extract and set a parent trace if otlp feature is enabled, otherwise this feature is
14 // an noop and we return the request as is
15 #[cfg(feature = "otlp")]
16 {
17 // Current context, if no or invalid data is received.
18 let parent_context = global::get_text_map_propagator(|propagator| {
19 propagator.extract(&HeaderExtractor(request.headers()))
20 });
21 tracing::Span::current().set_parent(parent_context);
22 }
23 request
24}
25
26/// Helper for extracting headers from HTTP Requests. This is used for OpenTelemetry context
27/// propagation over HTTP.
28#[cfg(feature = "otlp")]
29struct HeaderExtractor<'a>(&'a axum::http::HeaderMap);
30
31#[cfg(feature = "otlp")]
32impl Extractor for HeaderExtractor<'_> {
33 /// Get a value for a key from the HeaderMap. If the value is not valid ASCII, returns None.
34 fn get(&self, key: &str) -> Option<&str> {
35 self.0.get(key).and_then(|v| {
36 let s = v.to_str();
37 if let Err(ref error) = s {
38 tracing::warn!(%error, ?v, "cannot convert header value to ASCII")
39 };
40 s.ok()
41 })
42 }
43
44 /// Collect all the keys from the HeaderMap.
45 fn keys(&self) -> Vec<&str> {
46 self.0.keys().map(|k| k.as_str()).collect()
47 }
48}