logger_bro/
lib.rs

1use owo_colors::OwoColorize;
2use std::fmt::Arguments;
3use std::io::{self, Write};
4use std::sync::Mutex;
5use unicode_width::UnicodeWidthStr;
6
7#[derive(Clone, Copy, Debug)]
8pub enum Level { Info, Warn, Crit }
9
10impl Level {
11    fn as_str(self) -> &'static str {
12        match self { Level::Info => "INFO", Level::Warn => "WARN", Level::Crit => "CRIT" }
13    }
14}
15
16pub struct Logger {
17    obj_width: usize,
18    writer: Mutex<Box<dyn Write + Send>>,
19    gap_after_colon: usize,
20}
21
22impl Logger {
23    pub fn new(obj_width: usize) -> Self {
24        Self {
25            obj_width,
26            writer: Mutex::new(Box::new(io::stdout())),
27            gap_after_colon: 4,
28        }
29    }
30
31    pub fn log(&self, level: Level, obj: &str, args: Arguments) {
32        let level_tag = level.as_str();
33        let obj_padded = pad_obj(obj, self.obj_width);
34
35        let lvl_out = level_tag.red().to_string();
36        let obj_out = obj_padded.green().to_string();
37
38        let mut guard = self.writer.lock().unwrap();
39        let _ = write!(
40            &mut *guard,
41            "[{}] [{}]:{}{msg}\n",
42            lvl_out,
43            obj_out,
44            " ".repeat(self.gap_after_colon),
45            msg = format!("{}", args)
46        );
47        let _ = guard.flush();
48    }
49
50    pub fn info(&self, obj: &str, args: Arguments) { self.log(Level::Info, obj, args) }
51    pub fn warn(&self, obj: &str, args: Arguments) { self.log(Level::Warn, obj, args) }
52    pub fn crit(&self, obj: &str, args: Arguments) { self.log(Level::Crit, obj, args) }
53}
54
55fn pad_obj(obj: &str, width_cols: usize) -> String {
56    let mut s = obj.to_string();
57    while UnicodeWidthStr::width(s.as_str()) > width_cols {
58        s.pop();
59    }
60    let w = UnicodeWidthStr::width(s.as_str());
61    if w < width_cols {
62        s.push_str(&" ".repeat(width_cols - w));
63    }
64    s
65}
66
67#[macro_export] macro_rules! info  { ($lg:expr, $obj:expr, $($arg:tt)*) => { $lg.info($obj, format_args!($($arg)*)) } }
68#[macro_export] macro_rules! warn  { ($lg:expr, $obj:expr, $($arg:tt)*) => { $lg.warn($obj, format_args!($($arg)*)) } }
69#[macro_export] macro_rules! crit  { ($lg:expr, $obj:expr, $($arg:tt)*) => { $lg.crit($obj, format_args!($($arg)*)) } }