tide-tracing/src/lib.rs

91 lines
2.6 KiB
Rust

#[macro_use]
extern crate tracing;
use chrono::Utc;
use nrid::Nrid;
use tide::Middleware;
use tide::Next;
use tide::Request;
use tracing::Instrument;
use tracing::Level;
#[derive(Debug, Clone)]
pub struct LogMiddleware {
pub include_ip: bool,
pub include_query: bool,
pub multiline: bool,
}
impl Default for LogMiddleware {
fn default() -> Self {
Self {
include_ip: false,
include_query: false,
multiline: false,
}
}
}
impl LogMiddleware {
async fn log<'a, State: Clone + Send + Sync + 'static>(
&'a self,
req: Request<State>,
next: Next<'a, State>,
) -> tide::Result {
let start = Utc::now();
let id = Nrid::now();
let uri = req.url().clone();
let ip = req.remote().unwrap_or("unknown").to_string();
let span = span!(Level::ERROR, "Request", id = %id);
let res = async {
let path = uri.path();
let method = req.method();
let query = uri.query().unwrap_or("");
let received = start.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, false);
if self.multiline {
debug!(path = path);
debug!(method = %method);
if self.include_ip {
debug!(client_ip = %ip);
}
debug!(received = %received);
if self.include_query {
debug!(query = query);
}
} else {
debug!(path = path, method = %method, client_ip = %ip, received = %received, query = query);
}
// debug!(method = %req.method(), query = uri.query().unwrap_or(""), client_ip = %ip, received = %start, "Request recieved");
let res = next.run(req).await;
let end = Utc::now();
let span = span!(Level::ERROR, "Response");
async {
let status = res.status();
let duration = end.signed_duration_since(start).to_std().unwrap();
if self.multiline {
debug!(status = %status);
debug!(duration = ?duration);
} else {
debug!(status = %status, duration = ?duration);
}
}.instrument(span).await;
res
}.instrument(span).await;
Ok(res)
}
}
#[async_trait::async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for LogMiddleware {
async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide::Result {
self.log(req, next).await
}
}