coa_website/
logger.rs

1use std::fs::{File, OpenOptions};
2use std::io::{Result as IoResult, Write};
3
4use chrono::{SecondsFormat, Utc};
5
6use crate::config::Config;
7
8/// Logger used to record HTTP request information into a log file.
9pub struct Logger {
10    file: File
11}
12
13impl Default for Logger {
14    fn default() -> Self {
15        Self::new(&Config::default().log_file.clone()).unwrap()
16    }
17}
18
19impl Logger {
20
21    /// Creates a new logger writing to the file at the given path.
22    ///
23    /// If the file does not exist, it is created. Otherwise, logs are appended.
24    ///
25    /// # Errors
26    /// Returns an error if the file cannot be opened or created.
27    pub fn new(path: &str) -> IoResult<Self> {
28        let file = OpenOptions::new().create(true).append(true).open(path)?;
29        Ok(Logger { file })
30    }
31
32    /// Logs a single HTTP request entry with client IP, method, path, and status code.
33    ///
34    /// # Example log line:
35    /// `[2025-04-16T14:25:42] 127.0.0.1 "GET /index.html" 200`
36    ///
37    /// # Errors
38    /// Returns an error if writing to the log file fails.
39    pub fn log(&mut self, ip: &str, method: &str, path: &str, status: u16) -> IoResult<()> {
40        let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true);
41        writeln!(
42            self.file,
43            "[{}] {} \"{} {}\" {}",
44            timestamp, ip, method, path, status
45        )
46    }
47
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use std::fs;
54
55    #[test]
56    fn test_logger_writes_line() {
57        let path = "test_log.log";
58        {
59            let mut logger = Logger::new(path).unwrap();
60            logger.log("127.0.0.1", "GET", "/test", 200).unwrap();
61        }
62        let content = fs::read_to_string(path).unwrap();
63        assert!(content.contains("127.0.0.1"));
64        assert!(content.contains("GET /test"));
65        assert!(content.contains("200"));
66        let _ = fs::remove_file(path);
67    }
68}