use crate::{config::AccessLogConfig, error::ServiceError, FilterRequest, State}; use futures::executor::block_on; use log::error; use std::{net::SocketAddr, ops::ControlFlow, time::SystemTime}; use tokio::{ fs::OpenOptions, io::{AsyncWriteExt, BufWriter}, }; pub async fn access_log( state: &State, host: &str, addr: SocketAddr, config: &AccessLogConfig, req: &FilterRequest, ) -> Result, ServiceError> { let mut g = state.access_logs.write().await; let log = g.entry(host.to_owned()).or_insert_with(|| { BufWriter::new( // TODO aaahh dont block the runtime and dont panic in any case.... block_on( OpenOptions::new() .append(true) .create(true) .open(&config.file), ) .unwrap(), ) }); let method = req.method().as_str(); let time = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_micros(); let mut res = log .write_all(format!("{time}\t{addr}\t{method}\t{:?}\n", req.uri()).as_bytes()) .await; if config.flush && res.is_ok() { res = log.flush().await; } if config.reject_on_fail { res? } else if let Err(e) = res { error!("failed to write log: {e:?}") } Ok(ControlFlow::Continue(())) }