utilz_rs/
logger.rs

1#[cfg(not(feature = "async"))]
2use std::sync::RwLock;
3use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5#[cfg(feature = "async")]
6use async_trait::async_trait;
7#[cfg(feature = "async")]
8use once_cell::sync::Lazy;
9#[cfg(feature = "async")]
10use tokio::sync::RwLock;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum LogLevel {
14    Error,
15    Debug,
16    Info,
17    Warn,
18}
19
20struct Logger {
21    message: String,
22    level: LogLevel,
23    time: SystemTime,
24}
25
26pub struct Log;
27
28#[cfg(feature = "async")]
29static LOGS: Lazy<RwLock<Vec<Logger>>> = Lazy::new(|| RwLock::new(Vec::new()));
30#[cfg(feature = "async")]
31static LOG_LEVEL: Lazy<RwLock<LogLevel>> = Lazy::new(|| RwLock::new(LogLevel::Info));
32
33#[cfg(not(feature = "async"))]
34static LOGS: RwLock<Vec<Logger>> = RwLock::new(Vec::new());
35#[cfg(not(feature = "async"))]
36static LOG_LEVEL: RwLock<LogLevel> = RwLock::new(LogLevel::Debug);
37
38#[cfg(not(feature = "async"))]
39fn get_level() -> LogLevel {
40    *LOG_LEVEL.read().unwrap()
41}
42
43#[cfg(feature = "async")]
44async fn get_level() -> LogLevel {
45    *LOG_LEVEL.read().await
46}
47
48#[cfg(not(feature = "async"))]
49fn level_priority(level: LogLevel) -> u8 {
50    match level {
51        LogLevel::Error => 1,
52        LogLevel::Warn => 2,
53        LogLevel::Info => 3,
54        LogLevel::Debug => 4,
55    }
56}
57
58#[cfg(feature = "async")]
59async fn level_priority(level: LogLevel) -> u8 {
60    match level {
61        LogLevel::Error => 1,
62        LogLevel::Warn => 2,
63        LogLevel::Info => 3,
64        LogLevel::Debug => 4,
65    }
66}
67
68#[cfg(feature = "async")]
69impl Log {
70    pub async fn set_up_logger(level: LogLevel) {
71        *LOG_LEVEL.write().await = level;
72    }
73
74    pub async fn log_with_level(level: LogLevel, message: &str) {
75        if level_priority(level).await <= level_priority(get_level().await).await {
76            let log = Logger {
77                message: message.to_string(),
78                level,
79                time: SystemTime::now(),
80            };
81
82            LOGS.write().await.push(log);
83        }
84    }
85
86    pub async fn log(message: &str) {
87        Self::log_with_level(get_level().await, message).await;
88    }
89
90    pub async fn log_info(message: &str) {
91        Self::log_with_level(LogLevel::Info, message).await;
92    }
93
94    pub async fn log_debug(message: &str) {
95        Self::log_with_level(LogLevel::Debug, message).await;
96    }
97
98    pub async fn log_error(message: &str) {
99        Self::log_with_level(LogLevel::Error, message).await;
100    }
101
102    pub async fn log_warn(message: &str) {
103        Self::log_with_level(LogLevel::Warn, message).await;
104    }
105
106    pub async fn get_logs() -> Vec<String> {
107        LOGS.read()
108            .await
109            .iter()
110            .map(|log| {
111                let since_unix = log
112                    .time
113                    .duration_since(UNIX_EPOCH)
114                    .unwrap_or(Duration::from_secs(0));
115                format!(
116                    "[{:?}] @ {}s → {}",
117                    log.level,
118                    since_unix.as_secs(),
119                    log.message
120                )
121            })
122            .collect()
123    }
124
125    pub async fn print_logs() {
126        for log in Self::get_logs().await {
127            println!("{}", log);
128        }
129    }
130
131    pub async fn clear() {
132        LOGS.write().await.clear();
133    }
134}
135
136#[cfg(not(feature = "async"))]
137impl Log {
138    pub fn set_up_logger(level: LogLevel) {
139        *LOG_LEVEL.write().unwrap() = level;
140    }
141
142    pub fn log_with_level(level: LogLevel, message: &str) {
143        if level_priority(level) <= level_priority(get_level()) {
144            let log = Logger {
145                message: message.to_string(),
146                level,
147                time: SystemTime::now(),
148            };
149
150            LOGS.write().unwrap().push(log);
151        }
152    }
153
154    pub fn log(message: &str) {
155        Self::log_with_level(get_level(), message);
156    }
157
158    pub fn log_info(message: &str) {
159        Self::log_with_level(LogLevel::Info, message);
160    }
161
162    pub fn log_debug(message: &str) {
163        Self::log_with_level(LogLevel::Debug, message);
164    }
165
166    pub fn log_error(message: &str) {
167        Self::log_with_level(LogLevel::Error, message);
168    }
169
170    pub fn log_warn(message: &str) {
171        Self::log_with_level(LogLevel::Warn, message);
172    }
173
174    pub fn get_logs() -> Vec<String> {
175        LOGS.read()
176            .unwrap()
177            .iter()
178            .map(|log| {
179                let since_unix = log
180                    .time
181                    .duration_since(UNIX_EPOCH)
182                    .unwrap_or(Duration::from_secs(0));
183                format!(
184                    "[{:?}] @ {}s → {}",
185                    log.level,
186                    since_unix.as_secs(),
187                    log.message
188                )
189            })
190            .collect()
191    }
192
193    pub fn print_logs() {
194        for log in Self::get_logs() {
195            println!("{}", log);
196        }
197    }
198
199    pub fn clear() {
200        LOGS.write().unwrap().clear();
201    }
202}
203
204#[cfg(feature = "async")]
205#[async_trait(?Send)]
206pub trait Loggable: Sized + Send + 'static {
207    async fn log(&self);
208    async fn log_info(&self);
209    async fn log_error(&self);
210    async fn log_debug(&self);
211}
212
213#[cfg(not(feature = "async"))]
214pub trait Loggable {
215    fn log(self);
216    fn log_info(self);
217    fn log_error(self);
218    fn log_debug(self);
219}
220
221#[cfg(feature = "async")]
222#[async_trait(?Send)]
223impl Loggable for String {
224    async fn log(&self) {
225        Log::log(self).await
226    }
227    async fn log_info(&self) {
228        Log::log_info(self).await
229    }
230    async fn log_error(&self) {
231        Log::log_error(self).await
232    }
233    async fn log_debug(&self) {
234        Log::log_debug(self).await
235    }
236}
237
238#[cfg(not(feature = "async"))]
239impl Loggable for &str {
240    fn log(self) {
241        Log::log(self);
242    }
243    fn log_info(self) {
244        Log::log_info(self);
245    }
246    fn log_error(self) {
247        Log::log_error(self);
248    }
249    fn log_debug(self) {
250        Log::log_debug(self);
251    }
252}
253
254#[cfg(not(feature = "async"))]
255impl Loggable for String {
256    fn log(self) {
257        self.as_str().log()
258    }
259    fn log_info(self) {
260        self.as_str().log_info()
261    }
262    fn log_error(self) {
263        self.as_str().log_error()
264    }
265    fn log_debug(self) {
266        self.as_str().log_debug()
267    }
268}