1use std::sync::atomic::{AtomicI32, Ordering};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10#[repr(i32)]
11#[derive(Default)]
12pub enum Level {
13 #[default]
15 Unset = 0,
16 Debug = 1,
18 Info = 2,
20 Warn = 3,
22 Error = 4,
24}
25
26impl Level {
27 pub fn as_str(&self) -> &'static str {
28 match self {
29 Level::Unset => "info",
30 Level::Debug => "debug",
31 Level::Info => "info",
32 Level::Warn => "warn",
33 Level::Error => "error",
34 }
35 }
36}
37
38static CURRENT: AtomicI32 = AtomicI32::new(Level::Info as i32);
39
40pub fn set_level(l: Level) {
42 match l {
43 Level::Debug | Level::Info | Level::Warn | Level::Error => {
44 CURRENT.store(l as i32, Ordering::Relaxed);
45 }
46 Level::Unset => {}
47 }
48}
49
50pub fn enabled(l: Level) -> bool {
52 (l as i32) >= CURRENT.load(Ordering::Relaxed)
53}
54
55pub fn parse_level(s: &str) -> Result<Level, crate::errors::Error> {
57 match s.trim().to_ascii_lowercase().as_str() {
58 "debug" => Ok(Level::Debug),
59 "info" => Ok(Level::Info),
60 "warn" | "warning" => Ok(Level::Warn),
61 "error" => Ok(Level::Error),
62 _ => Err(crate::errors::Error::new(
63 crate::errors::Kind::Internal,
64 format!("unknown log level {s:?} (want debug|info|warn|error)"),
65 )),
66 }
67}
68
69fn emit(l: Level, msg: std::fmt::Arguments<'_>) {
70 if !enabled(l) {
71 return;
72 }
73 eprintln!("xyz[{}]: {}", l.as_str(), msg);
74}
75
76pub fn debugf(args: std::fmt::Arguments<'_>) {
77 emit(Level::Debug, args);
78}
79
80pub fn infof(args: std::fmt::Arguments<'_>) {
81 emit(Level::Info, args);
82}
83
84pub fn warnf(args: std::fmt::Arguments<'_>) {
85 emit(Level::Warn, args);
86}
87
88pub fn errorf(args: std::fmt::Arguments<'_>) {
89 emit(Level::Error, args);
90}
91
92#[macro_export]
93macro_rules! log_debug {
94 ($($arg:tt)*) => { $crate::logx::debugf(format_args!($($arg)*)) };
95}
96#[macro_export]
97macro_rules! log_info {
98 ($($arg:tt)*) => { $crate::logx::infof(format_args!($($arg)*)) };
99}
100#[macro_export]
101macro_rules! log_warn {
102 ($($arg:tt)*) => { $crate::logx::warnf(format_args!($($arg)*)) };
103}
104#[macro_export]
105macro_rules! log_error {
106 ($($arg:tt)*) => { $crate::logx::errorf(format_args!($($arg)*)) };
107}
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn parse_level_forms() {
114 assert_eq!(parse_level("debug").unwrap(), Level::Debug);
115 assert_eq!(parse_level("INFO").unwrap(), Level::Info);
116 assert_eq!(parse_level("warning").unwrap(), Level::Warn);
117 assert_eq!(parse_level("error").unwrap(), Level::Error);
118 assert!(parse_level("verbose").is_err());
119 assert!(parse_level("").is_err());
120 }
121
122 #[test]
123 fn set_level_and_enabled() {
124 set_level(Level::Error);
125 assert!(!enabled(Level::Info));
126 assert!(enabled(Level::Error));
127 set_level(Level::Debug);
128 assert!(enabled(Level::Info));
129 }
130}