rusty_logger/logger.rs
1use crate::modules::{self, Module};
2use crate::options::Options;
3use crate::timer::Timer;
4use crate::types::{LogType, TimeUnit};
5use std::{fmt::Display, io::stderr, time::Duration};
6
7/// A modular and powerful logger
8///
9/// # Example
10///
11/// ```
12/// use rusty_logger::Logger;
13/// use rusty_logger::types;
14///
15/// let mut logger = Logger::new("EXAMPLE", std::io::stdout());
16///
17/// logger.options.time_unit = types::TimeUnit::Nanoseconds;
18///
19/// logger.info("We will be timing a for loop");
20///
21/// logger.timer_start("for loop");
22///
23/// for i in 0..1000 {
24/// // Do something...
25/// }
26///
27/// logger.timer_log_and_stop("for loop");
28///
29/// logger.info("The for loop ended successfully");
30/// ```
31pub struct Logger<T: std::io::Write> {
32 pub options: Options,
33 timer: Timer,
34 modules: Vec<Box<dyn Module>>,
35 output: T,
36}
37
38pub struct LogMessage<'a> {
39 pub content: &'a str,
40 pub msg_type: LogType,
41 pub options: &'a Options,
42}
43
44impl<T: std::io::Write> Logger<T> {
45 /// Creates a new Logger with default values and the given name
46 ///
47 /// # Example
48 ///
49 /// ```
50 /// use rusty_logger::Logger;
51 ///
52 /// let mut logger = Logger::new("name", std::io::stdout());
53 ///
54 /// logger.info("This is a new logger named 'name' !");
55 /// ```
56 pub fn new(s: &str, output: T) -> Self {
57 let modules: Vec<Box<dyn Module>> = vec![
58 Box::new(modules::Name {}),
59 Box::new(modules::Time {}),
60 Box::new(modules::Type {}),
61 ];
62 Logger {
63 options: Options::new(s),
64 timer: Timer::new(),
65 modules,
66 output,
67 }
68 }
69
70 /// Creates a new Logger with custom options and modules
71 ///
72 /// # Example
73 ///
74 /// ```
75 /// use rusty_logger::{
76 /// Logger,
77 /// Module,
78 /// Options,
79 /// modules,
80 /// };
81 ///
82 /// let options = Options::new("homemade logger");
83 ///
84 /// let modules: Vec<Box<dyn Module>> = vec!(
85 /// Box::new(modules::Name{}),
86 /// Box::new(modules::Time{}),
87 /// Box::new(modules::Type{})
88 /// );
89 ///
90 /// let mut logger = Logger::homemade(std::io::stdout(), options, modules);
91 ///
92 /// logger.info("This is a new logger named 'name' which has 'options' as its options !");
93 /// ```
94 pub fn homemade(output: T, options: Options, modules: Vec<Box<dyn Module>>) -> Logger<T> {
95 Logger {
96 options,
97 timer: Timer::new(),
98 modules,
99 output,
100 }
101 }
102
103 /// Formats the message with the current logger options
104 /// and then prints it. It is a private function and is
105 /// only used by the other internal functions to print
106 /// the message.
107 ///
108 /// It goes through the options of the logger it is
109 /// called on and formats the message accordingly.
110 fn log(&mut self, msg: String, msg_type: LogType) {
111 let mut output = String::new();
112
113 let lm = LogMessage {
114 content: &msg[..],
115 msg_type,
116 options: &self.options,
117 };
118
119 self.modules.iter_mut().for_each(|module| {
120 output.push_str(&module.print(&lm));
121 });
122
123 match writeln!(self.output, "{}: {}", output, msg) {
124 std::result::Result::Err(err) => Logger::static_log(err, LogType::Error, stderr()),
125 std::result::Result::Ok(_) => {}
126 }
127 }
128
129 /// Static implementation for the log function
130 ///
131 /// Mainly used to print internal error messages
132 /// but can also be used by an end user
133 ///
134 /// # Example
135 ///
136 /// ```
137 /// use rusty_logger::{Logger, types::LogType};
138 ///
139 /// Logger::static_log("Printing on the fly", LogType::Info, std::io::stdout());
140 /// ```
141 pub fn static_log<D: Display>(msg: D, msg_type: LogType, output: T) {
142 let mut logger = Logger::new("STATIC", output);
143 logger.log(msg.to_string(), msg_type);
144 }
145
146 /// Logs the given message to the output
147 /// as an information
148 ///
149 /// # Example
150 ///
151 /// ```
152 /// use rusty_logger::Logger;
153 ///
154 /// let mut logger = Logger::new("name", std::io::stdout());
155 ///
156 /// logger.info("Here is some information I want to log");
157 /// ```
158 pub fn info<D: Display>(&mut self, msg: D) {
159 self.log(msg.to_string(), LogType::Info);
160 }
161
162 /// Logs the given message to the output
163 /// as a warning
164 ///
165 /// # Example
166 ///
167 /// ```
168 /// use rusty_logger::Logger;
169 ///
170 /// let mut logger = Logger::new("name", std::io::stdout());
171 ///
172 /// logger.warn("Here is a warning");
173 /// ```
174 pub fn warn<D: Display>(&mut self, msg: D) {
175 self.log(msg.to_string(), LogType::Warning);
176 }
177
178 /// Logs the given message to the output
179 /// as an error
180 ///
181 /// # Example
182 ///
183 /// ```
184 /// use rusty_logger::Logger;
185 ///
186 /// let mut logger = Logger::new("name", std::io::stdout());
187 ///
188 /// logger.info("Some error happened");
189 /// ```
190 pub fn error<D: Display>(&mut self, msg: D) {
191 self.log(msg.to_string(), LogType::Error);
192 }
193
194 /// Starts a new timer with the given name
195 /// and the actual time
196 pub fn timer_start(&mut self, msg: &str) {
197 self.timer.start(msg);
198 }
199
200 /// Gets the duration from when the timer
201 /// with the given name was started
202 pub fn timer_get(&self, msg: &str) -> Option<Duration> {
203 self.timer.get(msg)
204 }
205
206 /// Stops the timer with the given name
207 /// and returns it as a duration
208 pub fn timer_stop(&mut self, msg: &str) -> Option<Duration> {
209 self.timer.stop(msg)
210 }
211
212 /// Resets the timer with the given name
213 /// and returns the duration of the timer
214 /// before being reset as a duration
215 pub fn timer_reset(&mut self, msg: &str) -> Option<Duration> {
216 self.timer.reset(msg)
217 }
218
219 /// Pauses the timer with the given name
220 /// and returns the duration of the timer
221 /// before pausing it as a duration
222 pub fn timer_pause(&mut self, msg: &str) -> Option<Duration> {
223 self.timer.pause(msg)
224 }
225
226 /// Resumes the timer with the given name
227 pub fn timer_resume(&mut self, msg: &str) -> Option<Duration> {
228 self.timer.resume(msg)
229 }
230
231 /// Logs the time elapsed between the
232 /// start/reset of the timer and now
233 /// **without** reseting it
234 ///
235 /// # Example
236 ///
237 /// ```
238 /// use rusty_logger::Logger;
239 ///
240 /// let mut logger = Logger::new("name", std::io::stdout());
241 ///
242 /// logger.timer_start("new_timer");
243 ///
244 /// std::thread::sleep(std::time::Duration::from_millis(1));
245 ///
246 /// logger.timer_log("new_timer");
247 /// ```
248 pub fn timer_log(&mut self, msg: &str) -> Option<Duration> {
249 if let Some(time) = self.timer.get(msg) {
250 match self.options.time_unit {
251 TimeUnit::Nanoseconds => {
252 self.log(format!("{} - {}ns", msg, time.as_nanos()), LogType::Time);
253 }
254 TimeUnit::Microseconds => {
255 self.log(format!("{} - {}μs", msg, time.as_micros()), LogType::Time);
256 }
257 TimeUnit::Milliseconds => {
258 self.log(format!("{} - {}ms", msg, time.as_millis()), LogType::Time);
259 }
260 }
261 Some(time)
262 } else {
263 Logger::static_log(msg, LogType::Error, stderr());
264 None
265 }
266 }
267
268 /// Logs the time elapsed between the
269 /// start/reset of the timer and now
270 /// and then stops it
271 ///
272 /// # Example
273 ///
274 /// ```
275 /// use rusty_logger::Logger;
276 ///
277 /// let mut logger = Logger::new("name", std::io::stdout());
278 ///
279 /// logger.timer_start("new_timer");
280 ///
281 /// std::thread::sleep(std::time::Duration::from_millis(1));
282 ///
283 /// logger.timer_log_and_stop("new_timer");
284 /// ```
285 pub fn timer_log_and_stop(&mut self, msg: &str) -> Option<Duration> {
286 self.timer_log(msg);
287 self.timer_stop(msg)
288 }
289
290 /// Logs the time elapsed between the
291 /// start/reset of the timer and now
292 /// and then resets it
293 ///
294 /// # Example
295 ///
296 /// ```
297 /// use rusty_logger::Logger;
298 ///
299 /// let mut logger = Logger::new("name", std::io::stdout());
300 ///
301 /// logger.timer_start("new_timer");
302 ///
303 /// std::thread::sleep(std::time::Duration::from_millis(1));
304 ///
305 /// logger.timer_log_and_reset("new_timer");
306 ///
307 /// std::thread::sleep(std::time::Duration::from_millis(1));
308 ///
309 /// logger.timer_log_and_stop("new_timer");
310 /// ```
311 pub fn timer_log_and_reset(&mut self, msg: &str) -> Option<Duration> {
312 self.timer_log(msg);
313 self.timer_reset(msg)
314 }
315}