use super::{ClientIp, LOG_TARGET};
use axum::extract::Request;
use axum::extract::State;
use axum::middleware::Next;
use axum::response::Response;
use scopeguard::defer;
use std::borrow::Cow;
use tibba_error::Error;
use tibba_state::{AppState, CTX};
use tibba_util::get_header_value;
use tracing::{debug, info};
use urlencoding::decode;
type Result<T> = std::result::Result<T, Error>;
pub async fn stats(
State(state): State<&AppState>,
ClientIp(ip): ClientIp,
req: Request,
next: Next,
) -> Result<Response> {
debug!(target: LOG_TARGET, "--> stats");
defer!(debug!(target: LOG_TARGET, "<-- stats"););
let uri_str = req.uri().to_string();
let uri: Cow<str> = decode(&uri_str).unwrap_or(Cow::from(&uri_str));
let method = req.method().clone();
let headers = req.headers();
let x_forwarded_for = get_header_value(headers, "X-Forwarded-For")
.unwrap_or_default()
.to_string();
let referrer = get_header_value(headers, "Referer")
.unwrap_or_default()
.to_string();
let user_agent = get_header_value(headers, "User-Agent")
.unwrap_or_default()
.to_string();
let res = next.run(req).await;
let status = res.status().as_u16();
let ctx = CTX.get();
let message = if status >= 400 {
res.extensions()
.get::<Error>()
.map(|err| err.message.clone())
} else {
None
};
info!(
target: LOG_TARGET,
device_id = ctx.device_id, trace_id = ctx.trace_id, account = %ctx.get_account(), ip = %ip, processing = state.get_processing(), x_forwarded_for, referrer, user_agent, method = %method, uri = uri.as_ref(), status, elapsed = ctx.elapsed_ms(), error = message, );
Ok(res)
}