Implement configurable logging with tracing

- Replace eprintln! with tracing macros for configurable log levels
- Set up tracing_subscriber with level filtering from config
- Log format: YYYY-MM-DDTHH:MM:SSZ LEVEL IP "request" STATUS "message"
- Success logs: INFO level for 20 responses
- Error logs: WARN for 41/51, ERROR for 59
- Rate limiting and file serving now properly logged
- Remove unused RequestLogger::log_success method
This commit is contained in:
Jeena 2026-01-16 11:19:20 +00:00
parent 33ae576b25
commit 3865211554
3 changed files with 50 additions and 13 deletions

View file

@ -16,12 +16,20 @@ impl RequestLogger {
} }
} }
pub fn log_success(self, status_code: u8) {
println!("{} \"{}\" {}", self.client_ip, self.request_url, status_code);
}
pub fn log_error(self, status_code: u8, error_message: &str) { pub fn log_error(self, status_code: u8, error_message: &str) {
eprintln!("{} \"{}\" {} \"{}\"", self.client_ip, self.request_url, status_code, error_message); let level = match status_code {
41 | 51 => tracing::Level::WARN,
59 => tracing::Level::ERROR,
_ => tracing::Level::ERROR,
};
match level {
tracing::Level::WARN => tracing::warn!("{} \"{}\" {} \"{}\"", self.client_ip, self.request_url, status_code, error_message),
tracing::Level::ERROR => tracing::error!("{} \"{}\" {} \"{}\"", self.client_ip, self.request_url, status_code, error_message),
_ => {}
}
} }
@ -35,8 +43,28 @@ fn extract_client_ip(stream: &TlsStream<TcpStream>) -> String {
} }
} }
pub fn init_logging(_level: &str) { pub fn init_logging(level: &str) {
// Simple logging using stdout/stderr - systemd will capture this use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
let level = match level.to_lowercase().as_str() {
"error" => tracing::Level::ERROR,
"warn" => tracing::Level::WARN,
"info" => tracing::Level::INFO,
"debug" => tracing::Level::DEBUG,
"trace" => tracing::Level::TRACE,
_ => {
eprintln!("Warning: Invalid log level '{}', defaulting to 'info'", level);
tracing::Level::INFO
}
};
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer()
.compact()
.with_target(false)
.with_thread_ids(false))
.with(tracing_subscriber::filter::LevelFilter::from_level(level))
.init();
} }
#[cfg(test)] #[cfg(test)]

View file

@ -131,6 +131,7 @@ async fn main() {
loop { loop {
let (stream, _) = listener.accept().await.unwrap(); let (stream, _) = listener.accept().await.unwrap();
tracing::debug!("Accepted connection from {}", stream.peer_addr().unwrap_or_else(|_| "unknown".parse().unwrap()));
let acceptor = acceptor.clone(); let acceptor = acceptor.clone();
let dir = root.clone(); let dir = root.clone();
let expected_host = "localhost".to_string(); // Override for testing let expected_host = "localhost".to_string(); // Override for testing

View file

@ -17,10 +17,17 @@ pub async fn serve_file(
) -> io::Result<()> { ) -> io::Result<()> {
if file_path.exists() && file_path.is_file() { if file_path.exists() && file_path.is_file() {
let mime_type = get_mime_type(file_path); let mime_type = get_mime_type(file_path);
let header = format!("20 {}\r\n", mime_type);
stream.write_all(header.as_bytes()).await?;
// Log success after sending header
let client_ip = match stream.get_ref().0.peer_addr() {
Ok(addr) => addr.to_string(),
Err(_) => "unknown".to_string(),
};
tracing::info!("{} \"file:{}\" 20 \"Success\"", client_ip, file_path.display());
// Then send body
let content = fs::read(file_path)?; let content = fs::read(file_path)?;
let mut response = format!("20 {}\r\n", mime_type).into_bytes(); stream.write_all(&content).await?;
response.extend(content);
stream.write_all(&response).await?;
stream.flush().await?; stream.flush().await?;
Ok(()) Ok(())
} else { } else {
@ -118,10 +125,12 @@ pub async fn handle_connection(
// Serve the file // Serve the file
match serve_file(&mut stream, &file_path).await { match serve_file(&mut stream, &file_path).await {
Ok(_) => logger.log_success(20), Ok(_) => {
// Success already logged in serve_file
}
Err(_) => { Err(_) => {
// This shouldn't happen since we check existence, but handle gracefully // File transmission failed
logger.log_error(51, "File not found"); logger.log_error(51, "File transmission failed");
let _ = send_response(&mut stream, "51 Not found\r\n").await; let _ = send_response(&mut stream, "51 Not found\r\n").await;
} }
} }
@ -155,7 +164,6 @@ pub async fn handle_connection(
} }
ACTIVE_REQUESTS.fetch_sub(1, Ordering::Relaxed); ACTIVE_REQUESTS.fetch_sub(1, Ordering::Relaxed);
eprintln!("DEBUG: Request completed, count decremented");
Ok(()) Ok(())
} }