tower_http_tracing/
opentelemetry.rs1pub use opentelemetry::*;
3pub use opentelemetry_sdk as sdk;
4pub use tracing_opentelemetry;
5
6use opentelemetry_sdk::propagation::TraceContextPropagator;
7use opentelemetry::propagation::text_map_propagator::TextMapPropagator;
8
9pub struct HeaderMapExtractor<'a, T: AsRef<[u8]>>(pub &'a http::HeaderMap<T>);
11
12impl<T: AsRef<[u8]>> opentelemetry::propagation::Extractor for HeaderMapExtractor<'_, T> {
13 #[inline]
14 fn get(&self, key: &str) -> Option<&str> {
15 self.0.get(key).and_then(|value| core::str::from_utf8(value.as_ref()).ok())
16 }
17
18 #[inline]
19 fn keys(&self) -> Vec<&str> {
20 Vec::new()
21 }
22
23 #[inline]
24 fn get_all(&self, key: &str) -> Option<Vec<&str>> {
25 let values: Vec<_> = self.0.get_all(key).iter().filter_map(|value| core::str::from_utf8(value.as_ref()).ok()).collect();
26 if values.is_empty() {
27 None
28 } else {
29 Some(values)
30 }
31 }
32}
33
34pub struct HeaderMapInjector<'a, T: TryFrom<String>>(pub &'a mut http::HeaderMap<T>);
36
37impl<T: TryFrom<String>> opentelemetry::propagation::Injector for HeaderMapInjector<'_, T> {
38 #[inline]
39 fn set(&mut self, key: &str, value: String) {
40 let key = match http::HeaderName::from_bytes(key.as_bytes()) {
41 Ok(key) => key,
42 Err(_) => unreachable!()
43 };
44 match value.try_into() {
45 Ok(value) => self.0.insert(key, value),
46 Err(_) => unreachable!(),
47 };
48 }
49}
50
51#[inline(always)]
52pub fn on_request<T>(span: &tracing::Span, request: &http::Request<T>) {
56 use tracing_opentelemetry::OpenTelemetrySpanExt;
57
58 let propagator = TraceContextPropagator::new();
59 let context = propagator.extract(&HeaderMapExtractor(request.headers()));
60
61 if let Err(error) = span.set_parent(context) {
62 tracing::warn!("Unable to propagate parent context: {error}");
63 }
64}
65
66#[inline(always)]
67pub fn on_response_ok<T>(span: &tracing::Span, response: &mut http::Response<T>) {
69 use tracing_opentelemetry::OpenTelemetrySpanExt;
70
71 span.set_status(trace::Status::Ok);
72
73 let propagator = TraceContextPropagator::new();
74 let context = span.context();
75 propagator.inject_context(&context, &mut HeaderMapInjector(response.headers_mut()));
76}
77
78#[inline(always)]
79pub fn on_response_error(span: &tracing::Span, error: &impl std::error::Error) {
81 use tracing_opentelemetry::OpenTelemetrySpanExt;
82
83 let error = trace::Status::Error {
84 description: error.to_string().into()
85 };
86 span.set_status(error);
87}