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}