prettylogger/
lib.rs

1//! Fancy logger library.
2
3/// Fancy logger library.
4#[cfg(test)]
5mod tests;
6
7#[doc = include_str!("../README.md")]
8mod fileio;
9mod json;
10
11pub mod colors;
12pub mod config;
13pub mod format;
14pub mod output;
15
16use std::sync::Mutex;
17
18use format::LogFormatter;
19use serde::{Serialize, Deserialize};
20use config::{Verbosity, LogStruct, LogType};
21use output::LogOutput;
22
23/// `Logger` capable of filtering logs, formatting them and distributing them
24/// to various streams.
25///
26/// The `Logger` struct is modular and itself only filters the logs, relying
27/// on `LogFormatter` and `LogOutput` for log formatting and outputting.
28///
29/// Additionally, `Logger` includes a template system with built-in methods and
30/// constructors for easy JSON serialization and deserialization.
31///
32/// # Examples
33///
34/// Creating a `Logger` struct and printing out some logs:
35/// ```
36/// # use prettylogger::Logger;
37/// // Create a `Logger` instance with default configuration
38/// let mut logger = Logger::default();
39///
40/// // Print log messages
41/// logger.debug("debug message");
42/// logger.info("info message");
43/// logger.warning("warning message");
44/// logger.error("error message");
45/// logger.fatal("fatal error message");
46/// ```
47///
48/// Configuring the formatter of a `Logger`:
49/// ```
50/// # use prettylogger::{
51/// #     Logger,
52/// #     colors::Color,
53/// # };
54/// // Create a `Logger` instance with default configuration
55/// let mut logger = Logger::default();
56///
57/// // Set a simple log format
58/// logger.formatter.lock().unwrap().set_log_format("[ %d ] %m");
59///
60/// // Change debug log header color
61/// logger.formatter.lock().unwrap().set_debug_color(Color::Red);
62///
63/// // Set a fatal log header
64/// logger.formatter.lock().unwrap().set_fatal_header("--FATAL--");
65///
66/// // Configure datetime format
67/// logger.formatter.lock().unwrap().set_datetime_format("%H:%M");
68/// ```
69///
70/// Enabling log buffering:
71/// ```
72/// # use prettylogger::{
73/// #     Logger,
74/// #     output::Toggleable,
75/// # };
76/// // Create a `Logger` instance with default configuration
77/// let mut logger = Logger::default();
78///
79/// // Enable log buffering
80/// logger.output.buffer_output.lock().unwrap().enable();
81///
82/// // Write to the log buffer 128 times
83/// for i in 0..128 {
84///     logger.error(&format!("Error number {}", i));
85/// }
86///
87/// // Get a reference to the log buffer
88/// let buffer = logger.output.buffer_output.lock().unwrap().get_log_buffer();
89/// ```
90///
91/// Enabling file logging:
92/// ```
93/// # use prettylogger::{
94/// #     Logger,
95/// #     output::Toggleable,
96/// #     format::LogFormatter,
97/// #     config::LogStruct,
98/// # };
99/// # let mut path = std::env::temp_dir();
100/// # path.push("libprettylogger-tests/readme-logger-saving.json");
101/// # let path = &path.to_str().unwrap().to_string();
102/// // Create a `Logger` instance with default configuration
103/// let mut logger = Logger::default();
104///
105/// // Lock the file output and obtain a reference to it
106/// let mut file_output = logger.output.file_output.lock().unwrap();
107///
108/// // Required by `FileStream` for parsing logs
109/// let mut formatter = LogFormatter::default();
110///
111/// // Set the log file path **first**
112/// file_output.set_log_file_path(&path)
113///     .expect("Failed to set the log file path!");
114///
115/// // Enable the output
116/// file_output.enable().
117///     expect("Failed to enable the output!");
118///
119/// // Write to the log file buffer
120/// file_output.out(&LogStruct::debug("Hello from file!"),
121///     &mut formatter).expect("Failed to write to the buffer!");
122///
123/// // Flush the logs from the buffer to the log file
124/// file_output.flush();
125/// ```
126#[derive(Debug, Serialize, Deserialize)]
127pub struct Logger {
128    pub formatter: Mutex<LogFormatter>,
129    pub output: LogOutput,
130
131    pub(crate) verbosity: Verbosity,
132    pub(crate) filtering_enabled: bool,
133}
134
135impl Logger {
136    /// Returns true if log should be filtered and false otherwise.
137    pub(crate) fn filter_log(&self, log_type: LogType) -> bool {
138        if self.filtering_enabled {
139            return (log_type as i32) < self.verbosity as i32;
140        }
141        return false;
142    }
143
144    /// Prints a **debug message**.
145    pub fn debug(&self, message: &str) {
146        if self.filter_log(LogType::Debug) {
147            return;
148        }
149        let log = LogStruct::debug(message);
150        self.output.out(&log, &mut self.formatter.lock().unwrap());
151    }
152
153    /// Prints an **informational message**.
154    pub fn info(&self, message: &str) {
155        if self.filter_log(LogType::Info) {
156            return;
157        }
158        let log = LogStruct::info(message);
159        self.output.out(&log, &mut self.formatter.lock().unwrap());
160    }
161
162    /// Prints a **warning**.
163    pub fn warning(&self, message: &str) {
164        if self.filter_log(LogType::Warning) {
165            return;
166        }
167        let log = LogStruct::warning(message);
168        self.output.out(&log, &mut self.formatter.lock().unwrap());
169    }
170
171    /// Prints an **error**.
172    pub fn error(&self, message: &str) {
173        let log = LogStruct::error(message);
174        self.output.out(&log, &mut self.formatter.lock().unwrap());
175    }
176
177    /// Prints a **fatal error**.
178    pub fn fatal(&self, message: &str) {
179        let log = LogStruct::fatal_error(message);
180        self.output.out(&log, &mut self.formatter.lock().unwrap());
181    }
182
183    /// Sets `Logger` verbosity.
184    ///
185    /// # Examples
186    ///
187    /// Setting `Logger` verbosity:
188    /// ```
189    /// # use prettylogger::{Logger, config::Verbosity};
190    /// # let mut logger = Logger::default();
191    /// logger.set_verbosity(Verbosity::Quiet);
192    /// ```
193    pub fn set_verbosity<I: Into<Verbosity>>(&mut self, verbosity: I) {
194        self.verbosity = verbosity.into();
195    }
196
197    /// Enables log filtering.
198    pub fn enable_log_filtering(&mut self) {
199        self.filtering_enabled = true;
200    }
201
202    /// Disables log filtering.
203    pub fn disable_log_filtering(&mut self) {
204        self.filtering_enabled = false;
205    }
206}
207
208impl Default for Logger {
209    fn default() -> Self {
210        Logger {
211            output: LogOutput::default(),
212
213            verbosity: Verbosity::default(),
214            filtering_enabled: true,
215
216            formatter: LogFormatter::default().into(),
217        }
218    }
219}
220
221impl Drop for Logger {
222    fn drop(&mut self) {
223        self.output.file_output.lock().unwrap().drop_flush();
224    }
225}
226
227impl PartialEq for Logger {
228    fn eq(&self, other: &Self) -> bool {
229        return self.output == other.output &&
230            self.verbosity == other.verbosity &&
231            self.filtering_enabled == other.filtering_enabled;
232    }
233}
234
235/// Represents errors thrown by the `prettylogger` crate.
236#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
237pub struct Error {
238    pub message: String,
239}
240
241impl Error {
242    pub fn new(msg: &str) -> Self {
243        Error {
244            message: msg.to_string(),
245        }
246    }
247}
248
249impl std::fmt::Display for Error {
250    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
251        return write!(f, "{}", self.message)
252    }
253}
254
255impl std::error::Error for Error { }