From 1e47090f5d55e0e3ed17d895526fff6b1112bbff Mon Sep 17 00:00:00 2001 From: timedout Date: Sun, 12 Jul 2026 15:42:50 +0100 Subject: [PATCH] feat: Log client IP in router layer --- src/router/layers.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/router/layers.rs b/src/router/layers.rs index 0d2ed6d43..bde1d5cca 100644 --- a/src/router/layers.rs +++ b/src/router/layers.rs @@ -1,10 +1,10 @@ use std::{any::Any, sync::Arc, time::Duration}; use axum::{ - Router, - extract::{DefaultBodyLimit, MatchedPath}, + Router, extract, + extract::{DefaultBodyLimit, FromRequestParts, MatchedPath}, }; -use axum_client_ip::ClientIpSource; +use axum_client_ip::{ClientIp, ClientIpSource}; use conduwuit::{Result, Server, debug, error}; use conduwuit_service::{Services, state::Guard}; use http::{ @@ -20,7 +20,6 @@ use tower_http::{ timeout::{RequestBodyTimeoutLayer, ResponseBodyTimeoutLayer, TimeoutLayer}, trace::{DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, TraceLayer}, }; -use tracing::Level; use crate::{request, router}; @@ -67,15 +66,16 @@ pub(crate) fn build(services: &Arc) -> Result<(Router, Guard)> { let services_ = services.clone(); let layers = layers .layer(SetSensitiveHeadersLayer::new([header::AUTHORIZATION])) + .layer(client_ip_layer.into_extension()) .layer( TraceLayer::new_for_http() .make_span_with(tracing_span::<_>) - .on_failure(DefaultOnFailure::new().level(Level::ERROR)) - .on_request(DefaultOnRequest::new().level(Level::TRACE)) - .on_response(DefaultOnResponse::new().level(Level::DEBUG)), + .on_failure(DefaultOnFailure::new().level(tracing::Level::ERROR)) + .on_request(DefaultOnRequest::new().level(tracing::Level::TRACE)) + .on_response(DefaultOnResponse::new().level(tracing::Level::DEBUG)), ) + .layer(axum::middleware::from_fn(request_ip)) .layer(axum::middleware::from_fn_with_state(Arc::clone(services), request::handle)) - .layer(client_ip_layer.into_extension()) .layer(ResponseBodyTimeoutLayer::new(Duration::from_secs( server.config.client_response_timeout, ))) @@ -230,11 +230,25 @@ fn tracing_span(request: &http::Request) -> tracing::Span { parent: None, debug::INFO_SPAN_LEVEL, "router", + ip=tracing::field::Empty, method = %request.method(), %path, } } +/// Annotates the tracing span with the client IP +async fn request_ip( + request: extract::Request, + next: axum::middleware::Next, +) -> axum::response::Response { + let (mut parts, body) = request.into_parts(); + if let Ok(ip) = ClientIp::from_request_parts(&mut parts, &()).await { + let span = tracing::Span::current(); + span.record("ip", ip.0.to_string()); + } + next.run(extract::Request::from_parts(parts, body)).await +} + fn request_path_str(request: &http::Request) -> &str { request .uri()