1use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError};
2
3#[allow(dead_code)]
4static DEFAULT_BG_RED_TEXT: &str = "\x1b[31m";
5#[allow(dead_code)]
6static DEFAULT_BG_GREEN_TEXT: &str = "\x1b[32m";
7#[allow(dead_code)]
8static DEFAULT_BG_YELLOW_TEXT: &str = "\x1b[33m";
9#[allow(dead_code)]
10static DEFAULT_BG_BLUE_TEXT: &str = "\x1b[34m";
11static DEFAULT_BG_GRAY_TEXT: &str = "\x1b[90m";
12
13static RED_BG_BLACK_TEXT: &str = "\x1b[41;30m";
14static YELLOW_BG_BLACK_TEXT: &str = "\x1b[43;30m";
15static BLUE_BG_WHITE_TEXT: &str = "\x1b[44;37m";
16static GREEN_BG_BLACK_TEXT: &str = "\x1b[42;30m";
17static CYAN_BG_BLACK_TEXT: &str = "\x1b[46;30m";
18static DEFAULT_BG_DEFAULT_TEXT: &str = "\x1b[49;39m";
19
20pub extern crate log;
21
22#[cfg(not(feature = "tracing"))]
23static LOGGER: XanLogger = XanLogger {
24 log_level: LevelFilter::Off,
25};
26
27pub struct XanLogger {
28 log_level: LevelFilter,
29}
30
31impl XanLogger {
32 pub fn new(log_level: LevelFilter) -> Self {
33 Self { log_level }
34 }
35}
36
37impl Log for XanLogger {
38 fn enabled(&self, metadata: &Metadata) -> bool {
39 metadata.level() <= self.log_level
40 }
41
42 fn log(&self, r: &Record) {
43 let metadata = r.metadata();
44 let args = r.args();
45 let module_path = r.module_path();
46 let file = r.file();
47 let line = r.line();
48 let kv = r.key_values();
49 println!(
50 "[{}] [{}@{}:{}] [target:{}] [module_path:{}] {}",
51 chrono::Utc::now()
52 .format("%Y-%m-%dT%H:%M:%S.%3fZ")
53 .to_string(),
54 if let Some(lv) = kv.get("level".into()) {
55 format!(
56 "{}{}{}",
57 CYAN_BG_BLACK_TEXT,
58 lv.to_string().to_uppercase(),
59 DEFAULT_BG_DEFAULT_TEXT
60 )
61 } else {
62 match metadata.level() {
63 Level::Error => {
64 format!("{}ERROR{}", RED_BG_BLACK_TEXT, DEFAULT_BG_DEFAULT_TEXT)
65 }
66 Level::Warn => {
67 format!("{}WARN{}", YELLOW_BG_BLACK_TEXT, DEFAULT_BG_DEFAULT_TEXT)
68 }
69 Level::Info => format!("{}INFO{}", BLUE_BG_WHITE_TEXT, DEFAULT_BG_DEFAULT_TEXT),
70 Level::Debug => {
71 format!("{}DEBUG{}", GREEN_BG_BLACK_TEXT, DEFAULT_BG_DEFAULT_TEXT)
72 }
73 Level::Trace => {
74 format!("{}TRACE{}", DEFAULT_BG_GRAY_TEXT, DEFAULT_BG_DEFAULT_TEXT)
75 }
76 }
77 },
78 file.unwrap_or(""),
79 line.unwrap_or(0),
80 metadata.target().to_string(),
81 module_path.unwrap_or(""),
82 args,
83 );
84 }
85
86 fn flush(&self) {}
87}
88
89#[cfg(not(feature = "tracing"))]
90pub fn init_logger() -> Result<(), SetLoggerError> {
91 let log_level = std::env::var("LOG_LEVEL").unwrap_or("off".to_string());
92 let log_level = match log_level.to_lowercase().as_str() {
93 "trace" => LevelFilter::Trace,
94 "debug" => LevelFilter::Debug,
95 "info" => LevelFilter::Info,
96 "warn" => LevelFilter::Warn,
97 "error" => LevelFilter::Error,
98 _ => LevelFilter::Off,
99 };
100 log::set_logger(&LOGGER).map(|()| log::set_max_level(log_level))
101}
102
103#[cfg(feature = "tracing")]
104pub fn init_logger() -> Result<(), SetLoggerError> {
105 let log_level = std::env::var("LOG_LEVEL").unwrap_or("off".to_string());
106
107 let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
108 .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(log_level));
109
110 let _ = tracing_subscriber::fmt()
111 .with_env_filter(env_filter)
112 .try_init();
113
114 Ok(())
115}
116
117#[test]
118fn test() {
119 unsafe {
120 std::env::set_var("LOG_LEVEL", "INFO");
121 }
122 let _ = init_logger();
123 log::error!("This is an error message");
124 log::warn!("This is a warning message");
125 log::info!("This is an info message");
126 log::debug!("This is a debug message");
127 log::trace!("This is a trace message");
128 log::log!(target: "my_target", Level::Info, level = "CUSTOM"; "test log {}", "TEST");
129}