1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright (C) 2023 Fred Clausen

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

extern crate chrono;
extern crate env_logger;
extern crate log;

use chrono::Local;
use env_logger::fmt::Color;
use env_logger::Builder;
use log::LevelFilter;
use std::io::Write;

/// Trait to setup logging
/// To initialize logging, call `enable_logging` on a u8
pub trait SetupLogging {
    fn set_logging_level(self) -> LevelFilter;
    fn enable_logging(&self);
}

/// Setup logging. 0 = Info, 1 = Debug, 2 = Trace

impl SetupLogging for u8 {
    /// Set logging level. 0 = Info, 1 = Debug, 2 = Trace
    /// to set the logging level, call `set_logging_level` on a u8
    fn set_logging_level(self) -> LevelFilter {
        match self {
            0 => LevelFilter::Info,
            1 => LevelFilter::Debug,
            2..=u8::MAX => LevelFilter::Trace,
        }
    }

    /// Enable logging<br><br>
    /// The output is colored and looks like this:<br>
    /// \[INFO \]\[2021-08-22T15:49:01\]This is an info message<br>
    /// \[DEBUG\]\[2021-08-22T15:49:01\]This is a debug message<br>
    /// \[TRACE\]\[2021-08-22T15:49:01\]This is a trace message<br>
    /// \[ERROR\]\[2021-08-22T15:49:01\]This is an error message<br>
    /// \[WARN \]\[2021-08-22T15:49:01\]This is a warning message<br>
    /// \[OTHER\]\[2021-08-22T15:49:01\]This is a message with a different log level<br><br>
    /// The level field is colored and bold if the terminal supports it.<br>

    fn enable_logging(&self) {
        Builder::new()
            .format(|buf, record| {
                let mut level_style = buf.style();

                if record.level() == log::Level::Info {
                    level_style.set_color(Color::Green).set_bold(true);
                } else if record.level() == log::Level::Debug {
                    level_style.set_color(Color::Cyan).set_bold(true);
                } else if record.level() == log::Level::Trace {
                    level_style.set_color(Color::Magenta).set_bold(true);
                } else if record.level() == log::Level::Error {
                    level_style.set_color(Color::Red).set_bold(true);
                } else if record.level() == log::Level::Warn {
                    level_style.set_color(Color::Yellow).set_bold(true);
                } else {
                    level_style.set_color(Color::White).set_bold(true);
                }

                writeln!(
                    buf,
                    "[{}][{}]{}",
                    level_style.value(format!("{: <5}", record.level())),
                    Local::now().format("%Y-%m-%dT%H:%M:%S"),
                    record.args()
                )
            })
            .filter(None, self.set_logging_level())
            .init();
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_set_logging_level() {
        let info_level: u8 = 0;
        let debug_level: u8 = 1;
        let trace_level: u8 = 2;
        let stupid_levels: u8 = 255;
        let info_level_logging: LevelFilter = info_level.set_logging_level();
        let debug_level_logging: LevelFilter = debug_level.set_logging_level();
        let trace_level_logging: LevelFilter = trace_level.set_logging_level();
        let stupid_levels_logging: LevelFilter = stupid_levels.set_logging_level();
        assert_eq!(info_level_logging, LevelFilter::Info);
        assert_eq!(debug_level_logging, LevelFilter::Debug);
        assert_eq!(trace_level_logging, LevelFilter::Trace);
        assert_eq!(stupid_levels_logging, LevelFilter::Trace);
    }
}