diff --git a/Cargo.lock b/Cargo.lock index 9de2ed0..e4150ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1130,6 +1130,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", + "uuid", ] [[package]] @@ -1301,6 +1302,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "uuid" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" +dependencies = [ + "getrandom", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a7b537e..7f97bd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ tokio = {version = "1", features = ["rt-multi-thread"]} dotenvy = "0.15" tracing = "0.1" tracing-subscriber = {version = "0.3", features = ["env-filter"]} -tower-http = {version = "0.4", features = ["trace", "cors", "sensitive-headers"]} +tower-http = {version = "0.4", features = ["trace", "cors", "sensitive-headers", "request-id"]} hyper = {version = "0.14", features = ["client"]} http = "0.2" async-tungstenite = {version = "0.21", features = ["tokio-runtime"]} diff --git a/src/handler.rs b/src/handler.rs index 5f9a59a..decdc79 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -20,20 +20,24 @@ use base64::Engine; use futures::{SinkExt, StreamExt}; use http::{ header::{AUTHORIZATION, CACHE_CONTROL, CONTENT_TYPE}, - HeaderValue, Method, Request, Response, StatusCode, + HeaderName, HeaderValue, Method, Request, Response, StatusCode, }; use hyper::Body; use serde::{Deserialize, Serialize}; use serde_json::Value; use tokio::net::TcpStream; use tower_http::{ - cors::CorsLayer, sensitive_headers::SetSensitiveRequestHeadersLayer, trace::TraceLayer, + cors::CorsLayer, + request_id::{MakeRequestUuid, SetRequestIdLayer}, + sensitive_headers::SetSensitiveRequestHeadersLayer, + trace::TraceLayer, }; use tracing::{Instrument, Span}; use crate::{AppState, B64}; const AUDIO_CACHE_HEADER: HeaderValue = HeaderValue::from_static("private, max-age=604800"); +const REQUEST_ID: HeaderName = HeaderName::from_static("x-request-id"); #[derive(Deserialize)] struct Auth { @@ -73,18 +77,32 @@ fn make_span_trace(req: &Request) -> Span { query_map.insert("token", ""); } let query_display = QueryDisplay { map: query_map }; + + let request_id = req + .headers() + .get(REQUEST_ID) + .and_then(|v| v.to_str().ok()) + .unwrap_or("no id set"); + tracing::debug_span!( "request", method = %req.method(), path = %req.uri().path(), query = %query_display, version = ?req.version(), - headers = ?req.headers(), + id = %request_id, ) } pub(super) async fn handler(state: AppState) -> Result<(Router, Router), AppError> { - let trace_layer = TraceLayer::new_for_http().make_span_with(make_span_trace); + let trace_layer = TraceLayer::new_for_http() + .make_span_with(make_span_trace) + .on_request(|req: &Request, _span: &Span| { + tracing::debug!( + "started processing request with headers: {:#?}", + req.headers() + ) + }); let internal_router = Router::new() .route("/token/generate", get(generate_token)) @@ -97,12 +115,13 @@ pub(super) async fn handler(state: AppState) -> Result<(Router, Router), AppErro .route("/audio/external_id/:id", get(get_music)) .route("/audio/scoped/:id", get(get_scoped_music)) .route("/", get(metadata_ws)) + .layer(SetRequestIdLayer::new(REQUEST_ID.clone(), MakeRequestUuid)) .layer(SetSensitiveRequestHeadersLayer::new([AUTHORIZATION])) .layer(trace_layer) .layer( CorsLayer::new() .allow_origin(tower_http::cors::Any) - .allow_headers([CONTENT_TYPE]) + .allow_headers([CONTENT_TYPE, CACHE_CONTROL, REQUEST_ID]) .allow_methods([Method::GET]), ) .with_state(state);