// 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, 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 } }