stackable_telemetry/instrumentation/axum/extractor.rs
1use axum::http::{HeaderMap, HeaderName};
2use opentelemetry::{Context, propagation::Extractor};
3
4/// Extracts the [`TextMapPropagator`][1] to access trace parent information in
5/// HTTP headers.
6///
7/// This propagation is useful when an HTTP request already has a trace parent
8/// which can be picked up by the Tower [`Layer`][2] to link both spans together.
9/// A concrete usage example is available in [`SpanExt::from_request`][3].
10///
11/// This is pretty much a copy-pasted version of the [`HeaderExtractor`][4] from
12/// the `opentelemetry_http` crate. However, we cannot use this crate, as it
13/// uses an outdated version of the underlying `http` crate.
14///
15/// [1]: opentelemetry::propagation::TextMapPropagator
16/// [2]: tower::Layer
17/// [3]: crate::instrumentation::axum::SpanExt::from_request
18/// [4]: https://docs.rs/opentelemetry-http/latest/opentelemetry_http/struct.HeaderExtractor.html
19pub struct HeaderExtractor<'a>(pub(crate) &'a HeaderMap);
20
21impl Extractor for HeaderExtractor<'_> {
22 fn get(&self, key: &str) -> Option<&str> {
23 self.0
24 .get(key)
25 .and_then(|header_value| header_value.to_str().ok())
26 }
27
28 fn keys(&self) -> Vec<&str> {
29 self.0.keys().map(HeaderName::as_str).collect()
30 }
31}
32
33impl<'a> HeaderExtractor<'a> {
34 /// Create a new header extractor from a reference to a [`HeaderMap`].
35 pub fn new(headers: &'a HeaderMap) -> Self {
36 Self(headers)
37 }
38
39 /// Extracts the [`TextMapPropagator`][1] from the HTTP headers.
40 ///
41 /// [1]: opentelemetry::propagation::TextMapPropagator
42 pub fn extract_context(&self) -> Context {
43 opentelemetry::global::get_text_map_propagator(|propagator| propagator.extract(self))
44 }
45}