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}