1use 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
26pub 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 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 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 pub fn set_format(&mut self, format: u8) -> &mut Self {
485 self.fmthandle.set_format(format);
486 self
487 }
488
489 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 pub fn set_format(&self, format: u8) -> &Self {
641 unsafe {
642 asynclog.set_format(format);
643 }
644 self
645 }
646
647 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}