layla_log/
lib.rs

1//! A simple logger library. This library provides a simple log writer and simple log level control.
2//! It can be used to write logs in a program. The logs can be written to a dictionary.
3//! The log level can be set to different levels (Error, Warn, Debug, Info and Trace).
4
5mod logger;
6mod msg;
7mod setting;
8mod time;
9
10pub use logger::*;
11pub use setting::Setting;
12
13#[cfg(feature = "async")]
14pub use async_log::*;
15#[cfg(not(feature = "async"))]
16pub use log::*;
17
18use lazy_static::lazy_static;
19#[cfg(not(feature = "async"))]
20use std::sync::Mutex;
21#[cfg(feature = "async")]
22use tokio;
23#[cfg(feature = "async")]
24use tokio::sync::Mutex;
25
26lazy_static! {
27    /// The static logger.
28    /// If async feature is enabled, the mutex used is [``tokio::sync::mutex``], otherwise it is [`std::sync::Mutex`].
29    pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
30}
31
32/// A macro that returns the name of the function it is called in.
33#[macro_export]
34macro_rules! func {
35    () => {{
36        fn f() {}
37        fn type_name_of<T>(_: T) -> &'static str {
38            std::any::type_name::<T>()
39        }
40        let name = type_name_of(f);
41        // name.rsplit("::")
42        //     .find(|&part| part != "f" && part != "{{closure}}")
43        //     .expect("Short function name")
44        name.strip_suffix("::f")
45            .unwrap()
46            .rsplit("::")
47            .find(|&part| part != "{{closure}}")
48            .expect("Short function name")
49    }};
50}
51
52/// A macro that returns the current position in the code.
53#[macro_export]
54macro_rules! position {
55    () => {{
56        let function = $crate::func!();
57        let file = file!();
58        let line = line!();
59        format!("{} @ {}:{}", function, file, line)
60    }};
61}
62
63#[cfg(feature = "async")]
64mod async_log {
65    use super::*;
66
67    /// Define a public asynchronous function named `init` that takes a `Setting` parameter.
68    pub async fn init(setting: Setting) {
69        // Acquire a mutable lock on the `LOGGER` (which is presumably a globally accessible logging utility).
70        // The `await` keyword is used here to asynchronously wait for the lock to be acquired.
71        let mut logger = LOGGER.lock().await;
72        // Call the `init` method on the locked logger, passing in the `setting` parameter.
73        // This initializes the logger with the provided settings.
74        logger.init(setting).await;
75    }
76
77    /// Define a public asynchronous function named `clean_log`
78    pub async fn clean_log() {
79        // Acquire a mutable lock on the LOGGER, which is presumably a globally accessible logging utility
80        // The `await` keyword is used here to asynchronously wait for the lock to be acquired
81        let mut writer = LOGGER.lock().await;
82        // Call the `clear_dir` method on the locked writer to clear the directory where logs are stored
83        // This method is also awaited asynchronously, indicating it performs an I/O operation or similar
84        writer.clear_dir().await;
85    }
86
87    /// Macro to log error message.
88    /// First lock the logger in static, then log the message.
89    #[macro_export]
90    macro_rules! error {
91        ($($arg:tt)*) => {
92            let position = $crate::position!().to_string();
93            $crate::LOGGER.lock().await.error(format!($($arg)*).as_str(), position).await;
94        };
95    }
96
97    /// Macro to log warning message.
98    /// First lock the logger in static, then log the message.
99    #[macro_export]
100    macro_rules! warn {
101        ($($arg:tt)*) => {
102            let position = $crate::position!().to_string();
103            $crate::LOGGER.lock().await.warn(format!($($arg)*).as_str(), position).await;
104        };
105    }
106
107    /// Macro to log info message.
108    /// First lock the logger in static, then log the message.
109    #[macro_export]
110    macro_rules! info {
111        ($($arg:tt)*) => {
112            let position = $crate::position!().to_string();
113            $crate::LOGGER.lock().await.info(format!($($arg)*).as_str(), position).await;
114        };
115    }
116
117    /// Macro to log debug message.
118    /// First lock the logger in static, then log the message.
119    #[macro_export]
120    macro_rules! debug {
121        ($($arg:tt)*) => {
122            let position = $crate::position!().to_string();
123            $crate::LOGGER.lock().await.debug(format!($($arg)*).as_str(), position).await;
124        };
125    }
126
127    /// Macro to log trace message.
128    /// First lock the logger in static, then log the message.
129    #[macro_export]
130    macro_rules! trace {
131        ($($arg:tt)*) => {
132            let position = $crate::position!().to_string();
133            $crate::LOGGER.lock().await.trace(format!($($arg)*).as_str(), position).await;
134        };
135    }
136
137    /// Define a macro named `log` with two parameters: `$level` and `$($arg:tt)*`
138    #[macro_export]
139    macro_rules! log {
140        // Match the macro invocation with a level expression and a variable number of arguments
141        ($level:expr, $($arg:tt)*) => {
142            let position = $crate::position!().to_string();
143            $crate::LOGGER.lock().await.record($level, &format!($($arg)*), position).await;
144        }
145    }
146
147    /// Define a public asynchronous function named `enable_log`
148    pub async fn enable_log() {
149        // Acquire a mutable lock on the LOGGER, which is presumably a globally accessible logging utility
150        // The `await` keyword is used here to asynchronously wait for the lock to be acquired
151        let mut writer = LOGGER.lock().await;
152        // Call the `enable` method on the locked writer to enable logging
153        writer.enable();
154    }
155
156    /// Define a public asynchronous function named `disable_log`
157    pub async fn disable_log() {
158        // Acquire a mutable lock on the LOGGER, which is presumably a globally accessible logging mechanism
159        // The `await` keyword is used here to asynchronously wait for the lock to be acquired
160        let mut writer = LOGGER.lock().await;
161        // Call the `disable` method on the locked writer to disable logging
162        writer.disable();
163    }
164}
165
166#[cfg(not(feature = "async"))]
167mod log {
168    use super::*;
169
170    /// Macro to log error message.
171    /// First lock the logger in static, then log the message.
172    #[macro_export]
173    macro_rules! error {
174        ($($arg:tt)*) => {
175            let position = $crate::position!().to_string();
176            $crate::LOGGER.lock().expect("Cannot lock the logger.").error(&format!($($arg)*), position);
177        };
178    }
179
180    /// Macro to log warning message.
181    /// First lock the logger in static, then log the message.
182    #[macro_export]
183    macro_rules! warn {
184        ($($arg:tt)*) => {
185            let position = $crate::position!().to_string();
186            $crate::LOGGER.lock().expect("Cannot lock the logger.").warn(&format!($($arg)*), position);
187        };
188    }
189
190    /// Macro to log info message.
191    /// First lock the logger in static, then log the message.
192    #[macro_export]
193    macro_rules! info {
194        ($($arg:tt)*) => {
195            let position = $crate::position!().to_string();
196            $crate::LOGGER.lock().expect("Cannot lock the logger.").info(&format!($($arg)*), position);
197        };
198    }
199
200    /// Macro to log debug message.
201    /// First lock the logger in static, then log the message.
202    #[macro_export]
203    macro_rules! debug {
204        ($($arg:tt)*) => {
205            let position = $crate::position!().to_string();
206            $crate::LOGGER.lock().expect("Cannot lock the logger.").debug(&format!($($arg)*), position);
207        };
208    }
209
210    /// Macro to log trace message.
211    /// First lock the logger in static, then log the message.
212    #[macro_export]
213    macro_rules! trace {
214        ($($arg:tt)*) => {
215            let position = $crate::position!().to_string();
216            $crate::LOGGER.lock().expect("Cannot lock the logger.").trace(&format!($($arg)*), position);
217        };
218    }
219
220    #[macro_export]
221    macro_rules! log {
222        ($level:expr, $($arg:tt)*) => {
223            let position = $crate::position!().to_string();
224            $crate::LOGGER.lock().expect("Cannot lock the logger.").record($level, &format!($($arg)*), position);
225        }
226    }
227
228    /// Initialize the static logger with customized setting.
229    pub fn init(setting: Setting) {
230        let mut logger = LOGGER.lock().unwrap();
231        logger.init(setting);
232    }
233
234    /// Provide a easier way to clean all the existed logs.
235    pub fn clean_log() {
236        let mut writer = LOGGER.lock().expect("Cannot lock the logger.");
237        writer.clear_dir();
238    }
239
240    /// Public function to enable logging
241    pub fn enable_log() {
242        // Lock the LOGGER to ensure thread-safe access
243        let mut writer = LOGGER.lock().expect("Cannot lock the logger.");
244        // Enable logging using the writer
245        writer.enable();
246    }
247
248    /// Public function to disable logging
249    pub fn disable_log() {
250        // Lock the LOGGER to ensure thread-safe access
251        let mut writer = LOGGER.lock().expect("Cannot lock the logger.");
252        // Disable logging using the writer
253        writer.disable();
254    }
255}
256
257/// Enumeration of log levels.
258/// This defines the emergency of the log.
259/// (the corresponding number is used to compare the log level to decide write to the log file or not.)
260#[derive(Copy, Clone, Debug)]
261pub enum LogLevel {
262    Trace = 0,
263    Debug = 1,
264    Info = 2,
265    Warn = 3,
266    Error = 4,
267}
268
269impl std::fmt::Display for LogLevel {
270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271        match self {
272            LogLevel::Info => write!(f, "INFO "),
273            LogLevel::Debug => write!(f, "DEBUG"),
274            LogLevel::Warn => write!(f, "WARN "),
275            LogLevel::Error => write!(f, "ERROR"),
276            LogLevel::Trace => write!(f, "TRACE"),
277        }
278    }
279}
280
281impl LogLevel {
282    pub fn get_level(&self) -> usize {
283        *self as usize
284    }
285}
286
287unsafe impl Send for LogLevel {}