git_iris/
logger.rs

1#![allow(clippy::unwrap_used)] // todo: remove unwrap by using parking_lot to handle mutex
2use chrono::Local;
3use log::{Level, LevelFilter, Metadata, Record};
4use once_cell::sync::Lazy;
5use std::fs::OpenOptions;
6use std::io::Write;
7use std::sync::Mutex;
8
9struct GitIrisLogger;
10
11static LOGGER: GitIrisLogger = GitIrisLogger;
12static LOGGING_ENABLED: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
13static LOG_FILE: Lazy<Mutex<Option<std::fs::File>>> = Lazy::new(|| Mutex::new(None));
14static LOG_TO_STDOUT: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
15
16impl log::Log for GitIrisLogger {
17    fn enabled(&self, metadata: &Metadata) -> bool {
18        *LOGGING_ENABLED.lock().unwrap() && metadata.level() <= Level::Debug
19    }
20
21    fn log(&self, record: &Record) {
22        if self.enabled(record.metadata()) {
23            let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
24            let message = format!("{} {} - {}\n", timestamp, record.level(), record.args());
25
26            if let Some(file) = LOG_FILE.lock().unwrap().as_mut() {
27                let _ = file.write_all(message.as_bytes());
28                let _ = file.flush();
29            }
30
31            if *LOG_TO_STDOUT.lock().unwrap() {
32                print!("{message}");
33            }
34        }
35    }
36
37    fn flush(&self) {}
38}
39
40pub fn init() -> Result<(), log::SetLoggerError> {
41    log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Debug))
42}
43
44pub fn enable_logging() {
45    let mut logging_enabled = LOGGING_ENABLED.lock().unwrap();
46    *logging_enabled = true;
47}
48
49pub fn disable_logging() {
50    let mut logging_enabled = LOGGING_ENABLED.lock().unwrap();
51    *logging_enabled = false;
52}
53
54pub fn set_log_file(file_path: &str) -> std::io::Result<()> {
55    let file = OpenOptions::new()
56        .create(true)
57        .append(true)
58        .open(file_path)?;
59
60    let mut log_file = LOG_FILE.lock().unwrap();
61    *log_file = Some(file);
62    Ok(())
63}
64
65pub fn set_log_to_stdout(enabled: bool) {
66    let mut log_to_stdout = LOG_TO_STDOUT.lock().unwrap();
67    *log_to_stdout = enabled;
68}
69
70#[macro_export]
71macro_rules! log_debug {
72    ($($arg:tt)*) => {
73        log::debug!($($arg)*)
74    };
75}
76
77#[macro_export]
78macro_rules! log_error {
79    ($($arg:tt)*) => {
80        log::error!($($arg)*)
81    };
82}