feat(telemetry): add axum_middleware
This commit is contained in:
72
src/axum_middleware.rs
Normal file
72
src/axum_middleware.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
#[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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user