at_jet/middleware/
logging.rs

1//! Request logging middleware
2
3use {axum::http::Request,
4     std::{future::Future,
5           pin::Pin,
6           task::{Context,
7                  Poll},
8           time::Instant},
9     tower::{Layer,
10             Service},
11     tracing::{info,
12               warn}};
13
14/// Request logging layer
15#[derive(Clone)]
16pub struct RequestLoggingLayer;
17
18impl<S> Layer<S> for RequestLoggingLayer {
19  type Service = RequestLoggingMiddleware<S>;
20
21  fn layer(&self, inner: S) -> Self::Service {
22    RequestLoggingMiddleware { inner }
23  }
24}
25
26/// Request logging middleware service
27#[derive(Clone)]
28pub struct RequestLoggingMiddleware<S> {
29  inner: S,
30}
31
32impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for RequestLoggingMiddleware<S>
33where
34  S: Service<Request<ReqBody>, Response = axum::response::Response<ResBody>> + Clone + Send + 'static,
35  S::Future: Send,
36  ReqBody: Send + 'static,
37  ResBody: Send + 'static,
38{
39  type Error = S::Error;
40  type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
41  type Response = S::Response;
42
43  fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
44    self.inner.poll_ready(cx)
45  }
46
47  fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
48    let method = req.method().clone();
49    let uri = req.uri().clone();
50    let start = Instant::now();
51
52    let mut inner = self.inner.clone();
53
54    Box::pin(async move {
55      let response = inner.call(req).await?;
56      let duration = start.elapsed();
57      let status = response.status();
58
59      if status.is_success() {
60        info!(
61          method = %method,
62          uri = %uri,
63          status = %status.as_u16(),
64          duration_ms = %duration.as_millis(),
65          "Request completed"
66        );
67      } else {
68        warn!(
69          method = %method,
70          uri = %uri,
71          status = %status.as_u16(),
72          duration_ms = %duration.as_millis(),
73          "Request failed"
74        );
75      }
76
77      Ok(response)
78    })
79  }
80}