1use std::time::Instant;
25
26use tracing::{Instrument, Level};
27
28use salvo_core::http::{Request, ResBody, Response, StatusCode};
29use salvo_core::{Depot, FlowCtrl, Handler, async_trait};
30
31#[derive(Default, Debug)]
33pub struct Logger {
34 pub log_status_error: bool,
41}
42impl Logger {
43 #[inline]
45 #[must_use]
46 pub fn new() -> Self {
47 Self {
48 log_status_error: true,
49 }
50 }
51
52 #[must_use]
57 pub fn log_status_error(mut self, log_status_error: bool) -> Self {
58 self.log_status_error = log_status_error;
59 self
60 }
61}
62
63#[async_trait]
64impl Handler for Logger {
65 async fn handle(
66 &self,
67 req: &mut Request,
68 depot: &mut Depot,
69 res: &mut Response,
70 ctrl: &mut FlowCtrl,
71 ) {
72 let span = tracing::span!(
73 Level::INFO,
74 "Request",
75 remote_addr = %req.remote_addr().to_string(),
76 version = ?req.version(),
77 method = %req.method(),
78 path = %req.uri(),
79 );
80
81 async move {
82 let now = Instant::now();
83 ctrl.call_next(req, depot, res).await;
84 let duration = now.elapsed();
85
86 let status = res.status_code.unwrap_or(match &res.body {
87 ResBody::None => StatusCode::NOT_FOUND,
88 ResBody::Error(e) => e.code,
89 _ => StatusCode::OK,
90 });
91 if let ResBody::Error(error) = &res.body {
92 tracing::info!(
93 %status,
94 ?duration,
95 ?error,
96 "Response"
97 );
98 } else {
99 tracing::info!(
100 %status,
101 ?duration,
102 "Response"
103 );
104 }
105 }
106 .instrument(span)
107 .await
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use salvo_core::prelude::*;
114 use salvo_core::test::{ResponseExt, TestClient};
115 use tracing_test::traced_test;
116
117 use super::*;
118
119 #[tokio::test]
120 #[traced_test]
121 async fn test_log() {
122 #[handler]
123 async fn hello() -> &'static str {
124 "hello"
125 }
126
127 let router = Router::new()
128 .hoop(Logger::new())
129 .push(Router::with_path("hello").get(hello));
130
131 TestClient::get("http://127.0.0.1:5801/hello")
132 .send(router)
133 .await
134 .take_string()
135 .await
136 .unwrap();
137 assert!(logs_contain("duration"));
138 }
139}