src/handlers/console_handler.rs

Lines

100.00 %

Functions

100.00 %

Regions

99.43 %

LineCountSource (jump to first uncovered line)
1
//
2
// File Name:    console_handler.rs
3
// Directory:    src/handlers
4
// Project Name: flogging
5
//
6
// Copyright (C) 2025 Bradley Willcott
7
//
8
// SPDX-License-Identifier: GPL-3.0-or-later
9
//
10
// This library (crate) is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
14
//
15
// This library (crate) is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
// GNU General Public License for more details.
19
//
20
// You should have received a copy of the GNU General Public License
21
// along with this library (crate).  If not, see <https://www.gnu.org/licenses/>.
22
//
23
24
//!
25
//! # ConsoleHandler
26
//!
27
//! Publishes log entries to the console: `[std::io::stderr]`.
28
//!
29
30
pub mod console_type;
31
32
use crate::*;
33
use console_type::ConsoleType;
34
use std::{
35
    fmt,
36
    io::{self, Error, Write},
37
};
38
39
///
40
/// Publishes log entries to the console.
41
///
42
/// If `console_type` is:
43
///
44
/// - `ConsoleType::StdOut` - print to `stdout`,
45
/// - `ConsoleType::StdErr` - print to `stderr`,
46
/// - `ConsoleType::Production`:\
47
///   If `log_entry.level` is `LeveL::INFO`, then\
48
///   prints unformatted `log_entry.msg` to `stdout`, else\
49
///   prints formatted `log_entry.msg` to `stderr`.
50
///
51
#[derive(Debug, Default)]
52
pub struct ConsoleHandler {
53
    console_type: ConsoleType,
54
    formatter: Formatter,
55
    writer: Option<Vec<u8>>,
56
}
57
58
impl ConsoleHandler {
5931
    fn _create(console_type: ConsoleType) -> Self {
6031
        ConsoleHandler {
6131
            console_type,
6231
            formatter: FormatType::Simple.create(None),
6331
            writer: None,
6431
        }
6531
    }
66
678
    fn log(&self) -> String {
688
        if let Some(w) = self.writer.to_owned() {
695
            String::from_utf8(w).unwrap()
70
        } else {
713
            String::new()
72
        }
738
    }
74
}
75
76
impl fmt::Display for ConsoleHandler {
771
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
781
        self.formatter.fmt(f)
791
    }
80
}
81
82
impl HandlerTrait for ConsoleHandler {
8331
    fn create(console_type: &str) -> Result<Self, Error>
8431
    where
8531
        Self: Sized,
86
    {
8731
        Ok(ConsoleHandler::_create(console_type.parse().unwrap()))
8831
    }
89
90
    ///
91
    /// Removes the internal buffer, if in `test_mode`.\
92
    /// Will therefore, no longer be *in* `test_mode`.
93
    ///
946
    fn close(&mut self) {
953
        if self.writer.is_some() {
963
            self.writer = None;
973
        }
986
    }
99
100
    ///
101
    /// Clears the internal buffer, if in `test_mode`.
102
    ///
1036
    fn flush(&mut self) {
1046
        if let Some(w) = self.writer.as_mut() {
1053
            w.clear()
1063
        };
1076
    }
108
1096
    fn get_formatter(&self) -> Formatter {
1106
        self.formatter.clone()
1116
    }
112
1138
    fn get_log(&self) -> String {
1148
        self.log()
1158
    }
116
117
    ///
118
    /// `ConsoleHandler` is *always* open.
119
    ///
1206
    fn is_open(&self) -> bool {
1216
        true
1226
    }
123
12475
    fn publish(&mut self, log_entry: &LogEntry) {
12575
        match self.writer.as_mut() {
12610
            Some(w) => {
12710
                let _ = match self.console_type {
1286
                    ConsoleType::StdOut => writeln!(w, "{}", self.formatter.format(log_entry)),
1292
                    ConsoleType::StdErr => writeln!(w, "{}", self.formatter.format(log_entry)),
1302
                    ConsoleType::Production => production_test(w, &self.formatter, log_entry),
131
                };
132
            }
13365
            None => match self.console_type {
13450
                ConsoleType::StdOut => println!("{}", self.formatter.format(log_entry)),
1359
                ConsoleType::StdErr => eprintln!("{}", self.formatter.format(log_entry)),
1366
                ConsoleType::Production => production(&self.formatter, log_entry),
137
            },
138
        }
13975
    }
140
1417
    fn set_formatter(&mut self, formatter: Formatter) {
1427
        self.formatter = formatter;
1437
    }
144
145
    ///
146
    /// Sets the test mode to `state`.
147
    ///
148
    /// If set to `true`, use `get_log()` to obtain the
149
    /// log.
150
    ///
1518
    fn set_test_mode(&mut self, state: bool) {
1525
        if state {
1535
            // true
1545
            self.writer = Some(Vec::new());
1553
        } else {
1563
            self.writer = None;
1573
        }
1588
    }
159
}
160
1616
fn production(formatter: &Formatter, log_entry: &LogEntry) {
1623
    if log_entry.level() == Level::INFO {
1633
        println!("{}", log_entry.message());
1643
    } else {
1653
        eprintln!("{}", formatter.format(log_entry));
1663
    }
1676
}
168
1692
fn production_test(
1702
    writer: &mut Vec<u8>,
1712
    formatter: &Formatter,
1722
    log_entry: &LogEntry,
1732
) -> io::Result<()> {
1742
    if log_entry.level() == Level::INFO {
1751
        writeln!(writer, "{}", log_entry.message())?;
176
    } else {
1771
        writeln!(writer, "{}", formatter.format(log_entry))?;
178
    }
179
1802
    Ok(())
1812
}
182
183
#[cfg(test)]
184
mod tests {
185
    use crate::*;
186
187
    #[test]
1881
    fn stdout_handler() {
1891
        let mut log = Logger::console_logger(module_path!());
190
1911
        log.info("trait methods");
1921
        log.warning("The sky is falling!");
193
1941
        let handler = log.get_handler(crate::Handler::Console).unwrap();
1951
        handler.set_test_mode(false);
196
1971
        assert!(handler.is_open());
1981
        assert_eq!(
1991
            handler.get_formatter().to_string(),
2001
            "dt_fmt: \"\" - fmt_string: \"{mod_path}->{fn_name} [{level:7}] {message}\""
2011
                .to_string()
202
        );
203
2041
        assert_eq!(handler.get_log(), "".to_string());
205
2061
        handler.flush();
2071
        handler.close();
2081
    }
209
210
    #[test]
2111
    fn stdout_handler_test_mode() {
2121
        let expected = "flogging::handlers::console_handler::tests-> [INFO   ] trait methods
2131
flogging::handlers::console_handler::tests-> [WARNING] The sky is falling!
2141
"
2151
            .to_string();
216
2171
        let mut log = Logger::console_logger(module_path!());
218
2191
        let h = log.get_handler(crate::Handler::Console).unwrap();
2201
        h.set_test_mode(true);
221
2221
        assert!(h.is_open());
2231
        assert_eq!(
2241
            h.get_formatter().to_string(),
2251
            "dt_fmt: \"\" - fmt_string: \"{mod_path}->{fn_name} [{level:7}] {message}\""
2261
                .to_string()
227
        );
228
2291
        log.info("trait methods");
2301
        log.warning("The sky is falling!");
231
2321
        let h = log.get_handler(crate::Handler::Console).unwrap();
2331
        let buf = h.get_log();
234
2351
        assert_eq!(expected, buf);
236
2371
        h.flush();
2381
        h.close();
2391
    }
240
241
    #[test]
2421
    fn stderr_handler() {
2431
        let mut log = Logger::econsole_logger(module_path!());
244
2451
        log.info("trait methods");
2461
        log.warning("The sky is falling!");
247
2481
        let handler = log.get_handler(crate::Handler::EConsole).unwrap();
2491
        handler.set_test_mode(false);
250
2511
        assert!(handler.is_open());
2521
        assert_eq!(
2531
            handler.get_formatter().to_string(),
2541
            "dt_fmt: \"\" - fmt_string: \"{mod_path}->{fn_name} [{level:7}] {message}\""
2551
                .to_string()
256
        );
257
2581
        assert_eq!(handler.get_log(), "".to_string());
259
2601
        handler.flush();
2611
        handler.close();
2621
    }
263
264
    #[test]
2651
    fn stderr_handler_test_mode() {
2661
        let expected = "flogging::handlers::console_handler::tests-> [INFO   ] trait methods
2671
flogging::handlers::console_handler::tests-> [WARNING] The sky is falling!\n"
2681
            .to_string();
269
2701
        let mut log = Logger::econsole_logger(module_path!());
271
2721
        let h = log.get_handler(crate::Handler::EConsole).unwrap();
2731
        h.set_test_mode(true);
274
2751
        assert!(h.is_open());
2761
        assert_eq!(
2771
            h.get_formatter().to_string(),
2781
            "dt_fmt: \"\" - fmt_string: \"{mod_path}->{fn_name} [{level:7}] {message}\""
2791
                .to_string()
280
        );
281
2821
        log.info("trait methods");
2831
        log.warning("The sky is falling!");
284
2851
        let h = log.get_handler(crate::Handler::EConsole).unwrap();
2861
        let buf = h.get_log();
287
2881
        assert_eq!(expected, buf);
289
2901
        h.flush();
2911
        h.close();
2921
    }
293
294
    #[test]
2951
    fn production_handler() {
2961
        let mut log = Logger::pconsole_logger(module_path!());
297
2981
        log.info("trait methods");
2991
        log.warning("The sky is falling!");
300
3011
        let handler = log.get_handler(crate::Handler::PConsole).unwrap();
3021
        handler.set_test_mode(false);
303
3041
        assert!(handler.is_open());
3051
        assert_eq!(
3061
            handler.get_formatter().to_string(),
3071
            "dt_fmt: \"\" - fmt_string: \"{mod_path}->{fn_name} [{level:7}] {message}\""
3081
                .to_string()
309
        );
310
3111
        assert_eq!(handler.get_log(), "".to_string());
312
3131
        handler.flush();
3141
        handler.close();
3151
    }
316
317
    #[test]
3181
    fn production_handler_test_mode() {
3191
        let expected = "trait methods
3201
flogging::handlers::console_handler::tests-> [WARNING] The sky is falling!\n"
3211
            .to_string();
322
3231
        let mut log = Logger::pconsole_logger(module_path!());
324
3251
        let h = log.get_handler(crate::Handler::PConsole).unwrap();
3261
        h.set_test_mode(true);
327
3281
        assert!(h.is_open());
3291
        assert_eq!(
3301
            h.get_formatter().to_string(),
3311
            "dt_fmt: \"\" - fmt_string: \"{mod_path}->{fn_name} [{level:7}] {message}\""
3321
                .to_string()
333
        );
334
3351
        log.info("trait methods");
3361
        log.warning("The sky is falling!");
337
3381
        let h = log.get_handler(crate::Handler::PConsole).unwrap();
3391
        let buf = h.get_log();
340
3411
        assert_eq!(expected, buf);
342
3431
        h.flush();
3441
        h.close();
3451
    }
346
}