//! A line per HTTP request, as web servers log them: the method and path, the status, //! how long until the answer began (a stream, such as the dashboard's events, goes on //! after), where it came from, and the user. At debug, under the target `http` //! (`RUST_LOG=info,http=debug`, or `PUT /admin/log`): an open dashboard alone would //! fill the log at info. use axum::extract::{ConnectInfo, Request}; use axum::middleware::Next; use axum::response::Response; use tokio::time::Instant; use tracing::{Level, debug, enabled}; use super::auth::AuthenticatedUser; use super::listen::Peer; /// Outermost: what the layers inside answer too (a `401` included). The user comes back /// on the response (`auth::basic_auth`). pub(crate) async fn log_requests(request: Request, next: Next) -> Response { if !enabled!(target: "http", Level::DEBUG) { return next.run(request).await; } let method = request.method().clone(); let path = request .uri() .path_and_query() .map_or_else(|| request.uri().path().to_owned(), ToString::to_string); let from = match request.extensions().get::>() { Some(ConnectInfo(Peer::Tcp(address))) => address.to_string(), Some(ConnectInfo(Peer::Unix)) => "unix".to_owned(), None => "-".to_owned(), }; let started = Instant::now(); let response = next.run(request).await; let user = response .extensions() .get::() .map_or("-", |AuthenticatedUser(user)| user.as_str()); debug!( target: "http", method = %method, path = %path, status = response.status().as_u16(), ms = started.elapsed().as_millis(), from = %from, user = %user, "HTTP request" ); response }