]> Untitled Git - lemmy.git/blob - src/root_span_builder.rs
Merge branch 'vijaykramesh_clear_deleted_posts_comments'
[lemmy.git] / src / root_span_builder.rs
1 use actix_web::{http::StatusCode, ResponseError};
2 use tracing::Span;
3 use tracing_actix_web::RootSpanBuilder;
4
5 // Code in this module adapted from DefaultRootSpanBuilder
6 // https://github.com/LukeMathWalker/tracing-actix-web/blob/main/src/root_span_builder.rs
7 // and root_span!
8 // https://github.com/LukeMathWalker/tracing-actix-web/blob/main/src/root_span_macro.rs
9
10 pub struct QuieterRootSpanBuilder;
11
12 impl RootSpanBuilder for QuieterRootSpanBuilder {
13   fn on_request_start(request: &actix_web::dev::ServiceRequest) -> Span {
14     let request_id = tracing_actix_web::root_span_macro::private::get_request_id(request);
15
16     tracing::info_span!(
17         "HTTP request",
18         http.method = %request.method(),
19         http.scheme = request.connection_info().scheme(),
20         http.host = %request.connection_info().host(),
21         http.target = %request.uri().path(),
22         http.status_code = tracing::field::Empty,
23         otel.kind = "server",
24         otel.status_code = tracing::field::Empty,
25         trace_id = tracing::field::Empty,
26         request_id = %request_id,
27         exception.message = tracing::field::Empty,
28         // Not proper OpenTelemetry, but their terminology is fairly exception-centric
29         exception.details = tracing::field::Empty,
30     )
31   }
32
33   fn on_request_end<B>(
34     span: tracing::Span,
35     outcome: &Result<actix_web::dev::ServiceResponse<B>, actix_web::Error>,
36   ) {
37     match &outcome {
38       Ok(response) => {
39         if let Some(error) = response.response().error() {
40           // use the status code already constructed for the outgoing HTTP response
41           handle_error(span, response.status(), error.as_response_error());
42         } else {
43           let code: i32 = response.response().status().as_u16().into();
44           span.record("http.status_code", code);
45           span.record("otel.status_code", "OK");
46         }
47       }
48       Err(error) => {
49         let response_error = error.as_response_error();
50         handle_error(span, response_error.status_code(), response_error);
51       }
52     };
53   }
54 }
55
56 fn handle_error(span: Span, status_code: StatusCode, response_error: &dyn ResponseError) {
57   let code: i32 = status_code.as_u16().into();
58
59   span.record("http.status_code", code);
60
61   if status_code.is_client_error() {
62     span.record("otel.status_code", "OK");
63   } else {
64     span.record("otel.status_code", "ERROR");
65   }
66
67   // pre-formatting errors is a workaround for https://github.com/tokio-rs/tracing/issues/1565
68   let display_error = format!("{response_error}");
69   let debug_error = format!("{response_error:?}");
70
71   tracing::info_span!(
72     parent: None,
73     "Error encountered while processing the incoming HTTP request"
74   )
75   .in_scope(|| {
76     if status_code.is_client_error() {
77       tracing::warn!("{}\n{}", display_error, debug_error);
78     } else {
79       tracing::error!("{}\n{}", display_error, debug_error);
80     }
81   });
82
83   span.record("exception.message", &tracing::field::display(display_error));
84   span.record("exception.details", &tracing::field::display(debug_error));
85 }