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