73 lines
2.2 KiB
Rust
73 lines
2.2 KiB
Rust
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
use axum::{
|
|
extract::{ConnectInfo, MatchedPath, Request},
|
|
middleware::Next,
|
|
response::Response,
|
|
};
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
use std::net::SocketAddr;
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
use tracing::field;
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
fn first_forwarded_for(req: &Request) -> Option<String> {
|
|
let raw = req.headers().get("x-forwarded-for")?.to_str().ok()?;
|
|
raw.split(',')
|
|
.next()
|
|
.map(|s| s.trim())
|
|
.filter(|s| !s.is_empty())
|
|
.map(|s| s.to_string())
|
|
}
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
fn connect_info_ip(req: &Request) -> Option<String> {
|
|
req.extensions()
|
|
.get::<ConnectInfo<SocketAddr>>()
|
|
.map(|ci| ci.0.ip().to_string())
|
|
}
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
fn matched_route(req: &Request) -> Option<String> {
|
|
req.extensions()
|
|
.get::<MatchedPath>()
|
|
.map(|m| m.as_str().to_string())
|
|
}
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
fn request_id(req: &Request) -> Option<String> {
|
|
req.headers()
|
|
.get("x-request-id")
|
|
.and_then(|v| v.to_str().ok())
|
|
.map(|s| s.to_string())
|
|
}
|
|
|
|
#[cfg(all(feature = "response", feature = "telemetry"))]
|
|
pub async fn trace_http_request(req: Request, next: Next) -> Response {
|
|
let method = req.method().to_string();
|
|
let path = req.uri().path().to_string();
|
|
let route = matched_route(&req).unwrap_or_else(|| path.clone());
|
|
let client_ip = first_forwarded_for(&req).or_else(|| connect_info_ip(&req));
|
|
let req_id = request_id(&req);
|
|
|
|
let span = tracing::info_span!(
|
|
"http.request",
|
|
http.method = %method,
|
|
http.path = %path,
|
|
http.route = %route,
|
|
client.ip = %client_ip.clone().unwrap_or_else(|| "unknown".into()),
|
|
request_id = %req_id.clone().unwrap_or_else(|| "unknown".into()),
|
|
tenant_id = field::Empty,
|
|
user_id = field::Empty,
|
|
status = field::Empty,
|
|
);
|
|
|
|
let _guard = span.enter();
|
|
let resp = next.run(req).await;
|
|
let status = resp.status().as_u16();
|
|
tracing::Span::current().record("status", status);
|
|
resp
|
|
}
|
|
|