Skip to main content

service_conventions/
tracing_http.rs

1use opentelemetry::global;
2use std::collections::HashMap;
3use tower_http::classify::{ServerErrorsAsFailures, SharedClassifier};
4use tower_http::trace::{self, TraceLayer};
5use tracing::Level;
6use tracing_opentelemetry::OpenTelemetrySpanExt;
7
8pub type TracingLayer = TraceLayer<SharedClassifier<ServerErrorsAsFailures>>;
9pub fn trace_layer(
10    level: Level,
11) -> TraceLayer<SharedClassifier<ServerErrorsAsFailures>, MakeSpan, OnRequest> {
12    TraceLayer::new_for_http()
13        .make_span_with(MakeSpan::new())
14        .on_request(OnRequest::new())
15        .on_response(trace::DefaultOnResponse::new().level(level))
16}
17
18pub fn get_tracing_headers() -> http::HeaderMap {
19    let mut map: HashMap<String, String> = HashMap::new();
20    let ctx = tracing::Span::current().context();
21    global::get_text_map_propagator(|propagator| propagator.inject_context(&ctx, &mut map));
22    let mut hm = http::HeaderMap::new();
23    if let Some(tp) = map.get("traceparent") {
24        hm.insert(
25            "traceparent",
26            http::HeaderValue::from_str(tp).expect("cannot convert"),
27        );
28    }
29    if let Some(tp) = map.get("tracestate") {
30        hm.insert(
31            "tracestate",
32            http::HeaderValue::from_str(tp).expect("cannot convert"),
33        );
34    }
35    tracing::debug!(otel_headers= ?map, headermap= ?hm, "Tracing headers");
36    hm
37}
38
39#[derive(Clone, Debug)]
40pub struct MakeSpan {}
41
42impl MakeSpan {
43    fn new() -> Self {
44        MakeSpan {}
45    }
46}
47
48impl<B> tower_http::trace::MakeSpan<B> for MakeSpan {
49    fn make_span(&mut self, request: &http::Request<B>) -> tracing::Span {
50        tracing::span!(
51            tracing::Level::INFO,
52            "request",
53            method = %request.method(),
54            uri = %request.uri(),
55            version = ?request.version(),
56            "otel.name" = tracing::field::Empty,
57
58        )
59    }
60}
61#[derive(Clone, Debug)]
62pub struct OnRequest {}
63
64impl OnRequest {
65    fn new() -> Self {
66        OnRequest {}
67    }
68}
69
70impl<B> tower_http::trace::OnRequest<B> for OnRequest {
71    fn on_request(&mut self, request: &http::request::Request<B>, s: &tracing::Span) {
72        use tracing_opentelemetry::OpenTelemetrySpanExt;
73        let axum_headers = request.headers();
74        let maybe_traceparent = axum_headers.get("traceparent");
75        let name = format!("{} {}", request.method(), request.uri().path());
76        s.record("otel.name", name.clone());
77        if let Some(traceparent) = maybe_traceparent {
78            let mut hm = std::collections::HashMap::new();
79            hm.insert(
80                "traceparent".to_string(),
81                traceparent.to_str().unwrap().to_string(),
82            );
83            let parent_context =
84                global::get_text_map_propagator(|propagator| propagator.extract(&hm));
85            s.set_parent(parent_context.clone());
86        }
87    }
88}