1use anyhow::{Context, Result};
2use chrono::Local;
3use colored::*;
4use env_logger::{Builder, WriteStyle};
5use log::LevelFilter;
6use std::io::Write;
7
8pub struct ThinLogger {
9 app_level_logs: LevelFilter,
10 external_level_logs: LevelFilter,
11}
12
13impl ThinLogger {
14 pub fn new(app_level_logs: LevelFilter) -> Self {
15 ThinLogger {
16 app_level_logs,
17 external_level_logs: LevelFilter::Off,
18 }
19 }
20
21 pub fn external_logs(mut self, level: LevelFilter) -> Self {
22 self.external_level_logs = level;
23 self
24 }
25
26 pub fn init(self) -> Result<()> {
27 let mut builder = Builder::new();
28
29 builder
30 .format(|buf, record| {
31 let timestamp = Local::now()
32 .format("%H:%M:%S%p")
33 .to_string()
34 .yellow()
35 .dimmed();
36 let style = buf.default_level_style(record.level());
37 let level_style = format!("{style}{}{style:#}", record.level());
38
39 let target_pretty = record.target().split("::").next().unwrap();
40
41 writeln!(
42 buf,
43 "[{}] [{}] [{}]: {}",
44 timestamp,
45 level_style,
46 target_pretty,
47 record.args()
48 )
49 })
50 .format_level(true)
51 .write_style(WriteStyle::Always);
52
53 if self.external_level_logs != LevelFilter::Off {
54 builder.filter(None, self.external_level_logs);
55 } else {
56 let crate_mod = env!("CARGO_PKG_NAME").replace('-', "_");
57 builder
58 .filter(None, LevelFilter::Off)
59 .filter_module(&crate_mod, self.app_level_logs);
60 }
61
62 builder.try_init().context("Failed to initialize logger")
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_logger_logs() -> Result<()> {
72 ThinLogger::new(LevelFilter::Trace).init()?;
73 log::trace!("This is a test log");
74 log::debug!("This is a test log");
75 log::info!("This is a test log");
76 log::warn!("This is a test log");
77 log::error!("This is a test log");
78 Ok(())
79 }
80}