diff --git a/Cargo.lock b/Cargo.lock index d4817f007..390092b6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1776,6 +1776,7 @@ dependencies = [ "ffmpeg-next", "fs_extra", "futures-util", + "http-body-util", "image", "libc", "log", @@ -3499,9 +3500,9 @@ checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" diff --git a/Cargo.toml b/Cargo.toml index c31128815..6aeeb95f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ tokio = { workspace = true } axum = { version = "0.7.4", features = ["ws"] } futures-util = { workspace = true } wgpu = { workspace = true } +http-body-util = "0.1.2" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] shared_memory = { workspace = true } diff --git a/src/lib.rs b/src/lib.rs index 2ea0aa31b..f24d5211f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod config; pub mod logger; +pub mod middleware; pub mod routes; pub mod server; pub mod state; diff --git a/src/main.rs b/src/main.rs index 4a5104783..c463d9312 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use log::info; mod config; mod logger; +mod middleware; mod routes; mod server; mod state; diff --git a/src/middleware.rs b/src/middleware.rs new file mode 100644 index 000000000..d19f1f8d4 --- /dev/null +++ b/src/middleware.rs @@ -0,0 +1,77 @@ +use axum::{ + body::Body, + extract::Request, + http::StatusCode, + middleware::Next, + response::{IntoResponse, Response}, +}; +use core::str; +use http_body_util::BodyExt; +use serde_json::Value; +use tracing::{enabled, trace, Level}; + +pub async fn body_logger_middleware( + request: Request, + next: Next, +) -> Result { + if !enabled!(target: "live_compositor::log_request_body", Level::TRACE) { + return Ok(next.run(request).await); + } + let request = buffer_request_body(request).await?; + let response = next.run(request).await; + let response = buffer_response_body(response).await?; + + Ok(response) +} + +async fn buffer_request_body(request: Request) -> Result { + let (parts, body) = request.into_parts(); + + let bytes = body + .collect() + .await + .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())? + .to_bytes(); + + match serde_json::from_slice::(&bytes) { + Ok(body_json) => { + trace!(target: "live_compositor::log_request_body", method = ?parts.method, path = ?parts.uri, "Request body: {}", body_json); + } + Err(_) => match str::from_utf8(&bytes) { + Ok(body_str) => { + trace!(target: "live_compositor::log_request_body", method = ?parts.method, path = ?parts.uri, "Request body: {}", body_str); + } + Err(_) => { + trace!(target: "live_compositor::log_request_body", method = ?parts.method, path = ?parts.uri, "Request body: {:?}", bytes); + } + }, + } + + Ok(Request::from_parts(parts, Body::from(bytes))) +} + +async fn buffer_response_body(response: Response) -> Result { + let (parts, body) = response.into_parts(); + + let bytes = body + .collect() + .await + .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())? + .to_bytes(); + + match serde_json::from_slice::(&bytes) { + Ok(body_json) => { + trace!(target: "live_compositor::log_request_body", status=?parts.status, "Response body: {}", body_json); + } + Err(_) => match str::from_utf8(&bytes) { + Ok(body_str) => { + trace!(target: "live_compositor::log_request_body", status=?parts.status, "Response body: {}", body_str); + } + Err(_) => { + trace!(target: "live_compositor::log_request_body", status=?parts.status, "Response body: {:?}", bytes); + } + }, + } + + Ok(Response::from_parts(parts, Body::from(bytes))) +} diff --git a/src/routes.rs b/src/routes.rs index b88e3d1c3..6a41f3568 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -2,6 +2,7 @@ use axum::{ async_trait, extract::{rejection::JsonRejection, ws::WebSocketUpgrade, FromRequest, Request, State}, http::StatusCode, + middleware, response::IntoResponse, routing::{get, post}, Router, @@ -17,6 +18,7 @@ use self::{ update_output::handle_keyframe_request, update_output::handle_output_update, ws::handle_ws_upgrade, }; +use crate::middleware::body_logger_middleware; mod register_request; mod unregister_request; @@ -75,6 +77,7 @@ pub fn routes(state: ApiState) -> Router { "instance_id": state.config.instance_id }))), ) + .layer(middleware::from_fn(body_logger_middleware)) .with_state(state) }