RTIX / src /core /logging.rs
github-actions
deploy: clean backend production release
d8ffec9
// Comprehensive request/response logging middleware
use axum::{extract::Request, middleware::Next, response::Response};
use std::time::Instant;
use uuid::Uuid;
use crate::interfaces::http::api::AppState;
/// Enhanced request logging with performance metrics
pub async fn request_response_logging_middleware(
axum::extract::State(_state): axum::extract::State<AppState>,
mut req: Request,
next: Next,
) -> Response {
let request_id = Uuid::new_v4().to_string();
let method = req.method().to_string();
let path = req.uri().path().to_string();
let query = req.uri().query().map(|q| q.to_string());
// Extract client IP
let client_ip = req
.headers()
.get("x-forwarded-for")
.and_then(|h| h.to_str().ok())
.unwrap_or("unknown")
.to_string();
// Log request start
tracing::info!(
request_id = %request_id,
method = %method,
path = %path,
client_ip = %client_ip,
query = ?query,
"Request started"
);
// Track timing
let start_time = Instant::now();
// Add request ID to extensions
req.extensions_mut().insert(request_id.clone());
// Call next middleware
let mut response = next.run(req).await;
let duration = start_time.elapsed();
let status = response.status();
let duration_ms = duration.as_millis() as u64;
// Log based on status and duration
let log_level = match (
status.is_client_error(),
status.is_server_error(),
duration_ms > 1000,
) {
(true, _, _) => "warn", // Client errors
(_, true, _) => "error", // Server errors
(_, _, true) => "warn", // Slow requests
_ => "info", // Normal requests
};
match log_level {
"error" => {
tracing::error!(
request_id = %request_id,
method = %method,
path = %path,
status = %status.as_u16(),
duration_ms = duration_ms,
"Request failed"
);
}
"warn" => {
tracing::warn!(
request_id = %request_id,
method = %method,
path = %path,
status = %status.as_u16(),
duration_ms = duration_ms,
"Request slow or error"
);
}
_ => {
tracing::info!(
request_id = %request_id,
method = %method,
path = %path,
status = %status.as_u16(),
duration_ms = duration_ms,
"Request completed"
);
}
}
// Add timing header
if let Ok(header_value) = axum::http::HeaderValue::from_str(&duration_ms.to_string()) {
response
.headers_mut()
.insert("x-response-time-ms", header_value);
}
response
}
#[cfg(test)]
mod tests {
#[test]
fn test_logging_levels() {
// Integration tests would verify logging output
// This is a placeholder for middleware verification
}
}