xitca_http/util/middleware/
logger.rs

1use tracing::Level;
2use xitca_service::Service;
3
4/// a builder for logger service.
5#[derive(Clone)]
6pub struct Logger {
7    level: Level,
8}
9
10impl Default for Logger {
11    fn default() -> Self {
12        Self::new()
13    }
14}
15
16impl Logger {
17    /// construct a default logger with [`Level::WARN`]
18    pub fn new() -> Self {
19        Self::with_level(Level::WARN)
20    }
21
22    /// construct a logger with given [`Level`] verbosity.
23    pub fn with_level(level: Level) -> Self {
24        Self { level }
25    }
26}
27
28impl<S, E> Service<Result<S, E>> for Logger {
29    type Response = service::LoggerService<S>;
30    type Error = E;
31
32    async fn call(&self, res: Result<S, E>) -> Result<Self::Response, Self::Error> {
33        res.map(|service| service::LoggerService {
34            service,
35            level: self.level,
36        })
37    }
38}
39
40mod service {
41    use std::error;
42
43    use tracing::{Instrument, event, span};
44    use xitca_service::ready::ReadyService;
45
46    use crate::http::{BorrowReq, Method, Uri, header::HeaderMap};
47
48    use super::*;
49
50    pub struct LoggerService<S> {
51        pub(super) service: S,
52        pub(super) level: Level,
53    }
54
55    impl<S, Req> Service<Req> for LoggerService<S>
56    where
57        S: Service<Req>,
58        Req: BorrowReq<Method> + BorrowReq<Uri> + BorrowReq<HeaderMap>,
59        S::Error: error::Error,
60    {
61        type Response = S::Response;
62        type Error = S::Error;
63
64        #[inline]
65        async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
66            let method: &Method = req.borrow();
67            let uri: &Uri = req.borrow();
68
69            macro_rules! span2 {
70                ($lvl:expr, $name:expr, $($fields:tt)*) => {
71                    match $lvl {
72                        Level::TRACE => span!(Level::TRACE, $name, $($fields)*),
73                        Level::DEBUG => span!(Level::DEBUG, $name, $($fields)*),
74                        Level::INFO => span!(Level::INFO, $name, $($fields)*),
75                        Level::WARN => span!(Level::WARN, $name, $($fields)*),
76                        Level::ERROR => span!(Level::ERROR, $name, $($fields)*),
77                    }
78                }
79            }
80
81            let span = span2!(
82                self.level,
83                "request",
84                method = %method,
85                uri = %uri
86            );
87
88            async {
89                event!(target: "on_request", Level::INFO, "serving request");
90                match self.service.call(req).await {
91                    Ok(res) => {
92                        event!(target: "on_response", Level::INFO, "sending response");
93                        Ok(res)
94                    }
95                    Err(e) => {
96                        event!(target: "on_error", Level::WARN, "{}", e);
97                        Err(e)
98                    }
99                }
100            }
101            .instrument(span)
102            .await
103        }
104    }
105
106    impl<S> ReadyService for LoggerService<S>
107    where
108        S: ReadyService,
109    {
110        type Ready = S::Ready;
111
112        #[inline]
113        async fn ready(&self) -> Self::Ready {
114            self.service.ready().await
115        }
116    }
117}