narlog/
logger.rs

1use std::error::Error;
2use std::fmt::{Display, Formatter};
3use chrono::Local;
4use owo_colors::OwoColorize;
5use crate::enums::{LogLevel, TimestampType};
6
7impl Display for LogLevel {
8    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
9        match *self {
10            LogLevel::Trace => write!(f, "{}", "Trace".bright_black().bold()),
11            LogLevel::Info => write!(f, "{}", "Info".bright_cyan().bold()),
12            LogLevel::Debug => write!(f, "{}", "Debug".bright_yellow().bold()),
13            LogLevel::Warn => write!(f, "{}", "Warn".bright_yellow().bold()),
14            LogLevel::Error => write!(f, "{}", "Error".bright_red().bold()),
15            LogLevel::Fatal => write!(f, "{}", "Fatal".red().bold())
16        }
17    }
18}
19
20impl Display for TimestampType {
21    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22        match *self {
23            TimestampType::Time => write!(f, "{}", Local::now().format("%H:%M:%S")),
24            TimestampType::DateTime => write!(f, "{}", Local::now().format("%Y-%m-%d %H:%M:%S")),
25            TimestampType::VeryDetailed => write!(f, "{}", Local::now())
26        }
27    }
28}
29
30pub struct Logger {
31    prefix: Option<String>,
32    timestamp_type: Option<TimestampType>
33}
34
35impl Logger {
36    /// Creates **a logger instance**.
37    /// ```
38    /// use narlog::prelude::*;
39    /// let logger = Logger::new();
40    /// ```
41    pub fn new() -> Self {
42        Self {
43            prefix: None,
44            timestamp_type: None
45        }
46    }
47    
48    /// Sets **a specified prefix**.
49    /// ```
50    /// use narlog::prelude::*;
51    /// let logger = Logger::new().with_prefix("👍");
52    /// ```
53    pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
54        self.prefix = Some(prefix.into());
55        self
56    }
57
58    /// Sets **a timestamp**.
59    /// ```
60    /// use narlog::prelude::*;
61    /// let logger = Logger::new().with_timestamp(TimestampType::Time);
62    /// ```
63    pub fn with_timestamp(mut self, timestamp_type: TimestampType) -> Self {
64        self.timestamp_type = Some(timestamp_type);
65        self
66    }
67    
68    fn build_and_output(&self, msg: impl Into<String>, level: LogLevel) {
69        let msg = msg.into();
70        let mut buffer: Vec<String> = Vec::new();
71        
72        self.prefix.as_ref().map(|p| buffer.push(p.to_string()));
73        buffer.push(level.to_string());
74        self.timestamp_type.as_ref().map(|p| buffer.push(p.bright_black().to_string()));
75        buffer.push(msg);
76
77        println!("{}", buffer.join(" "));
78    }
79
80    /// Logs **a message** at the specified level.
81    /// ```
82    /// use narlog::prelude::*;
83    ///
84    /// let logger = Logger::new();
85    /// 
86    /// logger.log(LogLevel::Info, "Information");
87    /// logger.log(LogLevel::Warn, "Warning");
88    /// ```
89    pub fn log(&self, level: LogLevel, msg: impl Into<String>) {
90        self.build_and_output(msg, level);
91    }
92
93    /// Logs **a message** at the specified level with an optional error.
94    /// ```
95    /// use narlog::prelude::*;
96    /// use std::io::{self, ErrorKind};
97    ///
98    /// let logger = Logger::new();
99    /// let err = io::Error::new(ErrorKind::Other, "extra details");
100    ///
101    /// logger.log_with_error(LogLevel::Error, "Something went wrong", Some(&err));
102    /// logger.log_with_error(LogLevel::Fatal, "Catastrophic failure", None);
103    /// ```
104    pub fn log_with_error(&self, level: LogLevel, msg: impl Into<String>, err: Option<&dyn Error>) {
105        self.build_and_output(msg, level);
106        if let Some(err) = err {
107            match level {
108                LogLevel::Error => eprintln!("    {} {}", "Caused by:".bright_red(), err),
109                LogLevel::Fatal => eprintln!("    {} {}", "Caused by:".red(), err),
110                _ => eprintln!("    {} {}", "Caused by:".bright_red(), err),
111            }
112        }
113    }
114
115
116    // -------------------------//
117    //       Easy Methods       //
118    // -------------------------//
119
120    /// Logs **a message** at the trace level.
121    /// ```
122    /// use narlog::prelude::*;
123    /// let logger = Logger::new();
124    /// logger.trace("Lorem ipsum dolor sit amet");
125    /// ```
126    pub fn trace(&self, msg: impl Into<String>) {
127        self.log(LogLevel::Trace, msg);
128    }
129
130    /// Logs **a message** at the info level.
131    /// ```
132    /// use narlog::prelude::*;
133    /// let logger = Logger::new();
134    /// logger.info("consectetur adipiscing elit");
135    /// ```
136    pub fn info(&self, msg: impl Into<String>) {
137        self.log(LogLevel::Info, msg);
138    }
139
140    /// Logs **a message** at the debug level.
141    /// ```
142    /// use narlog::prelude::*;
143    /// let logger = Logger::new();
144    /// logger.debug("sed do eiusmod tempor incididunt ut labore");
145    /// ```
146    pub fn debug(&self, msg: impl Into<String>) {
147        self.log(LogLevel::Debug, msg);
148    }
149
150
151    /// Logs **a message** at the warn level.
152    /// ```
153    /// use narlog::prelude::*;
154    /// let logger = Logger::new();
155    /// logger.warn("Ut enim ad minim veniam");
156    /// ```
157    pub fn warn(&self, msg: impl Into<String>) {
158        self.log(LogLevel::Warn, msg);
159    }
160
161    /// Logs **a message** at the error level, with optional error details.
162    /// ```
163    /// use narlog::prelude::*;
164    /// use std::io::{self, ErrorKind};
165    ///
166    /// let logger = Logger::new();
167    /// let error = io::Error::new(ErrorKind::Other, "extra details");
168    /// logger.error("Something went wrong", Some(&error));
169    /// logger.error("Another error without details", None);
170    /// ```
171    pub fn error(&self, msg: impl Into<String>, err: Option<&dyn Error>) {
172        self.log_with_error(LogLevel::Error, msg, err);
173    }
174
175    /// Logs **a message** at the fatal level, with optional error details.
176    /// ```
177    /// use narlog::prelude::*;
178    /// use std::io::{self, ErrorKind};
179    ///
180    /// let logger = Logger::new();
181    /// let error = io::Error::new(ErrorKind::Other, "catastrophic failure");
182    /// logger.fatal("System crashed", Some(&error));
183    /// logger.fatal("Fatal error without details", None);
184    /// ```
185    pub fn fatal(&self, msg: impl Into<String>, err: Option<&dyn Error>) {
186        self.log_with_error(LogLevel::Fatal, msg, err);
187    }
188}