1use std::{fmt::Debug, result::Result as StdResult, time::Duration};
2
3use crate::{
4 env_level,
5 error::{Error, ErrorHandler, InvalidArgumentError, SetLoggerNameError},
6 periodic_worker::PeriodicWorker,
7 sink::{Sink, Sinks},
8 sync::*,
9 AtomicLevelFilter, Level, LevelFilter, Record, Result,
10};
11
12fn check_logger_name(name: impl AsRef<str>) -> StdResult<(), SetLoggerNameError> {
13 let name = name.as_ref();
14
15 if name.chars().any(|ch| {
16 ch == ','
17 || ch == '='
18 || ch == '*'
19 || ch == '?'
20 || ch == '$'
21 || ch == '{'
22 || ch == '}'
23 || ch == '"'
24 || ch == '\''
25 || ch == ';'
26 }) || name.starts_with(' ')
27 || name.ends_with(' ')
28 {
29 Err(SetLoggerNameError::new(name))
30 } else {
31 Ok(())
32 }
33}
34
35pub struct Logger {
110 name: Option<String>,
111 level_filter: AtomicLevelFilter,
112 sinks: Sinks,
113 flush_level_filter: AtomicLevelFilter,
114 error_handler: RwLock<ErrorHandler>,
115 periodic_flusher: Mutex<Option<(Duration, PeriodicWorker)>>,
116}
117
118impl Debug for Logger {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 f.debug_struct("Logger")
121 .field("name", &self.name)
122 .field("level_filter", &self.level_filter())
123 .field(
124 "sinks",
125 &self
126 .sinks
127 .iter()
128 .map(|sink| sink.level_filter())
129 .collect::<Vec<_>>(),
130 )
131 .field("flush_level_filter", &self.flush_level_filter())
132 .field("error_handler", &self.error_handler.read())
133 .field(
134 "periodic_flusher",
135 &self
136 .periodic_flusher
137 .lock()
138 .as_deref()
139 .map(|opt| opt.as_ref().map(|(dur, _)| *dur))
140 .as_ref()
141 .map(|dur| dur as &dyn Debug)
142 .unwrap_or(&"*lock is poisoned*"),
143 )
144 .finish()
145 }
146}
147
148impl Logger {
149 #[must_use]
167 pub fn builder() -> LoggerBuilder {
168 LoggerBuilder {
169 name: None,
170 level_filter: LevelFilter::MoreSevereEqual(Level::Info),
171 sinks: vec![],
172 flush_level_filter: LevelFilter::Off,
173 error_handler: ErrorHandler::default(),
174 }
175 }
176
177 #[must_use]
181 pub fn name(&self) -> Option<&str> {
182 self.name.as_ref().map(|s| s.as_ref())
183 }
184
185 pub fn set_name<S>(&mut self, name: Option<S>) -> StdResult<(), SetLoggerNameError>
187 where
188 S: Into<String>,
189 {
190 if let Some(name) = name {
191 let name = name.into();
192 check_logger_name(&name)?;
193 self.name = Some(name);
194 } else {
195 self.name = None;
196 }
197 Ok(())
198 }
199
200 #[must_use]
225 pub fn should_log(&self, level: Level) -> bool {
226 self.level_filter().test(level)
227 }
228
229 pub fn log(&self, record: &Record) {
238 if !self.should_log(record.level()) {
239 return;
240 }
241 self.sink_record(record);
242 }
243
244 pub fn flush(&self) {
255 self.flush_sinks();
256 }
257
258 #[must_use]
260 pub fn flush_level_filter(&self) -> LevelFilter {
261 self.flush_level_filter.get()
262 }
263
264 pub fn set_flush_level_filter(&self, level_filter: LevelFilter) {
289 self.flush_level_filter.set(level_filter);
290 }
291
292 #[must_use]
294 pub fn level_filter(&self) -> LevelFilter {
295 self.level_filter.get()
296 }
297
298 pub fn set_level_filter(&self, level_filter: LevelFilter) {
304 self.level_filter.set(level_filter);
305 }
306
307 pub fn set_flush_period(self: &Arc<Self>, interval: Option<Duration>) {
337 let mut periodic_flusher = self.periodic_flusher.lock_expect();
338
339 *periodic_flusher = None;
340
341 if let Some(interval) = interval {
342 let weak = Arc::downgrade(self);
343 let callback = move || {
344 let strong = weak.upgrade();
345 if let Some(strong) = strong {
346 strong.flush_sinks();
347 true
348 } else {
349 false }
352 };
353 *periodic_flusher = Some((interval, PeriodicWorker::new(callback, interval)));
354 }
355 }
356
357 #[must_use]
359 pub fn sinks(&self) -> &[Arc<dyn Sink>] {
360 &self.sinks
361 }
362
363 #[must_use]
365 pub fn sinks_mut(&mut self) -> &mut Sinks {
366 &mut self.sinks
367 }
368
369 pub fn set_error_handler<F: Into<ErrorHandler>>(&self, handler: F) {
384 *self.error_handler.write_expect() = handler.into();
385 }
386
387 #[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
399 pub fn fork_with<F>(self: &Arc<Self>, modifier: F) -> Result<Arc<Self>>
421 where
422 F: FnOnce(&mut Logger) -> Result<()>,
423 {
424 let flush_period = self.periodic_flusher.lock_expect().as_ref().map(|v| v.0);
425
426 let mut new_logger = self.clone_lossy();
427 modifier(&mut new_logger)?;
428
429 let new_logger = Arc::new(new_logger);
430 if let Some(interval) = flush_period {
431 new_logger.set_flush_period(Some(interval));
432 }
433
434 Ok(new_logger)
435 }
436
437 pub fn fork_with_name<S>(self: &Arc<Self>, new_name: Option<S>) -> Result<Arc<Self>>
460 where
461 S: Into<String>,
462 {
463 self.fork_with(|new| {
464 new.set_name(new_name).map_err(InvalidArgumentError::from)?;
465 Ok(())
466 })
467 }
468
469 #[must_use]
471 fn clone_lossy(&self) -> Self {
472 Logger {
473 name: self.name.clone(),
474 level_filter: AtomicLevelFilter::new(self.level_filter()),
475 sinks: self.sinks.clone(),
476 flush_level_filter: AtomicLevelFilter::new(self.flush_level_filter()),
477 periodic_flusher: Mutex::new(None),
478 error_handler: RwLock::new(self.error_handler.read_expect().clone()),
479 }
480 }
481
482 fn sink_record(&self, record: &Record) {
483 self.sinks.iter().for_each(|sink| {
484 if sink.should_log(record.level()) {
485 if let Err(err) = sink.log(record) {
486 self.handle_error(err);
487 }
488 }
489 });
490
491 if self.should_flush(record) {
492 self.flush();
493 }
494 }
495
496 fn flush_sinks_with(&self, with: impl Fn(&dyn Sink) -> Result<()>) {
497 self.sinks.iter().for_each(|sink| {
498 if let Err(err) = with(&**sink) {
499 self.handle_error(err);
500 }
501 });
502 }
503
504 pub(crate) fn flush_sinks_on_exit(&self) {
505 self.flush_sinks_with(|sink| sink.flush_on_exit());
506 }
507
508 pub(crate) fn flush_sinks(&self) {
509 self.flush_sinks_with(|sink| sink.flush());
510 }
511
512 fn handle_error(&self, err: Error) {
513 self.error_handler.read_expect().call_internal(
514 format!(
515 "Logger ({})",
516 self.name.as_ref().map_or("*no name*", String::as_str)
517 ),
518 err,
519 );
520 }
521
522 #[must_use]
523 fn should_flush(&self, record: &Record) -> bool {
524 self.flush_level_filter().test(record.level())
525 }
526}
527
528impl Clone for Logger {
529 fn clone(&self) -> Self {
536 if self.periodic_flusher.lock_expect().is_some() {
537 panic!(
538 "you can't clone a `Logger` with a `flush_period` value, \
539 clone a `Arc<Logger>` instead."
540 );
541 }
542 self.clone_lossy()
543 }
544}
545
546#[allow(missing_docs)]
547#[derive(Clone)]
548pub struct LoggerBuilder {
549 name: Option<String>,
550 level_filter: LevelFilter,
551 sinks: Sinks,
552 flush_level_filter: LevelFilter,
553 error_handler: ErrorHandler,
554}
555
556impl LoggerBuilder {
557 #[allow(clippy::new_without_default)]
559 #[deprecated(
560 since = "0.3.0",
561 note = "it may be removed in the future, use `Logger::builder()` instead"
562 )]
563 #[must_use]
564 pub fn new() -> Self {
565 Logger::builder()
566 }
567
568 pub fn name<S>(&mut self, name: S) -> &mut Self
580 where
581 S: Into<String>,
582 {
583 self.name = Some(name.into());
584 self
585 }
586
587 pub fn level_filter(&mut self, level_filter: LevelFilter) -> &mut Self {
591 self.level_filter = level_filter;
592 self
593 }
594
595 pub fn sink(&mut self, sink: Arc<dyn Sink>) -> &mut Self {
597 self.sinks.push(sink);
598 self
599 }
600
601 pub fn sinks<I>(&mut self, sinks: I) -> &mut Self
603 where
604 I: IntoIterator<Item = Arc<dyn Sink>>,
605 {
606 self.sinks.append(&mut sinks.into_iter().collect());
607 self
608 }
609
610 pub fn flush_level_filter(&mut self, level_filter: LevelFilter) -> &mut Self {
617 self.flush_level_filter = level_filter;
618 self
619 }
620
621 pub fn error_handler<F: Into<ErrorHandler>>(&mut self, handler: F) -> &mut Self {
629 self.error_handler = handler.into();
630 self
631 }
632
633 pub fn build(&mut self) -> Result<Logger> {
635 self.build_inner(self.preset_level(false))
636 }
637
638 pub fn build_arc(&mut self) -> Result<Arc<Logger>> {
649 self.build().map(Arc::new)
650 }
651
652 pub(crate) fn build_default(&mut self) -> Result<Logger> {
653 self.build_inner(self.preset_level(true))
654 }
655
656 #[must_use]
657 fn preset_level(&self, is_default: bool) -> Option<LevelFilter> {
658 if is_default {
659 env_level::logger_level(env_level::LoggerKind::Default)
660 } else {
661 env_level::logger_level(env_level::LoggerKind::Other(self.name.as_deref()))
662 }
663 }
664
665 fn build_inner(&mut self, preset_level: Option<LevelFilter>) -> Result<Logger> {
666 if let Some(name) = &self.name {
667 check_logger_name(name).map_err(InvalidArgumentError::from)?;
668 }
669
670 let logger = Logger {
671 name: self.name.clone(),
672 level_filter: AtomicLevelFilter::new(self.level_filter),
673 sinks: self.sinks.clone(),
674 flush_level_filter: AtomicLevelFilter::new(self.flush_level_filter),
675 error_handler: RwLock::new(self.error_handler.clone()),
676 periodic_flusher: Mutex::new(None),
677 };
678
679 if let Some(preset_level) = preset_level {
680 logger.set_level_filter(preset_level);
681 }
682
683 Ok(logger)
684 }
685
686 #[cfg(test)]
687 #[must_use]
688 fn build_inner_for_test(&mut self, env_level: &str, is_default: bool) -> Logger {
689 let preset_level = if is_default {
690 env_level::logger_level_inner(
691 &env_level::from_str_inner(env_level).unwrap(),
692 env_level::LoggerKind::Default,
693 )
694 } else {
695 env_level::logger_level_inner(
696 &env_level::from_str_inner(env_level).unwrap(),
697 env_level::LoggerKind::Other(self.name.as_deref()),
698 )
699 };
700
701 self.build_inner(preset_level).unwrap()
702 }
703}
704
705#[cfg(test)]
706mod tests {
707 use std::{thread, time::Duration};
708
709 use super::*;
710 use crate::{prelude::*, test_utils::*};
711
712 #[test]
713 fn logger_traits() {
714 assert_trait!(Logger: Send + Sync + Debug);
715 }
716
717 #[test]
718 fn flush_level() {
719 let test_sink = Arc::new(TestSink::new());
720 let test_logger = Logger::builder().sink(test_sink.clone()).build().unwrap();
721
722 trace!(logger: test_logger, "");
723 error!(logger: test_logger, "");
724 assert_eq!(test_sink.flush_count(), 0);
725 test_sink.reset();
726
727 test_logger.set_flush_level_filter(LevelFilter::MoreSevereEqual(Level::Warn));
728 debug!(logger: test_logger, "");
729 warn!(logger: test_logger, "");
730 assert_eq!(test_sink.flush_count(), 1);
731 test_sink.reset();
732
733 test_logger.set_flush_level_filter(LevelFilter::Off);
734 info!(logger: test_logger, "");
735 trace!(logger: test_logger, "");
736 assert_eq!(test_sink.flush_count(), 0);
737 test_sink.reset();
738
739 test_logger.set_flush_level_filter(LevelFilter::MoreSevereEqual(Level::Trace));
740 info!(logger: test_logger, "");
741 warn!(logger: test_logger, "");
742 assert_eq!(test_sink.flush_count(), 2);
743 test_sink.reset();
744 }
745
746 #[test]
747 fn periodic_flush() {
748 let test_sink = Arc::new(TestSink::new());
749 let test_logger = Logger::builder()
750 .sink(test_sink.clone())
751 .build_arc()
752 .unwrap();
753
754 test_logger.set_flush_period(Some(Duration::from_secs(1)));
755
756 assert_eq!(test_sink.flush_count(), 0);
757
758 thread::sleep(Duration::from_millis(1250));
759 assert_eq!(test_sink.flush_count(), 1);
760
761 thread::sleep(Duration::from_millis(1250));
762 assert_eq!(test_sink.flush_count(), 2);
763
764 test_logger.set_flush_period(None);
765
766 thread::sleep(Duration::from_millis(1250));
767 assert_eq!(test_sink.flush_count(), 2);
768
769 test_logger.set_flush_period(Some(Duration::from_secs(1)));
770
771 thread::sleep(Duration::from_millis(1250));
772 assert_eq!(test_sink.flush_count(), 3);
773 }
774
775 #[test]
776 fn builder_name() {
777 Logger::builder().name("hello-world");
778
779 macro_rules! assert_name_err {
780 ( $($name:literal),+ $(,)? ) => {
781 $(match Logger::builder().name($name).build() {
782 Err(Error::InvalidArgument(InvalidArgumentError::LoggerName(err))) => {
783 assert_eq!(err.name(), $name)
784 }
785 _ => panic!("test case '{}' failed", $name),
786 })+
787 };
788 }
789
790 assert_name_err! {
791 " hello", "hello ",
792 "hello,world", "hello=world", "hello*world", "hello?world", "hello$world",
793 "hello{world", "hello}world", r#"hello"world"#, "hello'world", "hello;world",
794 };
795 }
796
797 #[test]
798 fn env_level() {
799 macro_rules! assert_levels {
800 ($env_level:literal, DEFAULT => $default:expr, UNNAMED => $unnamed:expr, NAMED($name:literal) => $named:expr $(,)?) => {
801 assert_eq!(
802 Logger::builder()
803 .build_inner_for_test($env_level, true)
804 .level_filter(),
805 $default
806 );
807 assert_eq!(
808 Logger::builder()
809 .build_inner_for_test($env_level, false)
810 .level_filter(),
811 $unnamed
812 );
813 assert_eq!(
814 Logger::builder()
815 .name($name)
816 .build_inner_for_test($env_level, false)
817 .level_filter(),
818 $named
819 );
820 };
821 (_, DEFAULT => $default:expr, UNNAMED => $unnamed:expr, NAMED($name:literal) => $named:expr $(,)?) => {
822 assert_eq!(
823 Logger::builder().build_default().unwrap().level_filter(),
824 $default
825 );
826 assert_eq!(Logger::builder().build().unwrap().level_filter(), $unnamed);
827 assert_eq!(
828 Logger::builder()
829 .name($name)
830 .build()
831 .unwrap()
832 .level_filter(),
833 $named
834 );
835 };
836 }
837
838 let unchanged = LevelFilter::MoreSevereEqual(Level::Info);
839
840 assert_levels!(
841 _,
842 DEFAULT => unchanged,
843 UNNAMED => unchanged,
844 NAMED("name") => unchanged,
845 );
846
847 assert_levels!(
848 "deBug",
849 DEFAULT => LevelFilter::MoreSevereEqual(Level::Debug),
850 UNNAMED => unchanged,
851 NAMED("name") => unchanged,
852 );
853
854 assert_levels!(
855 "deBug,*=tRace",
856 DEFAULT => LevelFilter::MoreSevereEqual(Level::Debug),
857 UNNAMED => LevelFilter::MoreSevereEqual(Level::Trace),
858 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Trace),
859 );
860
861 assert_levels!(
862 "=trAce",
863 DEFAULT => unchanged,
864 UNNAMED => LevelFilter::MoreSevereEqual(Level::Trace),
865 NAMED("name") => unchanged,
866 );
867
868 assert_levels!(
869 "*=waRn",
870 DEFAULT => unchanged,
871 UNNAMED => LevelFilter::MoreSevereEqual(Level::Warn),
872 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Warn),
873 );
874
875 assert_levels!(
876 "=eRror,*=waRn",
877 DEFAULT => unchanged,
878 UNNAMED => LevelFilter::MoreSevereEqual(Level::Error),
879 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Warn),
880 );
881
882 assert_levels!(
883 "=eRror,*=waRn,name=trAce",
884 DEFAULT => unchanged,
885 UNNAMED => LevelFilter::MoreSevereEqual(Level::Error),
886 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Trace),
887 );
888
889 assert_levels!(
890 "all,*=all",
891 DEFAULT => LevelFilter::All,
892 UNNAMED => LevelFilter::All,
893 NAMED("name") => LevelFilter::All,
894 );
895
896 assert_levels!(
897 "off,*=all",
898 DEFAULT => LevelFilter::Off,
899 UNNAMED => LevelFilter::All,
900 NAMED("name") => LevelFilter::All,
901 );
902 }
903
904 #[test]
905 fn fork_logger() {
906 let test_sink = (Arc::new(TestSink::new()), Arc::new(TestSink::new()));
907 let logger = Arc::new(build_test_logger(|b| b.sink(test_sink.0.clone())));
908
909 assert!(logger.name().is_none());
910 assert_eq!(test_sink.0.log_count(), 0);
911 assert_eq!(test_sink.0.flush_count(), 0);
912 assert_eq!(test_sink.1.log_count(), 0);
913 assert_eq!(test_sink.1.flush_count(), 0);
914
915 info!(logger: logger, "qwq");
916 assert!(logger.name().is_none());
917 assert_eq!(test_sink.0.log_count(), 1);
918 assert_eq!(test_sink.0.flush_count(), 0);
919 assert_eq!(test_sink.1.log_count(), 0);
920 assert_eq!(test_sink.1.flush_count(), 0);
921
922 let old = logger;
923 let new = old.fork_with_name(Some("cat")).unwrap();
924 info!(logger: new, "meow");
925 assert!(old.name().is_none());
926 assert_eq!(new.name(), Some("cat"));
927 assert_eq!(test_sink.0.log_count(), 2);
928 assert_eq!(test_sink.0.flush_count(), 0);
929 assert_eq!(test_sink.1.log_count(), 0);
930 assert_eq!(test_sink.1.flush_count(), 0);
931
932 let old = new;
933 let new = old
934 .fork_with(|new| {
935 new.set_name(Some("dog")).unwrap();
936 new.sinks_mut().push(test_sink.1.clone());
937 Ok(())
938 })
939 .unwrap();
940 info!(logger: new, "woof");
941 assert_eq!(old.name(), Some("cat"));
942 assert_eq!(new.name(), Some("dog"));
943 assert_eq!(test_sink.0.log_count(), 3);
944 assert_eq!(test_sink.0.flush_count(), 0);
945 assert_eq!(test_sink.1.log_count(), 1);
946 assert_eq!(test_sink.1.flush_count(), 0);
947
948 assert!(matches!(
949 new.fork_with_name(Some("invalid,name")),
950 Err(Error::InvalidArgument(InvalidArgumentError::LoggerName(_)))
951 ));
952
953 assert!(new
954 .fork_with_name(None as Option<&str>)
955 .unwrap()
956 .name()
957 .is_none());
958
959 let test_sink = (Arc::new(TestSink::new()), Arc::new(TestSink::new()));
960 let old = Arc::new(build_test_logger(|b| b.sink(test_sink.0.clone())));
961 old.set_flush_period(Some(Duration::from_secs(1)));
962 std::thread::sleep(Duration::from_millis(1250));
963
964 let _new = old
965 .fork_with(|new| {
966 new.sinks_mut().clear();
967 new.sinks_mut().push(test_sink.1.clone());
968 Ok(())
969 })
970 .unwrap();
971 std::thread::sleep(Duration::from_millis(1250));
972
973 assert_eq!(test_sink.0.log_count(), 0);
974 assert_eq!(test_sink.0.flush_count(), 2);
975 assert_eq!(test_sink.1.log_count(), 0);
976 assert_eq!(test_sink.1.flush_count(), 1);
977 }
978}