1use chrono::{Local, SecondsFormat, Utc};
21use std::collections::BTreeMap;
22use std::fmt::{self, Debug, Display};
23use std::sync::Arc;
24
25pub type LevelMask = u16;
27
28pub mod levels {
30 use super::LevelMask;
31
32 pub const NONE: LevelMask = 0;
33 pub const FATAL: LevelMask = 1;
34 pub const ERROR: LevelMask = 2;
35 pub const WARN: LevelMask = 4;
36 pub const INFO: LevelMask = 8;
37 pub const DEBUG: LevelMask = 16;
38 pub const VERBOSE: LevelMask = 32;
39 pub const TRACE: LevelMask = 64;
40 pub const SILLY: LevelMask = 128;
41 pub const ALL: LevelMask = 255;
42 pub const PRODUCTION: LevelMask = FATAL | ERROR | WARN;
43 pub const DEVELOPMENT: LevelMask = FATAL | ERROR | WARN | INFO | DEBUG;
44}
45
46#[derive(Clone, Copy, Eq, Hash, PartialEq)]
48pub struct Level {
49 mask: LevelMask,
50 name: &'static str,
51}
52
53impl Level {
54 pub const FATAL: Self = Self::new(levels::FATAL, "fatal");
55 pub const ERROR: Self = Self::new(levels::ERROR, "error");
56 pub const WARN: Self = Self::new(levels::WARN, "warn");
57 pub const INFO: Self = Self::new(levels::INFO, "info");
58 pub const DEBUG: Self = Self::new(levels::DEBUG, "debug");
59 pub const VERBOSE: Self = Self::new(levels::VERBOSE, "verbose");
60 pub const TRACE: Self = Self::new(levels::TRACE, "trace");
61 pub const SILLY: Self = Self::new(levels::SILLY, "silly");
62
63 pub const fn new(mask: LevelMask, name: &'static str) -> Self {
64 Self { mask, name }
65 }
66
67 pub const fn mask(self) -> LevelMask {
68 self.mask
69 }
70
71 pub const fn name(self) -> &'static str {
72 self.name
73 }
74
75 pub const fn from_mask(mask: LevelMask) -> Option<Self> {
76 match mask {
77 levels::FATAL => Some(Self::FATAL),
78 levels::ERROR => Some(Self::ERROR),
79 levels::WARN => Some(Self::WARN),
80 levels::INFO => Some(Self::INFO),
81 levels::DEBUG => Some(Self::DEBUG),
82 levels::VERBOSE => Some(Self::VERBOSE),
83 levels::TRACE => Some(Self::TRACE),
84 levels::SILLY => Some(Self::SILLY),
85 _ => None,
86 }
87 }
88}
89
90impl Debug for Level {
91 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
92 formatter
93 .debug_struct("Level")
94 .field("name", &self.name)
95 .field("mask", &self.mask)
96 .finish()
97 }
98}
99
100pub const STANDARD_LEVELS: [Level; 8] = [
102 Level::FATAL,
103 Level::ERROR,
104 Level::WARN,
105 Level::INFO,
106 Level::DEBUG,
107 Level::VERBOSE,
108 Level::TRACE,
109 Level::SILLY,
110];
111
112#[derive(Debug, Clone, Copy, Eq, PartialEq)]
114pub enum LevelSpec<'a> {
115 Mask(LevelMask),
116 Name(&'a str),
117}
118
119impl<'a> From<Level> for LevelSpec<'a> {
120 fn from(level: Level) -> Self {
121 Self::Mask(level.mask())
122 }
123}
124
125impl<'a> From<LevelMask> for LevelSpec<'a> {
126 fn from(mask: LevelMask) -> Self {
127 Self::Mask(mask)
128 }
129}
130
131impl<'a> From<u8> for LevelSpec<'a> {
132 fn from(mask: u8) -> Self {
133 Self::Mask(LevelMask::from(mask))
134 }
135}
136
137impl<'a> From<u32> for LevelSpec<'a> {
138 fn from(mask: u32) -> Self {
139 Self::Mask(LevelMask::try_from(mask).unwrap_or(levels::NONE))
140 }
141}
142
143impl<'a> From<usize> for LevelSpec<'a> {
144 fn from(mask: usize) -> Self {
145 Self::Mask(LevelMask::try_from(mask).unwrap_or(levels::NONE))
146 }
147}
148
149impl<'a> From<i32> for LevelSpec<'a> {
150 fn from(mask: i32) -> Self {
151 Self::Mask(LevelMask::try_from(mask).unwrap_or(levels::NONE))
152 }
153}
154
155impl<'a> From<&'a str> for LevelSpec<'a> {
156 fn from(name: &'a str) -> Self {
157 Self::Name(name)
158 }
159}
160
161impl<'a> From<&'a String> for LevelSpec<'a> {
162 fn from(name: &'a String) -> Self {
163 Self::Name(name.as_str())
164 }
165}
166
167#[derive(Debug, Clone, Eq, PartialEq)]
169pub enum OwnedLevelSpec {
170 Mask(LevelMask),
171 Name(String),
172}
173
174impl From<Level> for OwnedLevelSpec {
175 fn from(level: Level) -> Self {
176 Self::Mask(level.mask())
177 }
178}
179
180impl From<LevelMask> for OwnedLevelSpec {
181 fn from(mask: LevelMask) -> Self {
182 Self::Mask(mask)
183 }
184}
185
186impl From<u8> for OwnedLevelSpec {
187 fn from(mask: u8) -> Self {
188 Self::Mask(LevelMask::from(mask))
189 }
190}
191
192impl From<u32> for OwnedLevelSpec {
193 fn from(mask: u32) -> Self {
194 Self::Mask(LevelMask::try_from(mask).unwrap_or(levels::NONE))
195 }
196}
197
198impl From<usize> for OwnedLevelSpec {
199 fn from(mask: usize) -> Self {
200 Self::Mask(LevelMask::try_from(mask).unwrap_or(levels::NONE))
201 }
202}
203
204impl From<i32> for OwnedLevelSpec {
205 fn from(mask: i32) -> Self {
206 Self::Mask(LevelMask::try_from(mask).unwrap_or(levels::NONE))
207 }
208}
209
210impl From<&str> for OwnedLevelSpec {
211 fn from(name: &str) -> Self {
212 Self::Name(name.to_string())
213 }
214}
215
216impl From<String> for OwnedLevelSpec {
217 fn from(name: String) -> Self {
218 Self::Name(name)
219 }
220}
221
222pub type LogSink = Arc<dyn Fn(Level, String) + Send + Sync + 'static>;
224
225pub struct LogArg {
227 value: LogArgValue,
228}
229
230enum LogArgValue {
231 Text(String),
232 Lazy(Box<dyn FnOnce() -> String + Send + 'static>),
233}
234
235impl LogArg {
236 pub fn text(value: impl Into<String>) -> Self {
238 Self {
239 value: LogArgValue::Text(value.into()),
240 }
241 }
242
243 pub fn lazy<F, M>(value: F) -> Self
246 where
247 F: FnOnce() -> M + Send + 'static,
248 M: Display,
249 {
250 Self {
251 value: LogArgValue::Lazy(Box::new(move || value().to_string())),
252 }
253 }
254
255 pub fn as_text(&self) -> Option<&str> {
257 match &self.value {
258 LogArgValue::Text(value) => Some(value.as_str()),
259 LogArgValue::Lazy(_) => None,
260 }
261 }
262
263 pub fn is_lazy(&self) -> bool {
265 matches!(self.value, LogArgValue::Lazy(_))
266 }
267
268 fn evaluate(self) -> String {
269 match self.value {
270 LogArgValue::Text(value) => value,
271 LogArgValue::Lazy(value) => value(),
272 }
273 }
274}
275
276impl Debug for LogArg {
277 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
278 match &self.value {
279 LogArgValue::Text(value) => formatter.debug_tuple("LogArg::Text").field(value).finish(),
280 LogArgValue::Lazy(_) => formatter.write_str("LogArg::Lazy(..)"),
281 }
282 }
283}
284
285impl From<&str> for LogArg {
286 fn from(value: &str) -> Self {
287 Self::text(value)
288 }
289}
290
291impl From<String> for LogArg {
292 fn from(value: String) -> Self {
293 Self::text(value)
294 }
295}
296
297pub struct PreprocessorOptions {
299 pub args: Vec<LogArg>,
300 pub level: Level,
301}
302
303pub struct PostprocessorOptions {
305 pub message: String,
306 pub level: Level,
307}
308
309pub type Preprocessor = Arc<dyn Fn(PreprocessorOptions) -> Vec<LogArg> + Send + Sync + 'static>;
311
312pub type Postprocessor = Arc<dyn Fn(PostprocessorOptions) -> String + Send + Sync + 'static>;
314
315#[derive(Clone)]
317pub struct LogLazyOptions {
318 level: OwnedLevelSpec,
319 presets: BTreeMap<String, LevelMask>,
320 sink: Option<LogSink>,
321 preprocessors: Vec<Preprocessor>,
322 postprocessors: Vec<Postprocessor>,
323}
324
325impl Debug for LogLazyOptions {
326 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
327 formatter
328 .debug_struct("LogLazyOptions")
329 .field("level", &self.level)
330 .field("presets", &self.presets)
331 .field("has_sink", &self.sink.is_some())
332 .field("preprocessors", &self.preprocessors.len())
333 .field("postprocessors", &self.postprocessors.len())
334 .finish()
335 }
336}
337
338impl Default for LogLazyOptions {
339 fn default() -> Self {
340 Self {
341 level: OwnedLevelSpec::Mask(levels::INFO),
342 presets: BTreeMap::new(),
343 sink: None,
344 preprocessors: Vec::new(),
345 postprocessors: Vec::new(),
346 }
347 }
348}
349
350impl LogLazyOptions {
351 pub fn new() -> Self {
352 Self::default()
353 }
354
355 pub fn level<L>(mut self, level: L) -> Self
356 where
357 L: Into<OwnedLevelSpec>,
358 {
359 self.level = level.into();
360 self
361 }
362
363 pub fn preset(mut self, name: impl Into<String>, mask: LevelMask) -> Self {
364 self.presets.insert(name.into(), mask);
365 self
366 }
367
368 pub fn sink<F>(mut self, sink: F) -> Self
369 where
370 F: Fn(Level, String) + Send + Sync + 'static,
371 {
372 self.sink = Some(Arc::new(sink));
373 self
374 }
375
376 pub fn preprocessor(mut self, preprocessor: Preprocessor) -> Self {
377 self.preprocessors.push(preprocessor);
378 self
379 }
380
381 pub fn preprocessor_fn<F>(mut self, preprocessor: F) -> Self
382 where
383 F: Fn(PreprocessorOptions) -> Vec<LogArg> + Send + Sync + 'static,
384 {
385 self.preprocessors.push(Arc::new(preprocessor));
386 self
387 }
388
389 pub fn postprocessor(mut self, postprocessor: Postprocessor) -> Self {
390 self.postprocessors.push(postprocessor);
391 self
392 }
393
394 pub fn postprocessor_fn<F>(mut self, postprocessor: F) -> Self
395 where
396 F: Fn(PostprocessorOptions) -> String + Send + Sync + 'static,
397 {
398 self.postprocessors.push(Arc::new(postprocessor));
399 self
400 }
401}
402
403pub mod preprocessors {
405 use super::{LogArg, Preprocessor, PreprocessorOptions};
406 use std::sync::Arc;
407
408 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
409 pub enum ContextPosition {
410 Start,
411 End,
412 }
413
414 #[derive(Debug, Clone, Eq, PartialEq)]
415 pub struct AddContextOptions {
416 pub context: String,
417 pub position: ContextPosition,
418 }
419
420 impl AddContextOptions {
421 pub fn new(context: impl Into<String>) -> Self {
422 Self {
423 context: context.into(),
424 position: ContextPosition::End,
425 }
426 }
427
428 pub fn position(mut self, position: ContextPosition) -> Self {
429 self.position = position;
430 self
431 }
432 }
433
434 pub fn add_context(options: AddContextOptions) -> Preprocessor {
435 Arc::new(move |mut preprocessor_options: PreprocessorOptions| {
436 let context = LogArg::text(options.context.clone());
437 match options.position {
438 ContextPosition::Start => {
439 preprocessor_options.args.insert(0, context);
440 preprocessor_options.args
441 }
442 ContextPosition::End => {
443 preprocessor_options.args.push(context);
444 preprocessor_options.args
445 }
446 }
447 })
448 }
449
450 pub struct FilterPredicateOptions<'a> {
451 pub arg: &'a LogArg,
452 pub index: usize,
453 pub level: super::Level,
454 }
455
456 pub struct FilterOptions<F> {
457 pub predicate: F,
458 }
459
460 pub fn filter<F>(options: FilterOptions<F>) -> Preprocessor
461 where
462 F: for<'a> Fn(FilterPredicateOptions<'a>) -> bool + Send + Sync + 'static,
463 {
464 let predicate = options.predicate;
465 Arc::new(move |preprocessor_options: PreprocessorOptions| {
466 let level = preprocessor_options.level;
467 preprocessor_options
468 .args
469 .into_iter()
470 .enumerate()
471 .filter_map(|(index, arg)| {
472 if predicate(FilterPredicateOptions {
473 arg: &arg,
474 index,
475 level,
476 }) {
477 Some(arg)
478 } else {
479 None
480 }
481 })
482 .collect()
483 })
484 }
485
486 pub struct MapTransformOptions {
487 pub arg: LogArg,
488 pub index: usize,
489 pub level: super::Level,
490 }
491
492 pub struct MapOptions<F> {
493 pub transform: F,
494 }
495
496 pub fn map<F>(options: MapOptions<F>) -> Preprocessor
497 where
498 F: Fn(MapTransformOptions) -> LogArg + Send + Sync + 'static,
499 {
500 let transform = options.transform;
501 Arc::new(move |preprocessor_options: PreprocessorOptions| {
502 let level = preprocessor_options.level;
503 preprocessor_options
504 .args
505 .into_iter()
506 .enumerate()
507 .map(|(index, arg)| transform(MapTransformOptions { arg, index, level }))
508 .collect()
509 })
510 }
511}
512
513pub mod postprocessors {
515 use super::{format_timestamp, Postprocessor, PostprocessorOptions};
516 use std::sync::Arc;
517
518 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
519 pub enum TimestampFormat {
520 Iso,
521 Locale,
522 Time,
523 Millis,
524 }
525
526 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
527 pub struct TimestampOptions {
528 pub format: TimestampFormat,
529 }
530
531 impl Default for TimestampOptions {
532 fn default() -> Self {
533 Self {
534 format: TimestampFormat::Iso,
535 }
536 }
537 }
538
539 impl TimestampOptions {
540 pub fn new() -> Self {
541 Self::default()
542 }
543
544 pub fn format(mut self, format: TimestampFormat) -> Self {
545 self.format = format;
546 self
547 }
548 }
549
550 pub fn timestamp(options: TimestampOptions) -> Postprocessor {
551 Arc::new(move |postprocessor_options: PostprocessorOptions| {
552 format!(
553 "[{}] {}",
554 format_timestamp(options.format),
555 postprocessor_options.message
556 )
557 })
558 }
559
560 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
561 pub struct LevelOptions {
562 pub uppercase: bool,
563 }
564
565 impl Default for LevelOptions {
566 fn default() -> Self {
567 Self { uppercase: true }
568 }
569 }
570
571 impl LevelOptions {
572 pub fn new() -> Self {
573 Self::default()
574 }
575
576 pub fn uppercase(mut self, uppercase: bool) -> Self {
577 self.uppercase = uppercase;
578 self
579 }
580 }
581
582 pub fn level(options: LevelOptions) -> Postprocessor {
583 Arc::new(move |postprocessor_options: PostprocessorOptions| {
584 let level_name = if options.uppercase {
585 postprocessor_options.level.name().to_uppercase()
586 } else {
587 postprocessor_options.level.name().to_string()
588 };
589 format!("[{}] {}", level_name, postprocessor_options.message)
590 })
591 }
592
593 #[derive(Debug, Clone, Eq, PartialEq)]
594 pub struct PidOptions {
595 pub label: String,
596 }
597
598 impl Default for PidOptions {
599 fn default() -> Self {
600 Self {
601 label: "PID".to_string(),
602 }
603 }
604 }
605
606 impl PidOptions {
607 pub fn new() -> Self {
608 Self::default()
609 }
610
611 pub fn label(mut self, label: impl Into<String>) -> Self {
612 self.label = label.into();
613 self
614 }
615 }
616
617 pub fn pid(options: PidOptions) -> Postprocessor {
618 Arc::new(move |postprocessor_options: PostprocessorOptions| {
619 format!(
620 "[{}:{}] {}",
621 options.label,
622 std::process::id(),
623 postprocessor_options.message
624 )
625 })
626 }
627
628 #[derive(Debug, Clone, Eq, PartialEq)]
629 pub struct TextOptions {
630 pub text: String,
631 }
632
633 impl TextOptions {
634 pub fn new(text: impl Into<String>) -> Self {
635 Self { text: text.into() }
636 }
637 }
638
639 pub fn prefix(options: TextOptions) -> Postprocessor {
640 Arc::new(move |postprocessor_options: PostprocessorOptions| {
641 format!("{} {}", options.text, postprocessor_options.message)
642 })
643 }
644
645 pub fn suffix(options: TextOptions) -> Postprocessor {
646 Arc::new(move |postprocessor_options: PostprocessorOptions| {
647 format!("{} {}", postprocessor_options.message, options.text)
648 })
649 }
650}
651
652#[derive(Clone)]
654pub struct LogLazy {
655 current_level: LevelMask,
656 presets: BTreeMap<String, LevelMask>,
657 sink: LogSink,
658 preprocessors: Vec<Preprocessor>,
659 postprocessors: Vec<Postprocessor>,
660}
661
662impl Debug for LogLazy {
663 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
664 formatter
665 .debug_struct("LogLazy")
666 .field("current_level", &self.current_level)
667 .field("presets", &self.presets)
668 .field("preprocessors", &self.preprocessors.len())
669 .field("postprocessors", &self.postprocessors.len())
670 .finish_non_exhaustive()
671 }
672}
673
674impl Default for LogLazy {
675 fn default() -> Self {
676 Self {
677 current_level: levels::INFO,
678 presets: default_presets(),
679 sink: Arc::new(default_sink),
680 preprocessors: Vec::new(),
681 postprocessors: Vec::new(),
682 }
683 }
684}
685
686impl LogLazy {
687 pub fn new() -> Self {
689 Self::default()
690 }
691
692 pub fn with_options(options: LogLazyOptions) -> Self {
694 let mut presets = default_presets();
695 for (name, mask) in options.presets {
696 presets.insert(name, mask);
697 }
698
699 let current_level = level_from_owned_spec(options.level, &presets, levels::INFO);
700
701 Self {
702 current_level,
703 presets,
704 sink: options.sink.unwrap_or_else(|| Arc::new(default_sink)),
705 preprocessors: options.preprocessors,
706 postprocessors: options.postprocessors,
707 }
708 }
709
710 pub fn with_level<'a, L>(level: L) -> Self
712 where
713 L: Into<LevelSpec<'a>>,
714 {
715 let mut logger = Self::default();
716 logger.set_level(level);
717 logger
718 }
719
720 pub fn with_level_and_presets<'a, L, I, S>(level: L, presets: I) -> Self
722 where
723 L: Into<LevelSpec<'a>>,
724 I: IntoIterator<Item = (S, LevelMask)>,
725 S: Into<String>,
726 {
727 let mut logger = Self::default();
728 for (name, mask) in presets {
729 logger.add_preset(name, mask);
730 }
731 logger.set_level(level);
732 logger
733 }
734
735 pub fn with_sink<'a, L, F>(level: L, sink: F) -> Self
737 where
738 L: Into<LevelSpec<'a>>,
739 F: Fn(Level, String) + Send + Sync + 'static,
740 {
741 let mut logger = Self::with_level(level);
742 logger.sink = Arc::new(sink);
743 logger
744 }
745
746 pub fn add_preset(&mut self, name: impl Into<String>, mask: LevelMask) {
748 self.presets.insert(name.into(), mask);
749 }
750
751 pub const fn level(&self) -> LevelMask {
753 self.current_level
754 }
755
756 pub fn set_level<'a, L>(&mut self, level: L)
758 where
759 L: Into<LevelSpec<'a>>,
760 {
761 self.current_level = self.level_or_default(level, levels::INFO);
762 }
763
764 pub fn level_or_default<'a, L>(&self, level: L, default: LevelMask) -> LevelMask
766 where
767 L: Into<LevelSpec<'a>>,
768 {
769 match level.into() {
770 LevelSpec::Mask(mask) => mask,
771 LevelSpec::Name(name) => self
772 .presets
773 .get(name)
774 .copied()
775 .or_else(|| builtin_level_mask(name))
776 .or_else(|| name.parse::<LevelMask>().ok())
777 .unwrap_or(default),
778 }
779 }
780
781 pub fn should_log<'a, L>(&self, level: L) -> bool
783 where
784 L: Into<LevelSpec<'a>>,
785 {
786 if self.current_level == levels::NONE {
787 return false;
788 }
789
790 let level_mask = self.level_or_default(level, levels::NONE);
791 level_mask != levels::NONE && (self.current_level & level_mask) != 0
792 }
793
794 pub fn enable_level<'a, L>(&mut self, level: L)
796 where
797 L: Into<LevelSpec<'a>>,
798 {
799 let level_mask = self.level_or_default(level, levels::NONE);
800 self.current_level |= level_mask;
801 }
802
803 pub fn disable_level<'a, L>(&mut self, level: L)
805 where
806 L: Into<LevelSpec<'a>>,
807 {
808 let level_mask = self.level_or_default(level, levels::NONE);
809 self.current_level &= !level_mask;
810 }
811
812 pub fn get_enabled_levels(&self) -> Vec<&'static str> {
814 STANDARD_LEVELS
815 .iter()
816 .filter(|level| self.should_log(level.mask()))
817 .map(|level| level.name())
818 .collect()
819 }
820
821 pub fn log<F, M>(&self, message: F)
823 where
824 F: FnOnce() -> M,
825 M: Display,
826 {
827 self.emit(Level::INFO, message);
828 }
829
830 pub fn emit<'a, L, F, M>(&self, level: L, message: F)
832 where
833 L: Into<LevelSpec<'a>>,
834 F: FnOnce() -> M,
835 M: Display,
836 {
837 let level_mask = self.level_or_default(level, levels::NONE);
838 if !self.should_log(level_mask) {
839 return;
840 }
841
842 if let Some(level) = Level::from_mask(level_mask) {
843 if self.preprocessors.is_empty() && self.postprocessors.is_empty() {
844 (self.sink)(level, message().to_string());
845 } else {
846 self.emit_prepared_args(level, vec![LogArg::text(message().to_string())]);
847 }
848 }
849 }
850
851 pub fn emit_args<'a, L, I>(&self, level: L, args: I)
853 where
854 L: Into<LevelSpec<'a>>,
855 I: IntoIterator<Item = LogArg>,
856 {
857 let level_mask = self.level_or_default(level, levels::NONE);
858 if !self.should_log(level_mask) {
859 return;
860 }
861
862 if let Some(level) = Level::from_mask(level_mask) {
863 self.emit_prepared_args(level, args.into_iter().collect());
864 }
865 }
866
867 fn emit_prepared_args(&self, level: Level, args: Vec<LogArg>) {
868 let mut processable_args = args;
869 for preprocessor in &self.preprocessors {
870 processable_args = preprocessor(PreprocessorOptions {
871 args: processable_args,
872 level,
873 });
874 }
875
876 let mut message = processable_args
877 .into_iter()
878 .map(LogArg::evaluate)
879 .collect::<Vec<_>>()
880 .join(" ");
881
882 for postprocessor in &self.postprocessors {
883 message = postprocessor(PostprocessorOptions { message, level });
884 }
885
886 (self.sink)(level, message);
887 }
888
889 pub fn fatal<F, M>(&self, message: F)
890 where
891 F: FnOnce() -> M,
892 M: Display,
893 {
894 self.emit(Level::FATAL, message);
895 }
896
897 pub fn error<F, M>(&self, message: F)
898 where
899 F: FnOnce() -> M,
900 M: Display,
901 {
902 self.emit(Level::ERROR, message);
903 }
904
905 pub fn warn<F, M>(&self, message: F)
906 where
907 F: FnOnce() -> M,
908 M: Display,
909 {
910 self.emit(Level::WARN, message);
911 }
912
913 pub fn info<F, M>(&self, message: F)
914 where
915 F: FnOnce() -> M,
916 M: Display,
917 {
918 self.emit(Level::INFO, message);
919 }
920
921 pub fn debug<F, M>(&self, message: F)
922 where
923 F: FnOnce() -> M,
924 M: Display,
925 {
926 self.emit(Level::DEBUG, message);
927 }
928
929 pub fn verbose<F, M>(&self, message: F)
930 where
931 F: FnOnce() -> M,
932 M: Display,
933 {
934 self.emit(Level::VERBOSE, message);
935 }
936
937 pub fn trace<F, M>(&self, message: F)
938 where
939 F: FnOnce() -> M,
940 M: Display,
941 {
942 self.emit(Level::TRACE, message);
943 }
944
945 pub fn silly<F, M>(&self, message: F)
946 where
947 F: FnOnce() -> M,
948 M: Display,
949 {
950 self.emit(Level::SILLY, message);
951 }
952}
953
954#[macro_export]
956macro_rules! log_lazy {
957 ($logger:expr, $level:expr, $($arg:tt)+) => {{
958 $logger.emit($level, || format!($($arg)+));
959 }};
960}
961
962#[macro_export]
964macro_rules! info_lazy {
965 ($logger:expr, $($arg:tt)+) => {{
966 $logger.info(|| format!($($arg)+));
967 }};
968}
969
970#[macro_export]
972macro_rules! debug_lazy {
973 ($logger:expr, $($arg:tt)+) => {{
974 $logger.debug(|| format!($($arg)+));
975 }};
976}
977
978#[macro_export]
980macro_rules! error_lazy {
981 ($logger:expr, $($arg:tt)+) => {{
982 $logger.error(|| format!($($arg)+));
983 }};
984}
985
986fn default_presets() -> BTreeMap<String, LevelMask> {
987 BTreeMap::from([
988 ("production".to_string(), levels::PRODUCTION),
989 ("development".to_string(), levels::DEVELOPMENT),
990 ])
991}
992
993fn level_from_owned_spec(
994 level: OwnedLevelSpec,
995 presets: &BTreeMap<String, LevelMask>,
996 default: LevelMask,
997) -> LevelMask {
998 match level {
999 OwnedLevelSpec::Mask(mask) => mask,
1000 OwnedLevelSpec::Name(name) => presets
1001 .get(name.as_str())
1002 .copied()
1003 .or_else(|| builtin_level_mask(name.as_str()))
1004 .or_else(|| name.parse::<LevelMask>().ok())
1005 .unwrap_or(default),
1006 }
1007}
1008
1009fn format_timestamp(format: postprocessors::TimestampFormat) -> String {
1010 match format {
1011 postprocessors::TimestampFormat::Iso => {
1012 Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true)
1013 }
1014 postprocessors::TimestampFormat::Locale => Local::now().format("%c").to_string(),
1015 postprocessors::TimestampFormat::Time => Local::now().format("%T").to_string(),
1016 postprocessors::TimestampFormat::Millis => Utc::now().timestamp_millis().to_string(),
1017 }
1018}
1019
1020fn builtin_level_mask(name: &str) -> Option<LevelMask> {
1021 match name {
1022 "none" => Some(levels::NONE),
1023 "fatal" => Some(levels::FATAL),
1024 "error" => Some(levels::ERROR),
1025 "warn" => Some(levels::WARN),
1026 "info" => Some(levels::INFO),
1027 "debug" => Some(levels::DEBUG),
1028 "verbose" => Some(levels::VERBOSE),
1029 "trace" => Some(levels::TRACE),
1030 "silly" => Some(levels::SILLY),
1031 "all" => Some(levels::ALL),
1032 "production" => Some(levels::PRODUCTION),
1033 "development" => Some(levels::DEVELOPMENT),
1034 _ => None,
1035 }
1036}
1037
1038fn default_sink(level: Level, message: String) {
1039 match level {
1040 Level::FATAL | Level::ERROR | Level::WARN => eprintln!("{message}"),
1041 _ => println!("{message}"),
1042 }
1043}