tklog/
Async.rs

1// Copyright (c) 2024, donnie4w <donnie4w@gmail.com>
2// All rights reserved.
3// https://github.com/donnie4w/tklog
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use std::collections::HashMap;
18
19use crate::asyncfile::FileHandler;
20use crate::handle::{FHandler, FileOptionType, FmtHandler};
21use crate::tklog::asynclog;
22use crate::trie::Trie;
23use crate::{arguments_to_string, l2tk, log_fmt, AttrFormat, Format, LogContext, LogOption, LogOptionConst, OptionTrait, LEVEL, MODE, PRINTMODE, TKLOG2ASYNC_LOG};
24use tokio::sync::mpsc;
25
26/// this is the tklog encapsulated Logger whose File operations
27/// are based on tokio, Therefore, it supports asynchronous scenarios
28/// and Logger allows you to set parameters for async log printing of tklog.
29///
30/// # Examples
31///
32/// Create a async Logger Object  and set the parameters:
33///
34/// ```no_run
35/// use tklog::LEVEL;
36/// use tklog::Format;
37/// use tklog::MODE;
38///
39/// let mut log = tklog::Async::Logger::new();
40///
41/// let  init =  async ||  {
42/// log.set_console(true)
43/// .set_level(LEVEL::Debug)
44/// .set_cutmode_by_time("tklogs.log", MODE::DAY, 10, true).await;
45/// };
46/// ```
47pub struct Logger {
48    sender: mpsc::UnboundedSender<(LEVEL, String, String)>,
49    fmthandle: FmtHandler,
50    filehandle: (String, FHandler),
51    mutex: tokio::sync::Mutex<u32>,
52    pub mode: PRINTMODE,
53    modmap: Trie<(LogOptionConst, String)>,
54    fmap: HashMap<String, FHandler>,
55    custom_handler: Option<fn(&LogContext) -> bool>,
56    separator: String,
57    levels: Option<[Option<(LogOption, String)>; 7]>,
58    // levelfmt: Option<Box<dyn Fn(LEVEL) -> String + Send + Sync>>,
59    // timefmt: Option<Box<dyn Fn() -> (String, String, String) + Send + Sync>>,
60    attrfmt: AttrFormat,
61}
62
63impl Logger {
64    pub fn new() -> Self {
65        let (sender, mut receiver) = mpsc::unbounded_channel();
66        tokio::spawn(async move {
67            while let Some(message) = receiver.recv().await {
68                let (level, module, msg) = message;
69                let m1: String = module;
70                let m2: String = msg;
71                crate::async_log!(level, m1.as_str(), m2.as_str());
72            }
73        });
74        Logger {
75            sender,
76            fmthandle: FmtHandler::new(),
77            filehandle: ("".to_string(), FHandler::new()),
78            mutex: tokio::sync::Mutex::new(0),
79            mode: PRINTMODE::DELAY,
80            modmap: Trie::new(),
81            fmap: HashMap::new(),
82            custom_handler: None,
83            separator: "".to_string(),
84            levels: None,
85            // levelfmt: None,
86            // timefmt: None,
87            attrfmt: AttrFormat::new(),
88        }
89    }
90
91    pub async fn print(&mut self, level: LEVEL, module: &str, message: &str) {
92        let mut console = String::new();
93        let mut msg = String::new();
94        let mut is_bodyfmt = false;
95
96        if let Some(f) = &self.attrfmt.bodyfmt {
97            is_bodyfmt = true;
98            msg = f(level, message.to_string());
99        }
100
101        if self.modmap.len() > 0 {
102            if let Some(mm) = self.modmap.get(module) {
103                let (lo, filename) = mm;
104                let mut is_mod_console = self.fmthandle.get_console();
105                let mut is_consolefmt = false;
106                if let Some(cs) = lo.console {
107                    is_mod_console = cs;
108                    if is_mod_console {
109                        if let Some(f) = &self.attrfmt.console_bodyfmt {
110                            is_consolefmt = true;
111                            console = f(level, message.to_string());
112                        }
113                    }
114                }
115                if filename != "" {
116                    if *filename == self.filehandle.0 {
117                        let _ = self
118                            .filehandle
119                            .1
120                            .async_print(
121                                is_mod_console,
122                                if is_mod_console {
123                                    if is_consolefmt {
124                                        console.as_str()
125                                    } else {
126                                        ""
127                                    }
128                                } else {
129                                    ""
130                                },
131                                if is_bodyfmt { msg.as_str() } else { message },
132                            )
133                            .await;
134                    } else {
135                        if let Some(fm) = self.fmap.get_mut(filename) {
136                            let _ = fm
137                                .async_print(
138                                    is_mod_console,
139                                    if is_mod_console {
140                                        if is_consolefmt {
141                                            console.as_str()
142                                        } else {
143                                            ""
144                                        }
145                                    } else {
146                                        ""
147                                    },
148                                    if is_bodyfmt { msg.as_str() } else { message },
149                                )
150                                .await;
151                        }
152                    }
153                    return;
154                }
155            }
156        }
157
158        if let Some(levels) = &self.levels {
159            if let Some(lp) = &levels[level as usize - 1] {
160                let (lo, filename) = lp;
161                let mut is_level_console = self.fmthandle.get_console();
162                let mut is_consolefmt = false;
163                if let Some(cs) = lo.console {
164                    is_level_console = cs;
165                    if is_level_console && console.is_empty() {
166                        if let Some(f) = &self.attrfmt.console_bodyfmt {
167                            is_consolefmt = true;
168                            console = f(level, message.to_string());
169                        }
170                    }
171                }
172                if filename != "" {
173                    if *filename == self.filehandle.0 {
174                        let _ = self
175                            .filehandle
176                            .1
177                            .async_print(
178                                is_level_console,
179                                if is_level_console {
180                                    if is_consolefmt {
181                                        console.as_str()
182                                    } else {
183                                        ""
184                                    }
185                                } else {
186                                    ""
187                                },
188                                if is_bodyfmt { msg.as_str() } else { message },
189                            )
190                            .await;
191                    } else {
192                        if let Some(fm) = self.fmap.get_mut(filename) {
193                            let _ = fm
194                                .async_print(
195                                    is_level_console,
196                                    if is_level_console {
197                                        if is_consolefmt {
198                                            console.as_str()
199                                        } else {
200                                            ""
201                                        }
202                                    } else {
203                                        ""
204                                    },
205                                    if is_bodyfmt { msg.as_str() } else { message },
206                                )
207                                .await;
208                        }
209                    }
210                    return;
211                }
212            }
213        }
214
215        let is_console = self.fmthandle.get_console();
216        let mut is_consolefmt = false;
217        if is_console && console.is_empty() {
218            if let Some(f) = &self.attrfmt.console_bodyfmt {
219                is_consolefmt = true;
220                console = f(level, message.to_string());
221            }
222        }
223        let _ = self
224            .filehandle
225            .1
226            .async_print(
227                is_console,
228                if is_console {
229                    if is_consolefmt {
230                        console.as_str()
231                    } else {
232                        ""
233                    }
234                } else {
235                    ""
236                },
237                if is_bodyfmt { msg.as_str() } else { message },
238            )
239            .await;
240    }
241
242    pub async fn safeprint(&mut self, level: LEVEL, module: &str, message: &str) {
243        let _mutex_guard = self.mutex.lock().await;
244
245        let mut console = String::new();
246        let mut msg = String::new();
247        let mut is_bodyfmt = false;
248
249        if let Some(f) = &self.attrfmt.bodyfmt {
250            is_bodyfmt = true;
251            msg = f(level, message.to_string());
252        }
253
254        if self.modmap.len() > 0 {
255            if let Some(mm) = self.modmap.get(module) {
256                let (lo, filename) = mm;
257                let mut is_mod_console = self.fmthandle.get_console();
258                let mut is_consolefmt = false;
259                if let Some(cs) = lo.console {
260                    is_mod_console = cs;
261                    if is_mod_console {
262                        if let Some(f) = &self.attrfmt.console_bodyfmt {
263                            is_consolefmt = true;
264                            console = f(level, message.to_string());
265                        }
266                    }
267                }
268                if filename != "" {
269                    if *filename == self.filehandle.0 {
270                        let _ = self
271                            .filehandle
272                            .1
273                            .async_print(
274                                is_mod_console,
275                                if is_mod_console {
276                                    if is_consolefmt {
277                                        console.as_str()
278                                    } else {
279                                        ""
280                                    }
281                                } else {
282                                    ""
283                                },
284                                if is_bodyfmt { msg.as_str() } else { message },
285                            )
286                            .await;
287                    } else {
288                        if let Some(fm) = self.fmap.get_mut(filename) {
289                            let _ = fm
290                                .async_print(
291                                    is_mod_console,
292                                    if is_mod_console {
293                                        if is_consolefmt {
294                                            console.as_str()
295                                        } else {
296                                            ""
297                                        }
298                                    } else {
299                                        ""
300                                    },
301                                    if is_bodyfmt { msg.as_str() } else { message },
302                                )
303                                .await;
304                        }
305                    }
306                    return;
307                }
308            }
309        }
310
311        if let Some(levels) = &self.levels {
312            if let Some(lp) = &levels[level as usize - 1] {
313                let (lo, filename) = lp;
314                let mut is_level_console = self.fmthandle.get_console();
315                let mut is_consolefmt = false;
316                if let Some(cs) = lo.console {
317                    is_level_console = cs;
318                    if is_level_console && console.is_empty() {
319                        if let Some(f) = &self.attrfmt.console_bodyfmt {
320                            is_consolefmt = true;
321                            console = f(level, message.to_string());
322                        }
323                    }
324                }
325                if filename != "" {
326                    if *filename == self.filehandle.0 {
327                        let _ = self
328                            .filehandle
329                            .1
330                            .async_print(
331                                is_level_console,
332                                if is_level_console {
333                                    if is_consolefmt {
334                                        console.as_str()
335                                    } else {
336                                        ""
337                                    }
338                                } else {
339                                    ""
340                                },
341                                if is_bodyfmt { msg.as_str() } else { message },
342                            )
343                            .await;
344                    } else {
345                        if let Some(fm) = self.fmap.get_mut(filename) {
346                            let _ = fm
347                                .async_print(
348                                    is_level_console,
349                                    if is_level_console {
350                                        if is_consolefmt {
351                                            console.as_str()
352                                        } else {
353                                            ""
354                                        }
355                                    } else {
356                                        ""
357                                    },
358                                    if is_bodyfmt { msg.as_str() } else { message },
359                                )
360                                .await;
361                        }
362                    }
363                    return;
364                }
365            }
366        }
367
368        let is_console = self.fmthandle.get_console();
369        let mut is_consolefmt = false;
370        if is_console && console.is_empty() {
371            if let Some(f) = &self.attrfmt.console_bodyfmt {
372                is_consolefmt = true;
373                console = f(level, message.to_string());
374            }
375        }
376        let _ = self
377            .filehandle
378            .1
379            .async_print(
380                is_console,
381                if is_console {
382                    if is_consolefmt {
383                        console.as_str()
384                    } else {
385                        ""
386                    }
387                } else {
388                    ""
389                },
390                if is_bodyfmt { msg.as_str() } else { message },
391            )
392            .await;
393    }
394
395    pub fn log(&self, level: LEVEL, module: String, message: String) {
396        self.sender.send((level, module, message)).expect("send error");
397    }
398
399    pub fn get_level(&mut self, module: &str) -> LEVEL {
400        if module != "" && self.modmap.len() > 0 {
401            if let Some(mm) = self.modmap.get(module) {
402                let (lo, _) = mm;
403                if let Some(level) = lo.level {
404                    return level;
405                }
406            }
407        }
408        self.fmthandle.get_level()
409    }
410
411    pub fn is_file_line(&mut self, level: LEVEL, module: &str) -> bool {
412        if let Some(levels) = &self.levels {
413            if let Some(lp) = &levels[level as usize - 1] {
414                let (lo, _) = lp;
415                if let Some(v) = lo.format {
416                    return v & (Format::LongFileName | Format::ShortFileName) != 0;
417                }
418            }
419        }
420
421        if module != "" && self.modmap.len() > 0 {
422            if let Some(mm) = self.modmap.get(module) {
423                let (lo, _) = mm;
424                if let Some(v) = lo.format {
425                    return v & (Format::LongFileName | Format::ShortFileName) != 0;
426                }
427            }
428        }
429        self.fmthandle.is_file_line()
430    }
431
432    pub fn fmt(&mut self, module: &str, level: LEVEL, filename: &str, line: u32, message: String) -> String {
433        if self.custom_handler.is_some() {
434            if let Some(ch) = &self.custom_handler {
435                if !ch(&LogContext { level: level, filename: filename.to_string(), line: line, log_body: message.clone(), modname: module.to_string() }) {
436                    return String::new();
437                }
438            }
439        }
440        let mut fmat = self.fmthandle.get_format();
441        let mut formatter = self.fmthandle.get_formatter();
442        if module != "" && self.modmap.len() > 0 {
443            if let Some(mm) = self.modmap.get(module) {
444                let (lo, _) = mm;
445                if let Some(v) = lo.format {
446                    fmat = v;
447                }
448                if lo.formatter.is_some() {
449                    formatter = lo.formatter.as_ref();
450                }
451            }
452        }
453
454        if let Some(levels) = &self.levels {
455            if let Some(lp) = &levels[level as usize - 1] {
456                let (lo, _) = lp;
457                if let Some(v) = lo.format {
458                    fmat = v;
459                }
460                if lo.formatter.is_some() {
461                    formatter = lo.formatter.as_ref();
462                }
463            }
464        }
465        log_fmt(self.attrfmt.levelfmt.as_ref(), self.attrfmt.timefmt.as_ref(), fmat, formatter, level, filename, line, message.as_str())
466    }
467
468    pub fn set_printmode(&mut self, mode: PRINTMODE) -> &mut Self {
469        self.mode = mode;
470        self
471    }
472
473    pub fn set_level(&mut self, level: LEVEL) -> &mut Self {
474        self.fmthandle.set_level(level);
475        self
476    }
477
478    pub fn set_console(&mut self, console: bool) -> &mut Self {
479        self.fmthandle.set_console(console);
480        self
481    }
482
483    /**Format::LevelFlag | Format::Date | Format::Time | Format::ShortFileName; */
484    pub fn set_format(&mut self, format: u8) -> &mut Self {
485        self.fmthandle.set_format(format);
486        self
487    }
488
489    /** default: "{level}{time} {file}:{message}\n" */
490    pub fn set_formatter(&mut self, formatter: &str) -> &mut Self {
491        self.fmthandle.set_formatter(formatter.to_string());
492        self
493    }
494
495    pub async fn set_cutmode_by_size(&mut self, filename: &str, maxsize: u64, maxbackups: u32, compress: bool) -> &mut Self {
496        let fsm = FileOptionType::new(crate::CUTMODE::SIZE, MODE::DAY, filename, maxsize, maxbackups, compress);
497        let fh = FileHandler::new(Box::new(fsm)).await;
498        self.filehandle.0 = filename.to_string();
499        self.filehandle.1.set_async_file_handler(fh.unwrap());
500        self
501    }
502
503    pub async fn set_cutmode_by_time(&mut self, filename: &str, mode: MODE, maxbackups: u32, compress: bool) -> &mut Self {
504        let ftm = FileOptionType::new(crate::CUTMODE::TIME, mode, filename, 0, maxbackups, compress);
505        let fh = FileHandler::new(Box::new(ftm)).await;
506        self.filehandle.0 = filename.to_string();
507        self.filehandle.1.set_async_file_handler(fh.unwrap());
508        self
509    }
510
511    pub async fn set_cutmode_by_mixed(&mut self, filename: &str, maxsize: u64, mode: MODE, maxbackups: u32, compress: bool) -> &mut Self {
512        let ftm = FileOptionType::new(crate::CUTMODE::MIXED, mode, filename, maxsize, maxbackups, compress);
513        let fh = FileHandler::new(Box::new(ftm)).await;
514        self.filehandle.0 = filename.to_string();
515        self.filehandle.1.set_async_file_handler(fh.unwrap());
516        self
517    }
518
519    pub async fn set_option(&mut self, option: LogOption) -> &mut Self {
520        if let Some(v) = option.console {
521            self.fmthandle.set_console(v);
522        }
523        if let Some(v) = option.format {
524            self.fmthandle.set_format(v);
525        }
526        if let Some(v) = option.formatter {
527            self.fmthandle.set_formatter(v);
528        }
529        if let Some(v) = option.level {
530            self.fmthandle.set_level(v);
531        }
532        if let Some(v) = option.fileoption {
533            match FileHandler::new(v).await {
534                Ok(f) => {
535                    self.filehandle.0 = f.get_file_name();
536                    self.filehandle.1.set_async_file_handler(f);
537                }
538                Err(_) => {}
539            }
540        }
541        self
542    }
543
544    pub async fn set_mod_option(&mut self, module: &str, option: LogOption) -> &mut Self {
545        let mut filename = "".to_string();
546        if let Some(v) = option.fileoption {
547            match FileHandler::new(v).await {
548                Ok(f) => {
549                    filename = f.get_file_name();
550                    if filename != self.filehandle.0 && !self.fmap.contains_key(&filename) {
551                        let mut fhandler = FHandler::new();
552                        fhandler.set_async_file_handler(f);
553                        self.fmap.insert(filename.clone(), fhandler);
554                    }
555                }
556                Err(_) => {}
557            }
558        }
559        self.modmap.insert(module, (LogOptionConst { level: option.level, format: option.format, formatter: option.formatter, console: option.console }, filename.clone()));
560        self
561    }
562
563    pub fn set_custom_handler(&mut self, handler: fn(&LogContext) -> bool) {
564        self.custom_handler = Some(handler);
565    }
566
567    pub async fn set_level_option(&mut self, level: LEVEL, option: &dyn OptionTrait) -> &mut Self {
568        let mut filename = "".to_string();
569        if let Some(v) = option.get_fileoption() {
570            match FileHandler::new(v).await {
571                Ok(f) => {
572                    filename = f.get_file_name();
573                    if filename != self.filehandle.0 && !self.fmap.contains_key(&filename) {
574                        let mut fhandler = FHandler::new();
575                        fhandler.set_async_file_handler(f);
576                        self.fmap.insert(filename.clone(), fhandler);
577                    }
578                }
579                Err(_) => {}
580            }
581        }
582        let lo = LogOption { level: None, format: option.get_format(), formatter: option.get_formatter(), console: option.get_console(), fileoption: option.get_fileoption() };
583
584        if self.levels.is_none() {
585            self.levels = Some(std::array::from_fn(|_| None));
586        }
587
588        if let Some(levels) = &mut self.levels {
589            levels[level as usize - 1] = Some((lo, filename));
590        }
591
592        self
593    }
594
595    pub fn set_separator(&mut self, separator: &str) -> &mut Self {
596        self.separator = separator.to_string();
597        self
598    }
599
600    pub fn get_separator(&self) -> String {
601        self.separator.clone()
602    }
603
604    pub fn set_attr_format<F>(&mut self, mut f: F)
605    where
606        F: FnMut(&mut AttrFormat) + Send + Sync + 'static,
607    {
608        f(&mut self.attrfmt);
609    }
610}
611
612pub struct Log;
613
614impl Log {
615    pub fn new() -> Self {
616        Log {}
617    }
618    pub fn set_printmode(&self, mode: PRINTMODE) -> &Self {
619        unsafe {
620            asynclog.set_printmode(mode);
621        }
622        self
623    }
624
625    pub fn set_level(&self, level: LEVEL) -> &Self {
626        unsafe {
627            asynclog.set_level(level);
628        }
629        self
630    }
631
632    pub fn set_console(&self, console: bool) -> &Self {
633        unsafe {
634            asynclog.set_console(console);
635        }
636        self
637    }
638
639    /**Format::LevelFlag | Format::Date | Format::Time | Format::ShortFileName; */
640    pub fn set_format(&self, format: u8) -> &Self {
641        unsafe {
642            asynclog.set_format(format);
643        }
644        self
645    }
646
647    /** default: "{level}{time} {file}:{message}\n" */
648    pub fn set_formatter(&self, formatter: &str) -> &Self {
649        unsafe {
650            asynclog.set_formatter(formatter);
651        }
652        self
653    }
654
655    pub async fn set_cutmode_by_size(&self, filename: &str, maxsize: u64, maxbackups: u32, compress: bool) -> &Self {
656        unsafe {
657            asynclog.set_cutmode_by_size(filename, maxsize, maxbackups, compress).await;
658        }
659        self
660    }
661
662    pub async fn set_cutmode_by_time(&self, filename: &str, mode: MODE, maxbackups: u32, compress: bool) -> &Self {
663        unsafe {
664            asynclog.set_cutmode_by_time(filename, mode, maxbackups, compress).await;
665        }
666        self
667    }
668
669    pub async fn set_cutmode_by_mixed(&self, filename: &str, maxsize: u64, mode: MODE, maxbackups: u32, compress: bool) -> &Self {
670        unsafe {
671            asynclog.set_cutmode_by_mixed(filename, maxsize, mode, maxbackups, compress).await;
672        }
673        self
674    }
675
676    pub fn set_custom_handler(&self, handler: fn(&LogContext) -> bool) -> &Self {
677        unsafe { asynclog.set_custom_handler(handler) }
678        self
679    }
680
681    fn is_file_line(&self, level: LEVEL, module: &str) -> bool {
682        unsafe {
683            return asynclog.is_file_line(level, module);
684        }
685    }
686
687    pub async fn set_option(&self, option: LogOption) -> &Self {
688        unsafe {
689            asynclog.set_option(option).await;
690        }
691        self
692    }
693
694    pub async fn set_mod_option(&self, module: &str, option: LogOption) -> &Self {
695        unsafe {
696            asynclog.set_mod_option(module, option).await;
697        }
698        self
699    }
700
701    pub async fn set_level_option(&self, level: LEVEL, option: impl OptionTrait) -> &Self {
702        unsafe {
703            asynclog.set_level_option(level, &option).await;
704        }
705        self
706    }
707
708    pub fn set_separator(&self, separator: &str) -> &Self {
709        unsafe {
710            asynclog.set_separator(separator);
711        };
712        self
713    }
714
715    pub fn uselog(&self) -> &Self {
716        let _ = log::set_logger(&TKLOG2ASYNC_LOG);
717        log::set_max_level(log::LevelFilter::Trace);
718        self
719    }
720
721    pub fn set_attr_format<F>(&self, f: F)
722    where
723        F: FnMut(&mut AttrFormat) + Send + Sync + 'static,
724    {
725        unsafe {
726            asynclog.set_attr_format(f);
727        }
728    }
729}
730
731impl log::Log for Log {
732    fn enabled(&self, _: &log::Metadata) -> bool {
733        return true;
734    }
735    fn log(&self, record: &log::Record) {
736        let level = l2tk(record.level());
737        let mut module = "";
738        if let Some(m) = record.module_path() {
739            module = m;
740            unsafe {
741                if asynclog.get_level(module) > level {
742                    return;
743                }
744            }
745        }
746
747        let args = record.args();
748        let mut file = "";
749        let mut line: u32 = 0;
750        if self.is_file_line(level, module) {
751            line = record.line().unwrap_or(0);
752            file = record.file().unwrap_or("");
753        }
754        unsafe {
755            let s = asynclog.fmt(module, level, file, line, arguments_to_string(args));
756            if !s.is_empty() {
757                asynclog.log(level, module.to_string(), s);
758            }
759        }
760    }
761    fn flush(&self) {}
762}
763
764#[macro_export]
765macro_rules! async_log {
766    ($level:expr,$module:expr,$msg:expr) => {
767        let msg: &str = $msg;
768        let module: &str = $module;
769        unsafe {
770            crate::tklog::asynclog.print($level, module, msg).await;
771        }
772    };
773}
774
775#[macro_export]
776macro_rules! async_trace {
777    () => {};
778    ($($arg:expr),*) => {
779        $crate::async_log_common!($crate::LEVEL::Trace, $($arg),*);
780    };
781}
782
783#[macro_export]
784macro_rules! async_debug {
785    () => {};
786    ($($arg:expr),*) => {
787        $crate::async_log_common!($crate::LEVEL::Debug, $($arg),*);
788    };
789}
790
791#[macro_export]
792macro_rules! async_info {
793    () => {};
794    ($($arg:expr),*) => {
795        $crate::async_log_common!($crate::LEVEL::Info, $($arg),*);
796    };
797}
798
799#[macro_export]
800macro_rules! async_warn {
801    () => {};
802    ($($arg:expr),*) => {
803        $crate::async_log_common!($crate::LEVEL::Warn, $($arg),*);
804    };
805}
806
807#[macro_export]
808macro_rules! async_error {
809    () => {};
810    ($($arg:expr),*) => {
811        $crate::async_log_common!($crate::LEVEL::Error, $($arg),*);
812    };
813}
814
815#[macro_export]
816macro_rules! async_fatal {
817    () => {};
818    ($($arg:expr),*) => {
819        $crate::async_log_common!($crate::LEVEL::Fatal, $($arg),*);
820    };
821}
822
823#[macro_export]
824macro_rules! async_log_common {
825    ($level:expr, $($arg:expr),*) => {
826        unsafe {
827            let module = module_path!();
828            if $crate::tklog::asynclog.get_level(module) <= $level {
829                let formatted_args: Vec<String> = vec![$(format!("{}", $arg)),*];
830                let mut file = "";
831                let mut line = 0;
832                if $crate::tklog::asynclog.is_file_line($level,module) {
833                    file = file!();
834                    line = line!();
835                }
836                let msg: String = formatted_args.join($crate::tklog::asynclog.get_separator().as_str());
837                if  $crate::tklog::asynclog.mode==$crate::PRINTMODE::DELAY {
838                    let s = $crate::tklog::asynclog.fmt(module,$level, file, line, msg);
839                    if !s.is_empty(){
840                        $crate::tklog::asynclog.log($level,module.to_string(),s);
841                    }
842                }else {
843                    let s = $crate::tklog::asynclog.fmt(module,$level, file, line, msg);
844                    if !s.is_empty(){
845                        $crate::tklog::asynclog.safeprint($level,module,s.as_str()).await;
846                    }
847                }
848            }
849        }
850    };
851    () => {};
852}