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