logger/
logger.rs

1use arcref::ArcRef;
2use std::sync::Arc;
3
4/// Logging levels
5#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
6pub enum Level {
7    INFO,
8    WARN,
9    ERROR,
10}
11
12/// Generic interface for logging
13pub trait Logger {
14    fn log(&self, level: Level, line: &str);
15}
16
17pub trait LoggerFactory {
18    fn new_logger(&self) -> ArcRef<dyn Logger>;
19}
20
21// Builtin loggers
22pub struct StdoutLogger;
23
24impl Logger for StdoutLogger {
25    fn log(&self, level: Level, line: &str) {
26        println!("{level:?}: {line}");
27    }
28}
29
30// Default console logger factory
31pub struct ConsoleFactory;
32
33impl LoggerFactory for ConsoleFactory {
34    fn new_logger(&self) -> ArcRef<dyn Logger> {
35        // StdoutLogger is a ZST, so we can create a &'static dyn Logger to it
36        ArcRef::new_ref(&StdoutLogger)
37    }
38}
39
40/// Only log at the configured level or higher
41pub struct FilteredLogger(Level, ArcRef<dyn Logger>);
42
43impl Logger for FilteredLogger {
44    fn log(&self, level: Level, line: &str) {
45        if level >= self.0 {
46            self.1.log(level, line);
47        }
48    }
49}
50
51pub struct FilteredLoggerFactory {
52    min_level: Level,
53    delegate: ArcRef<dyn Logger>,
54}
55
56impl LoggerFactory for FilteredLoggerFactory {
57    fn new_logger(&self) -> ArcRef<dyn Logger> {
58        ArcRef::new_arc(Arc::new(FilteredLogger(
59            self.min_level,
60            self.delegate.clone(),
61        )))
62    }
63}
64
65fn main() {
66    let console = ConsoleFactory.new_logger();
67    let filtered = FilteredLoggerFactory {
68        min_level: Level::WARN,
69        delegate: console,
70    };
71
72    let logger = filtered.new_logger();
73    logger.log(Level::INFO, "this will not print");
74    logger.log(Level::WARN, "but this will");
75    logger.log(Level::ERROR, "and so will this");
76}