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 { }