Files
Notes/notes-service/vendor/axum-client-ip/examples/tracing.rs
T
2026-08-01 16:11:49 +03:00

77 lines
2.5 KiB
Rust

//! An example of integration with Tracing
use std::net::SocketAddr;
use axum::{
Router,
extract::{self, FromRequestParts},
http::{self},
middleware::{self, Next},
routing::get,
};
use axum_client_ip::{ClientIp, ClientIpSource};
use tokio::net::TcpListener;
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;
use tracing::{Span, info, info_span, level_filters::LevelFilter};
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::TRACE.into())
.from_env_lossy(),
)
.with(fmt::layer())
.init();
let app = Router::new()
.route(
"/",
get(async || {
info!("hi");
"Hello, World!"
}),
)
.layer(
ServiceBuilder::new()
// Hardcode IP source, look into `examples/configurable.rs` for runtime
// configuration
.layer(ClientIpSource::ConnectInfo.into_extension())
// Create a request span with a placeholder for IP
.layer(
TraceLayer::new_for_http().make_span_with(|request: &http::Request<_>| {
info_span!(
"request",
method = %request.method(),
uri = %request.uri(),
ip = tracing::field::Empty
)
}),
)
// Extract IP and fill the span placeholder
.layer(middleware::from_fn(
async |request: extract::Request, next: Next| {
let (mut parts, body) = request.into_parts();
if let Ok(ip) = ClientIp::from_request_parts(&mut parts, &()).await {
let span = Span::current();
span.record("ip", ip.0.to_string());
}
next.run(extract::Request::from_parts(parts, body)).await
},
)),
);
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
let listener = TcpListener::bind(&addr).await.unwrap();
println!("Listening on http://localhost:3000/");
axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await
.unwrap()
}