1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
//! 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::<ConnectInfo<Peer>>() {
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::<AuthenticatedUser>()
.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
}
|