1use crate::log::log_level::LogLevel;
2use crate::log::logger::VibeLogger;
3use chrono::Local;
4use indexmap::IndexMap;
5use lazy_static::lazy_static;
6use serde_json::Value;
7use tokio::sync::RwLock;
8
9pub static LOG_PREFIX: &str = "V";
11
12pub trait LogListenerTrait: Fn(String, LogLevel, String, String) + Send + Sync {}
14pub type DBLogListener = Box<dyn LogListenerTrait>;
16impl<T> LogListenerTrait for T where T: Fn(String, LogLevel, String, String) + Send + Sync {}
17
18pub fn create_log_content(first_field: Option<&str>, values: Option<Vec<Value>>) -> String {
25 if first_field.is_none() && values.is_none() {
26 return "{}".to_string();
27 }
28
29 let first_field = first_field.unwrap_or_default();
30 let values = values.unwrap_or_default();
31
32 let keys: Vec<&str> = first_field.split('|').collect();
33
34 let mut map = IndexMap::new();
35
36 for (i, key) in keys.iter().enumerate() {
37 if i < values.len() {
38 map.insert(*key, values[i].clone());
39 }
40 }
41
42 match serde_json::to_string(&map) {
43 Ok(json_str) => json_str,
44 Err(_) => format!("{:?}", map),
45 }
46}
47
48pub fn on_log(
54 location: String,
55 level: LogLevel,
56 ext: Option<String>,
57 tag: &str,
58 first_field: Option<&str>,
59 values: Option<Vec<Value>>,
60 suffix: &str,
61) {
62 let content = create_log_content(first_field, values);
63 let tag_data = match ext {
64 Some(ext) => format!("{}-{}-{}-{}", LOG_PREFIX, ext, tag, suffix),
65 None => format!("{}-{}-{}", LOG_PREFIX, tag, suffix),
66 };
67
68 match GLOBAL_DB_LOG_LISTENER.try_read() {
69 Ok(listener) => {
70 if let Some(on_log) = &*listener {
71 on_log(location.clone(), level, tag_data.clone(), content.clone());
72 }
73 }
74 Err(error) => {
75 println!(
76 "Error occurred while locking GLOBAL_LOG_LISTENER: {:?}",
77 error
78 );
79 }
80 }
81
82 let time = Local::now().format("%H:%M:%S%.3f");
83 println!("{} {} {:?} {}", time, tag_data.clone(), level, content);
84}
85
86#[doc(hidden)]
87#[macro_export]
88macro_rules! location {
89 () => {{
90 let location = std::panic::Location::caller();
91 let location_str = format!(
92 "{}:{}:{}",
93 location.file(),
94 location.line(),
95 location.column()
96 );
97 location_str
98 }};
99}
100
101#[doc(hidden)]
102#[macro_export]
103macro_rules! internal_log_db {
104 ($level:expr, $suffix:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
105 let values = vec![$( $crate::__serde_json::json!($value) ),*];
106 let location = std::panic::Location::caller();
107 let location = format!(
108 "{}:{}:{}",
109 location.file(),
110 location.line(),
111 location.column()
112 );
113 $crate::__vibe_internal_log_on_log(location.clone(), $level, None, $tag, Some($first_field), Some(values), $suffix)
114 };
115
116 ($level:expr, $suffix:expr, $tag:expr, $( $value:expr ),*) => {
117 let values = vec![$( $crate::__serde_json::json!($value) ),*];
118 let location = std::panic::Location::caller();
119 let location = format!(
120 "{}:{}:{}",
121 location.file(),
122 location.line(),
123 location.column()
124 );
125 $crate::__vibe_internal_log_on_log(location.clone(), $level, None, $tag, None, None, $suffix)
126 };
127
128 ($level:expr, $suffix:expr, $tag:expr) => {
129 let location = std::panic::Location::caller();
130 let location = format!(
131 "{}:{}:{}",
132 location.file(),
133 location.line(),
134 location.column()
135 );
136 $crate::__vibe_internal_log_on_log(location.clone(), $level, None, $tag, None, None, $suffix)
137 };
138}
139
140#[doc(hidden)]
141#[macro_export]
142macro_rules! internal_log_db_ext {
143 ($ext:expr, $level:expr, $suffix:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
144 let values = vec![$( $crate::__serde_json::json!($value) ),*];
145 let location = std::panic::Location::caller();
146 let location = format!(
147 "{}:{}:{}",
148 location.file(),
149 location.line(),
150 location.column()
151 );
152 $crate::__vibe_internal_log_on_log(location.clone(), $level, $ext, $tag, Some($first_field), Some(values), $suffix)
153 };
154
155 ($ext:expr, $level:expr, $suffix:expr, $tag:expr, $( $value:expr ),*) => {
156 let values = vec![$( $crate::__serde_json::json!($value) ),*];
157 let location = std::panic::Location::caller();
158 let location = format!(
159 "{}:{}:{}",
160 location.file(),
161 location.line(),
162 location.column()
163 );
164 $crate::__vibe_internal_log_on_log(location.clone(), $level, $ext, $tag, None, None, $suffix)
165 };
166
167 ($ext:expr, $level:expr, $suffix:expr, $tag:expr) => {
168 let location = std::panic::Location::caller();
169 let location = format!(
170 "{}:{}:{}",
171 location.file(),
172 location.line(),
173 location.column()
174 );
175 $crate::__vibe_internal_log_on_log(location.clone(), $level, $ext, $tag, None, None, $suffix)
176 };
177}
178
179#[macro_export]
187macro_rules! log_i {
188 ($tag:expr, $first_field:expr, $( $value:expr ),*) => {
189 $crate::internal_log_db!($crate::VibeLogLevel::Info, "I", $tag, $first_field, $( $value ),*)
190 };
191
192 ($tag:expr, $( $value:expr ),*) => {
193 $crate::internal_log_db!($crate::VibeLogLevel::Info, "I", $tag, $( $value ),*)
194 };
195
196 ($tag:expr) => {
197 $crate::internal_log_db!($crate::VibeLogLevel::Info, "I", $tag)
198 };
199}
200
201#[macro_export]
209macro_rules! log_i_ {
210 ($ext:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
211 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Info, "I", $tag, $first_field, $( $value ),*)
212 };
213
214 ($ext:expr, $tag:expr, $( $value:expr ),*) => {
215 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Info, "I", $tag, $( $value ),*)
216 };
217
218 ($ext:expr, $tag:expr) => {
219 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Info, "I", $tag)
220 };
221}
222
223#[macro_export]
225macro_rules! log_t {
226 ($tag:expr, $first_field:expr, $( $value:expr ),*) => {
227 $crate::internal_log_db!($crate::VibeLogLevel::Info, "T", $tag, $first_field, $( $value ),*)
228 };
229
230 ($tag:expr, $( $value:expr ),*) => {
231 $crate::internal_log_db!($crate::VibeLogLevel::Info, "T", $tag, $( $value ),*)
232 };
233
234 ($tag:expr) => {
235 $crate::internal_log_db!($crate::VibeLogLevel::Info, "T", $tag)
236 };
237}
238
239#[macro_export]
241macro_rules! log_t_ {
242 ($ext:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
243 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Info, "T", $tag, $first_field, $( $value ),*)
244 };
245
246 ($ext:expr, $tag:expr, $( $value:expr ),*) => {
247 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Info, "T", $tag, $( $value ),*)
248 };
249
250 ($ext:expr, $tag:expr) => {
251 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Info, "T", $tag)
252 };
253}
254
255#[macro_export]
257macro_rules! log_r {
258 ($tag:expr, $first_field:expr, $( $value:expr ),*) => {
259 $crate::internal_log_db!($crate::VibeLogLevel::Debug, "R", $tag, $first_field, $( $value ),*)
260 };
261
262 ($tag:expr, $( $value:expr ),*) => {
263 $crate::internal_log_db!($crate::VibeLogLevel::Debug, "R", $tag, $( $value ),*)
264 };
265
266 ($tag:expr) => {
267 $crate::internal_log_db!($crate::VibeLogLevel::Debug, "R", $tag)
268 };
269}
270
271#[macro_export]
273macro_rules! log_r_ {
274 ($ext:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
275 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Debug, "R", $tag, $first_field, $( $value ),*)
276 };
277
278 ($ext:expr, $tag:expr, $( $value:expr ),*) => {
279 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Debug, "R", $tag, $( $value ),*)
280 };
281
282 ($ext:expr, $tag:expr) => {
283 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Debug, "R", $tag)
284 };
285}
286
287#[macro_export]
289macro_rules! log_s {
290 ($tag:expr, $first_field:expr, $( $value:expr ),*) => {
291 $crate::internal_log_db!($crate::VibeLogLevel::Debug, "S", $tag, $first_field, $( $value ),*)
292 };
293
294 ($tag:expr, $( $value:expr ),*) => {
295 $crate::internal_log_db!($crate::VibeLogLevel::Debug, "S", $tag, $( $value ),*)
296 };
297
298 ($tag:expr) => {
299 $crate::internal_log_db!($crate::VibeLogLevel::Debug, "S", $tag)
300 };
301}
302
303#[macro_export]
305macro_rules! log_s_ {
306 ($ext:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
307 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Debug, "S", $tag, $first_field, $( $value ),*)
308 };
309
310 ($ext:expr, $tag:expr, $( $value:expr ),*) => {
311 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Debug, "S", $tag, $( $value ),*)
312 };
313
314 ($ext:expr, $tag:expr) => {
315 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Debug, "S", $tag)
316 };
317}
318
319#[macro_export]
327macro_rules! log_e {
328 ($tag:expr, $first_field:expr, $( $value:expr ),*) => {
329 $crate::internal_log_db!($crate::VibeLogLevel::Error, "E", $tag, $first_field, $( $value ),*)
330 };
331
332 ($tag:expr, $( $value:expr ),*) => {
333 $crate::internal_log_db!($crate::VibeLogLevel::Error, "E", $tag, $( $value ),*)
334 };
335
336 ($tag:expr) => {
337 $crate::internal_log_db!($crate::VibeLogLevel::Error, "E", $tag)
338 };
339}
340
341#[macro_export]
343macro_rules! log_e_ {
344 ($ext:expr, $tag:expr, $first_field:expr, $( $value:expr ),*) => {
345 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Error, "E", $tag, $first_field, $( $value ),*)
346 };
347
348 ($ext:expr, $tag:expr, $( $value:expr ),*) => {
349 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Error, "E", $tag, $( $value ),*)
350 };
351
352 ($ext:expr, $tag:expr) => {
353 $crate::internal_log_db_ext!($ext, $crate::VibeLogLevel::Error, "E", $tag)
354 };
355}
356
357#[macro_export]
367macro_rules! array_to_json_string {
368 ($vec:expr) => {{
369 let cloned_vec = $vec.clone();
370
371 match $crate::__serde_json::to_string(&cloned_vec) {
372 Ok(json) => json,
373 Err(e) => format!("JSON serialization failed: {}", e),
374 }
375 }};
376}
377
378#[macro_export]
380macro_rules! obj_array_to_json_string {
381 ($vec:expr) => {{
382 format!(
383 "[{}]",
384 $vec.iter()
385 .map(|x| x.to_string())
386 .collect::<Vec<_>>()
387 .join(", ")
388 )
389 }};
390}
391
392#[macro_export]
394macro_rules! basic_type_map_to_json_string {
395 ($map:expr) => {{
396 use std::collections::HashMap;
397
398 let cloned_map: HashMap<String, _> = $map.clone();
399
400 (|| -> String {
401 match $crate::__serde_json::to_string(&cloned_map) {
402 Ok(json) => json,
403 Err(e) => format!("JSON serialization failed: {}", e),
404 }
405 })()
406 }};
407}
408
409#[macro_export]
411macro_rules! impl_display_json {
412 ($($struct:ty),*) => {
413 $(
414 impl std::fmt::Display for $struct {
415 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
416 match $crate::__serde_json::to_string(self) {
417 Ok(json) => write!(f, "{}", json),
418 Err(e) => write!(f, "Serialization error: {}", e),
419 }
420 }
421 }
422 )*
423 };
424}
425
426#[macro_export]
437macro_rules! err {
438 ($err:expr) => {{
439 log::error!(
440 "Error: {:?}, {:?}",
441 $err,
442 std::backtrace::Backtrace::capture()
443 );
444 $err
445 }};
446}
447
448lazy_static! {
449 static ref GLOBAL_DB_LOG_LISTENER: RwLock<Option<DBLogListener>> = RwLock::new(None);
450}
451
452impl VibeLogger {
453 pub fn register_log_listener<T: LogListenerTrait + 'static>(listener: Option<T>) {
459 if let Ok(mut guard) = GLOBAL_DB_LOG_LISTENER.try_write() {
460 match listener {
461 None => *guard = None,
462 Some(listener) => *guard = Some(Box::new(listener)),
463 }
464 }
465 }
466
467 pub fn clear_global_log_listener() {
473 if let Ok(mut guard) = GLOBAL_DB_LOG_LISTENER.try_write() {
474 *guard = None;
475 }
476 }
477}
478
479#[cfg(test)]
480mod strict_tests {
481 use super::*;
482 include!(concat!(
483 env!("CARGO_MANIFEST_DIR"),
484 "/test/unit/log/logger_macro_tests.rs"
485 ));
486}