use crate::extensions::HttpReqExt;
use crate::middleware::extract_remote_address;
use axum::middleware::Next;
use axum::response::IntoResponse;
use hyper::Request;
use tokio::time::Instant;
use tracing::{Level, Span};
const PROTOCOL_HTTP: &str = "http";
pub async fn trace_http_request<B>(
request: Request<B>,
next: Next<B>,
service_name: &str,
component_name: &str,
) -> impl IntoResponse {
let span = Span::current();
let req_method = request.method().to_string();
let remote_address = extract_remote_address(&request);
span.record("service", service_name);
span.record("component", component_name);
span.record("http.method", &req_method);
if let Some(addr) = remote_address {
span.record("net.peer.ip", addr.ip().to_string());
span.record("net.peer.port", addr.port());
}
let url = request
.uri()
.path_and_query()
.map_or_else(|| request.uri().path(), |p| p.as_str())
.to_owned();
tracing::info!(
method = &req_method,
url = &url,
">>> [Request] [{req_method}] [{url}]"
);
let duration = Instant::now();
let mut response = next.run(request).await;
let elapsed = duration.elapsed();
let duration = elapsed.as_millis();
let status = response.status();
span.record("http.status_code", status.as_str());
tracing::info!(
method = &req_method,
url = &url,
duration = duration,
statusCode = status.as_str(),
"[Response] <<< [{req_method}] [{url}] [{PROTOCOL_HTTP}] [{status}] in [{duration}ms]"
);
response.headers_mut().inject_from_current_span();
response
}
pub fn make_http_span() -> Span {
tracing::span!(
Level::INFO,
"http-request",
service = tracing::field::Empty,
component = tracing::field::Empty,
http.method = tracing::field::Empty,
http.status_code = tracing::field::Empty,
net.peer.ip = tracing::field::Empty,
net.peer.port = tracing::field::Empty,
trace.level = "INFO"
)
}