service_conventions/
tracing_http.rs1use 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}