astro_run_logger/
lib.rs

1use colored::Colorize;
2use log::Level;
3use std::{env, str::FromStr, sync::OnceLock};
4
5#[derive(Clone)]
6pub struct Logger {
7  level: log::Level,
8}
9
10impl Logger {
11  pub fn new(level: log::Level) -> Self {
12    Self { level }
13  }
14}
15
16impl log::Log for Logger {
17  fn enabled(&self, metadata: &log::Metadata) -> bool {
18    metadata.level() <= self.level
19  }
20
21  fn log(&self, record: &log::Record) {
22    if !self.enabled(record.metadata()) {
23      return;
24    }
25
26    let time = chrono::Local::now()
27      .format("%Y-%m-%d %H:%M:%S")
28      .to_string()
29      .magenta();
30
31    let level = match record.level() {
32      Level::Error => "ERROR".red(),
33      Level::Warn => "WARN".yellow(),
34      Level::Info => "INFO".green(),
35      Level::Debug => "DEBUG".green(),
36      Level::Trace => "TRACE".green(),
37    };
38
39    let prefix = match (record.module_path(), record.line()) {
40      (Some(module_path), Some(line)) => format!("{}:{}", module_path, line).cyan(),
41      (Some(module_path), None) => module_path.cyan(),
42      _ => "".cyan(),
43    };
44
45    let log = format!("{} {} {} {}", time, prefix, level, record.args());
46    println!("{}", log);
47  }
48
49  fn flush(&self) {}
50}
51
52static LOGGER: OnceLock<()> = OnceLock::new();
53
54pub fn init_logger() {
55  if LOGGER.get().is_some() {
56    return;
57  }
58
59  LOGGER.get_or_init(|| {
60    let level = env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string());
61    let level = log::Level::from_str(&level).unwrap_or(log::Level::Info);
62
63    let logger = Logger::new(level.clone());
64    log::set_logger(Box::leak(Box::new(logger))).unwrap();
65    log::set_max_level(level.to_level_filter());
66  });
67}
68
69pub fn init_logger_with_level(level: log::Level) {
70  if LOGGER.get().is_some() {
71    return;
72  }
73
74  LOGGER.get_or_init(|| {
75    let logger = Logger::new(level.clone());
76    log::set_logger(Box::leak(Box::new(logger))).unwrap();
77    log::set_max_level(level.to_level_filter());
78  });
79}
80
81#[cfg(test)]
82mod tests {
83  use super::*;
84
85  #[test]
86  fn test() {
87    init_logger();
88    log::info!("Hello, world!");
89    log::warn!("Hello, world!");
90    log::error!("Hello, world!");
91    log::debug!("Hello, world!");
92    log::trace!("Hello, world!");
93  }
94
95  #[test]
96  fn test_with_env() {
97    env::set_var("RUST_LOG", "debug");
98    init_logger();
99    log::info!("Hello, world!");
100    log::warn!("Hello, world!");
101    log::error!("Hello, world!");
102    log::debug!("Hello, world!");
103    log::trace!("Hello, world!");
104    env::remove_var("RUST_LOG");
105  }
106
107  #[test]
108  fn test_with_level_debug() {
109    init_logger_with_level(log::Level::Trace);
110    log::info!("Hello, world!");
111    log::warn!("Hello, world!");
112    log::error!("Hello, world!");
113    log::debug!("Hello, world!");
114    log::trace!("Hello, world!");
115  }
116}