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) {
385 *self.error_handler.write_expect() = handler.into();
386 }
387
388 #[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
400 pub fn fork_with<F>(self: &Arc<Self>, modifier: F) -> Result<Arc<Self>>
422 where
423 F: FnOnce(&mut Logger) -> Result<()>,
424 {
425 let flush_period = self.periodic_flusher.lock_expect().as_ref().map(|v| v.0);
426
427 let mut new_logger = self.clone_lossy();
428 modifier(&mut new_logger)?;
429
430 let new_logger = Arc::new(new_logger);
431 if let Some(interval) = flush_period {
432 new_logger.set_flush_period(Some(interval));
433 }
434
435 Ok(new_logger)
436 }
437
438 pub fn fork_with_name<S>(self: &Arc<Self>, new_name: Option<S>) -> Result<Arc<Self>>
461 where
462 S: Into<String>,
463 {
464 self.fork_with(|new| {
465 new.set_name(new_name).map_err(InvalidArgumentError::from)?;
466 Ok(())
467 })
468 }
469
470 #[must_use]
472 fn clone_lossy(&self) -> Self {
473 Logger {
474 name: self.name.clone(),
475 level_filter: AtomicLevelFilter::new(self.level_filter()),
476 sinks: self.sinks.clone(),
477 flush_level_filter: AtomicLevelFilter::new(self.flush_level_filter()),
478 periodic_flusher: Mutex::new(None),
479 error_handler: RwLock::new(self.error_handler.read_expect().clone()),
480 }
481 }
482
483 fn sink_record(&self, record: &Record) {
484 self.sinks.iter().for_each(|sink| {
485 if sink.should_log(record.level()) {
486 if let Err(err) = sink.log(record) {
487 self.handle_error(err);
488 }
489 }
490 });
491
492 if self.should_flush(record) {
493 self.flush();
494 }
495 }
496
497 fn flush_sinks_with(&self, with: impl Fn(&dyn Sink) -> Result<()>) {
498 self.sinks.iter().for_each(|sink| {
499 if let Err(err) = with(&**sink) {
500 self.handle_error(err);
501 }
502 });
503 }
504
505 pub(crate) fn flush_sinks_on_exit(&self) {
506 self.flush_sinks_with(|sink| sink.flush_on_exit());
507 }
508
509 pub(crate) fn flush_sinks(&self) {
510 self.flush_sinks_with(|sink| sink.flush());
511 }
512
513 fn handle_error(&self, err: Error) {
514 self.error_handler.read_expect().call_internal(
515 format!(
516 "Logger ({})",
517 self.name.as_ref().map_or("*no name*", String::as_str)
518 ),
519 err,
520 );
521 }
522
523 #[must_use]
524 fn should_flush(&self, record: &Record) -> bool {
525 self.flush_level_filter().test(record.level())
526 }
527}
528
529impl Clone for Logger {
530 fn clone(&self) -> Self {
537 if self.periodic_flusher.lock_expect().is_some() {
538 panic!(
539 "you can't clone a `Logger` with a `flush_period` value, \
540 clone a `Arc<Logger>` instead."
541 );
542 }
543 self.clone_lossy()
544 }
545}
546
547#[allow(missing_docs)]
548#[derive(Clone)]
549pub struct LoggerBuilder {
550 name: Option<String>,
551 level_filter: LevelFilter,
552 sinks: Sinks,
553 flush_level_filter: LevelFilter,
554 error_handler: ErrorHandler,
555}
556
557impl LoggerBuilder {
558 #[allow(clippy::new_without_default)]
560 #[deprecated(
561 since = "0.3.0",
562 note = "it may be removed in the future, use `Logger::builder()` instead"
563 )]
564 #[must_use]
565 pub fn new() -> Self {
566 Logger::builder()
567 }
568
569 pub fn name<S>(&mut self, name: S) -> &mut Self
581 where
582 S: Into<String>,
583 {
584 self.name = Some(name.into());
585 self
586 }
587
588 pub fn level_filter(&mut self, level_filter: LevelFilter) -> &mut Self {
592 self.level_filter = level_filter;
593 self
594 }
595
596 pub fn sink(&mut self, sink: Arc<dyn Sink>) -> &mut Self {
598 self.sinks.push(sink);
599 self
600 }
601
602 pub fn sinks<I>(&mut self, sinks: I) -> &mut Self
604 where
605 I: IntoIterator<Item = Arc<dyn Sink>>,
606 {
607 self.sinks.append(&mut sinks.into_iter().collect());
608 self
609 }
610
611 pub fn flush_level_filter(&mut self, level_filter: LevelFilter) -> &mut Self {
618 self.flush_level_filter = level_filter;
619 self
620 }
621
622 pub fn error_handler<F: Into<ErrorHandler>>(&mut self, handler: F) -> &mut Self {
630 self.error_handler = handler.into();
631 self
632 }
633
634 pub fn build(&mut self) -> Result<Logger> {
636 self.build_inner(self.preset_level(false))
637 }
638
639 pub fn build_arc(&mut self) -> Result<Arc<Logger>> {
650 self.build().map(Arc::new)
651 }
652
653 pub(crate) fn build_default(&mut self) -> Result<Logger> {
654 self.build_inner(self.preset_level(true))
655 }
656
657 #[must_use]
658 fn preset_level(&self, is_default: bool) -> Option<LevelFilter> {
659 if is_default {
660 env_level::logger_level(env_level::LoggerKind::Default)
661 } else {
662 env_level::logger_level(env_level::LoggerKind::Other(self.name.as_deref()))
663 }
664 }
665
666 fn build_inner(&mut self, preset_level: Option<LevelFilter>) -> Result<Logger> {
667 if let Some(name) = &self.name {
668 check_logger_name(name).map_err(InvalidArgumentError::from)?;
669 }
670
671 let logger = Logger {
672 name: self.name.clone(),
673 level_filter: AtomicLevelFilter::new(self.level_filter),
674 sinks: self.sinks.clone(),
675 flush_level_filter: AtomicLevelFilter::new(self.flush_level_filter),
676 error_handler: RwLock::new(self.error_handler.clone()),
677 periodic_flusher: Mutex::new(None),
678 };
679
680 if let Some(preset_level) = preset_level {
681 logger.set_level_filter(preset_level);
682 }
683
684 Ok(logger)
685 }
686
687 #[cfg(test)]
688 #[must_use]
689 fn build_inner_for_test(&mut self, env_level: &str, is_default: bool) -> Logger {
690 let preset_level = if is_default {
691 env_level::logger_level_inner(
692 &env_level::from_str_inner(env_level).unwrap(),
693 env_level::LoggerKind::Default,
694 )
695 } else {
696 env_level::logger_level_inner(
697 &env_level::from_str_inner(env_level).unwrap(),
698 env_level::LoggerKind::Other(self.name.as_deref()),
699 )
700 };
701
702 self.build_inner(preset_level).unwrap()
703 }
704}
705
706#[cfg(test)]
707mod tests {
708 use std::{thread, time::Duration};
709
710 use super::*;
711 use crate::{prelude::*, test_utils::*};
712
713 #[test]
714 fn logger_traits() {
715 assert_trait!(Logger: Send + Sync + Debug);
716 }
717
718 #[test]
719 fn flush_level() {
720 let test_sink = Arc::new(TestSink::new());
721 let test_logger = Logger::builder().sink(test_sink.clone()).build().unwrap();
722
723 trace!(logger: test_logger, "");
724 error!(logger: test_logger, "");
725 assert_eq!(test_sink.flush_count(), 0);
726 test_sink.reset();
727
728 test_logger.set_flush_level_filter(LevelFilter::MoreSevereEqual(Level::Warn));
729 debug!(logger: test_logger, "");
730 warn!(logger: test_logger, "");
731 assert_eq!(test_sink.flush_count(), 1);
732 test_sink.reset();
733
734 test_logger.set_flush_level_filter(LevelFilter::Off);
735 info!(logger: test_logger, "");
736 trace!(logger: test_logger, "");
737 assert_eq!(test_sink.flush_count(), 0);
738 test_sink.reset();
739
740 test_logger.set_flush_level_filter(LevelFilter::MoreSevereEqual(Level::Trace));
741 info!(logger: test_logger, "");
742 warn!(logger: test_logger, "");
743 assert_eq!(test_sink.flush_count(), 2);
744 test_sink.reset();
745 }
746
747 #[test]
748 fn periodic_flush() {
749 let test_sink = Arc::new(TestSink::new());
750 let test_logger = Logger::builder()
751 .sink(test_sink.clone())
752 .build_arc()
753 .unwrap();
754
755 test_logger.set_flush_period(Some(Duration::from_secs(1)));
756
757 assert_eq!(test_sink.flush_count(), 0);
758
759 thread::sleep(Duration::from_millis(1250));
760 assert_eq!(test_sink.flush_count(), 1);
761
762 thread::sleep(Duration::from_millis(1250));
763 assert_eq!(test_sink.flush_count(), 2);
764
765 test_logger.set_flush_period(None);
766
767 thread::sleep(Duration::from_millis(1250));
768 assert_eq!(test_sink.flush_count(), 2);
769
770 test_logger.set_flush_period(Some(Duration::from_secs(1)));
771
772 thread::sleep(Duration::from_millis(1250));
773 assert_eq!(test_sink.flush_count(), 3);
774 }
775
776 #[test]
777 fn builder_name() {
778 Logger::builder().name("hello-world");
779
780 macro_rules! assert_name_err {
781 ( $($name:literal),+ $(,)? ) => {
782 $(match Logger::builder().name($name).build() {
783 Err(Error::InvalidArgument(InvalidArgumentError::LoggerName(err))) => {
784 assert_eq!(err.name(), $name)
785 }
786 _ => panic!("test case '{}' failed", $name),
787 })+
788 };
789 }
790
791 assert_name_err! {
792 " hello", "hello ",
793 "hello,world", "hello=world", "hello*world", "hello?world", "hello$world",
794 "hello{world", "hello}world", r#"hello"world"#, "hello'world", "hello;world",
795 };
796 }
797
798 #[test]
799 fn env_level() {
800 macro_rules! assert_levels {
801 ($env_level:literal, DEFAULT => $default:expr, UNNAMED => $unnamed:expr, NAMED($name:literal) => $named:expr $(,)?) => {
802 assert_eq!(
803 Logger::builder()
804 .build_inner_for_test($env_level, true)
805 .level_filter(),
806 $default
807 );
808 assert_eq!(
809 Logger::builder()
810 .build_inner_for_test($env_level, false)
811 .level_filter(),
812 $unnamed
813 );
814 assert_eq!(
815 Logger::builder()
816 .name($name)
817 .build_inner_for_test($env_level, false)
818 .level_filter(),
819 $named
820 );
821 };
822 (_, DEFAULT => $default:expr, UNNAMED => $unnamed:expr, NAMED($name:literal) => $named:expr $(,)?) => {
823 assert_eq!(
824 Logger::builder().build_default().unwrap().level_filter(),
825 $default
826 );
827 assert_eq!(Logger::builder().build().unwrap().level_filter(), $unnamed);
828 assert_eq!(
829 Logger::builder()
830 .name($name)
831 .build()
832 .unwrap()
833 .level_filter(),
834 $named
835 );
836 };
837 }
838
839 let unchanged = LevelFilter::MoreSevereEqual(Level::Info);
840
841 assert_levels!(
842 _,
843 DEFAULT => unchanged,
844 UNNAMED => unchanged,
845 NAMED("name") => unchanged,
846 );
847
848 assert_levels!(
849 "deBug",
850 DEFAULT => LevelFilter::MoreSevereEqual(Level::Debug),
851 UNNAMED => unchanged,
852 NAMED("name") => unchanged,
853 );
854
855 assert_levels!(
856 "deBug,*=tRace",
857 DEFAULT => LevelFilter::MoreSevereEqual(Level::Debug),
858 UNNAMED => LevelFilter::MoreSevereEqual(Level::Trace),
859 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Trace),
860 );
861
862 assert_levels!(
863 "=trAce",
864 DEFAULT => unchanged,
865 UNNAMED => LevelFilter::MoreSevereEqual(Level::Trace),
866 NAMED("name") => unchanged,
867 );
868
869 assert_levels!(
870 "*=waRn",
871 DEFAULT => unchanged,
872 UNNAMED => LevelFilter::MoreSevereEqual(Level::Warn),
873 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Warn),
874 );
875
876 assert_levels!(
877 "=eRror,*=waRn",
878 DEFAULT => unchanged,
879 UNNAMED => LevelFilter::MoreSevereEqual(Level::Error),
880 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Warn),
881 );
882
883 assert_levels!(
884 "=eRror,*=waRn,name=trAce",
885 DEFAULT => unchanged,
886 UNNAMED => LevelFilter::MoreSevereEqual(Level::Error),
887 NAMED("name") => LevelFilter::MoreSevereEqual(Level::Trace),
888 );
889
890 assert_levels!(
891 "all,*=all",
892 DEFAULT => LevelFilter::All,
893 UNNAMED => LevelFilter::All,
894 NAMED("name") => LevelFilter::All,
895 );
896
897 assert_levels!(
898 "off,*=all",
899 DEFAULT => LevelFilter::Off,
900 UNNAMED => LevelFilter::All,
901 NAMED("name") => LevelFilter::All,
902 );
903 }
904
905 #[test]
906 fn fork_logger() {
907 let test_sink = (Arc::new(TestSink::new()), Arc::new(TestSink::new()));
908 let logger = Arc::new(build_test_logger(|b| b.sink(test_sink.0.clone())));
909
910 assert!(logger.name().is_none());
911 assert_eq!(test_sink.0.log_count(), 0);
912 assert_eq!(test_sink.0.flush_count(), 0);
913 assert_eq!(test_sink.1.log_count(), 0);
914 assert_eq!(test_sink.1.flush_count(), 0);
915
916 info!(logger: logger, "qwq");
917 assert!(logger.name().is_none());
918 assert_eq!(test_sink.0.log_count(), 1);
919 assert_eq!(test_sink.0.flush_count(), 0);
920 assert_eq!(test_sink.1.log_count(), 0);
921 assert_eq!(test_sink.1.flush_count(), 0);
922
923 let old = logger;
924 let new = old.fork_with_name(Some("cat")).unwrap();
925 info!(logger: new, "meow");
926 assert!(old.name().is_none());
927 assert_eq!(new.name(), Some("cat"));
928 assert_eq!(test_sink.0.log_count(), 2);
929 assert_eq!(test_sink.0.flush_count(), 0);
930 assert_eq!(test_sink.1.log_count(), 0);
931 assert_eq!(test_sink.1.flush_count(), 0);
932
933 let old = new;
934 let new = old
935 .fork_with(|new| {
936 new.set_name(Some("dog")).unwrap();
937 new.sinks_mut().push(test_sink.1.clone());
938 Ok(())
939 })
940 .unwrap();
941 info!(logger: new, "woof");
942 assert_eq!(old.name(), Some("cat"));
943 assert_eq!(new.name(), Some("dog"));
944 assert_eq!(test_sink.0.log_count(), 3);
945 assert_eq!(test_sink.0.flush_count(), 0);
946 assert_eq!(test_sink.1.log_count(), 1);
947 assert_eq!(test_sink.1.flush_count(), 0);
948
949 assert!(matches!(
950 new.fork_with_name(Some("invalid,name")),
951 Err(Error::InvalidArgument(InvalidArgumentError::LoggerName(_)))
952 ));
953
954 assert!(new
955 .fork_with_name(None as Option<&str>)
956 .unwrap()
957 .name()
958 .is_none());
959
960 let test_sink = (Arc::new(TestSink::new()), Arc::new(TestSink::new()));
961 let old = Arc::new(build_test_logger(|b| b.sink(test_sink.0.clone())));
962 old.set_flush_period(Some(Duration::from_secs(1)));
963 std::thread::sleep(Duration::from_millis(1250));
964
965 let _new = old
966 .fork_with(|new| {
967 new.sinks_mut().clear();
968 new.sinks_mut().push(test_sink.1.clone());
969 Ok(())
970 })
971 .unwrap();
972 std::thread::sleep(Duration::from_millis(1250));
973
974 assert_eq!(test_sink.0.log_count(), 0);
975 assert_eq!(test_sink.0.flush_count(), 2);
976 assert_eq!(test_sink.1.log_count(), 0);
977 assert_eq!(test_sink.1.flush_count(), 1);
978 }
979}