Configurable, improved, middleware struct instead of function

This commit is contained in:
Michael Pfaff 2021-01-21 11:49:00 -05:00
parent ea1ed6fd70
commit 8a7353dc97
Signed by: michael
GPG Key ID: E53B118B12B5C7F9
3 changed files with 60 additions and 18 deletions

4
Cargo.lock generated
View File

@ -1364,8 +1364,10 @@ dependencies = [
[[package]]
name = "tide_tracing"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"async-trait",
"chrono",
"nrid",
"tide",
"tracing",

View File

@ -1,6 +1,6 @@
[package]
name = "tide_tracing"
version = "0.1.0"
version = "0.2.0"
authors = ["Michael Pfaff <michael@pfaff.dev>"]
edition = "2018"
@ -8,5 +8,7 @@ edition = "2018"
[dependencies]
nrid = { git = "https://git.pfaff.dev/michael/nrid.rs.git" }
tide = "0.15.0"
tracing = "0.1.15"
tide = { version = "0.15.0" }
tracing = { version = "0.1.15" }
async-trait = { version = "0.1.36" }
chrono = { version = "0.4.19" }

View File

@ -1,33 +1,71 @@
#[macro_use]
extern crate tracing;
use core::future::Future;
use core::pin::Pin;
use chrono::Utc;
use nrid::Nrid;
use std::time::Instant;
use tide::Middleware;
use tide::Next;
use tide::Request;
use tracing::Instrument;
use tracing::Level;
pub fn log_middleware<'a, State: 'static + Clone + Send + Sync>(
req: Request<State>,
next: Next<'a, State>,
) -> Pin<Box<dyn Future<Output = tide::Result> + Send + 'a>> {
Box::pin(async move {
let now = Instant::now();
#[derive(Debug, Clone)]
pub struct LogMiddleware {
include_ip: bool,
include_query: bool,
}
impl Default for LogMiddleware {
fn default() -> Self {
Self {
include_ip: false,
include_query: 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();
// doesn't take forwarding into account and includes useless socket port information
// let ip = req.peer_addr().unwrap_or("unknown").to_string();
let ip = req.remote().unwrap_or("unknown").to_string();
let span = span!(Level::ERROR, "Request", id = %id);
let res = async {
debug!(req.method = %req.method(), req.uri.path = uri.path(), req.uri.query = uri.query().unwrap_or(""), client_ip = %ip, received = ?now);
debug!(path = uri.path());
debug!(method = %req.method());
if self.include_query {
debug!(query = uri.query().unwrap_or(""));
}
if self.include_ip {
debug!(client_ip = %ip);
}
debug!(received = %start);
// debug!(method = %req.method(), query = uri.query().unwrap_or(""), client_ip = %ip, received = %start, "Request recieved");
let res = next.run(req).await;
debug!(status = %res.status(), elapsed = ?now.elapsed(), "Response");
let end = Utc::now();
let span = span!(Level::ERROR, "Response");
async {
debug!(status = %res.status());
debug!(duration = %end.signed_duration_since(start));
}.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
}
}