Skip to main content

simplelog/
config.rs

1#[cfg(feature = "termcolor")]
2use log::Level;
3use log::LevelFilter;
4
5use std::borrow::Cow;
6#[cfg(feature = "termcolor")]
7use termcolor::Color;
8pub use time::{format_description::FormatItem, macros::format_description, UtcOffset};
9
10#[derive(Debug, Clone, Copy)]
11/// Padding to be used for logging the level
12pub enum LevelPadding {
13    /// Add spaces on the left side
14    Left,
15    /// Add spaces on the right side
16    Right,
17    /// Do not pad the level
18    Off,
19}
20
21#[derive(Debug, Clone, Copy)]
22/// Padding to be used for logging the thread id/name
23pub enum ThreadPadding {
24    /// Add spaces on the left side, up to usize many
25    Left(usize),
26    /// Add spaces on the right side, up to usize many
27    Right(usize),
28    /// Do not pad the thread id/name
29    Off,
30}
31
32#[derive(Debug, Clone, Copy)]
33/// Padding to be used for logging the thread id/name
34pub enum TargetPadding {
35    /// Add spaces on the left side, up to usize many
36    Left(usize),
37    /// Add spaces on the right side, up to usize many
38    Right(usize),
39    /// Do not pad the thread id/name
40    Off,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq)]
44/// Mode for logging the thread name or id or both.
45pub enum ThreadLogMode {
46    /// Log thread ids only
47    IDs,
48    /// Log the thread names only
49    Names,
50    /// If this thread is named, log the name. Otherwise, log the thread id.
51    Both,
52}
53
54#[derive(Debug, Clone)]
55pub(crate) enum TimeFormat {
56    Rfc2822,
57    Rfc3339,
58    Custom(&'static [time::format_description::FormatItem<'static>]),
59}
60
61/// Configuration for the Loggers
62///
63/// All loggers print the message in the following form:
64/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
65/// Every space delimited part except the actual message is optional.
66///
67/// Pass this struct to your logger to change when these information shall
68/// be logged.
69///
70/// Construct using [`Default`](Config::default) or using [`ConfigBuilder`]
71#[derive(Debug, Clone)]
72pub struct Config {
73    pub(crate) time: LevelFilter,
74    pub(crate) level: LevelFilter,
75    pub(crate) level_padding: LevelPadding,
76    pub(crate) thread: LevelFilter,
77    pub(crate) thread_log_mode: ThreadLogMode,
78    pub(crate) thread_padding: ThreadPadding,
79    pub(crate) target: LevelFilter,
80    pub(crate) target_padding: TargetPadding,
81    pub(crate) location: LevelFilter,
82    pub(crate) time_format: TimeFormat,
83    pub(crate) time_offset: UtcOffset,
84    pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>,
85    pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>,
86    #[cfg(feature = "termcolor")]
87    pub(crate) level_color: [Option<Color>; 6],
88    pub(crate) write_log_enable_colors: bool,
89}
90
91/// Builder for the Logger Configurations (`Config`)
92///
93/// All loggers print the message in the following form:
94/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
95/// Every space delimited part except the actual message is optional.
96///
97/// Use this struct to create a custom `Config` changing when these information shall
98/// be logged. Every part can be enabled for a specific Level and is then
99/// automatically enable for all lower levels as well.
100///
101/// The Result is that the logging gets more detailed the more verbose it gets.
102/// E.g. to have one part shown always use `Level::Error`. But if you
103/// want to show the source line only on `Trace` use that.
104#[derive(Debug, Clone)]
105#[non_exhaustive]
106pub struct ConfigBuilder(Config);
107
108impl ConfigBuilder {
109    /// Create a new default ConfigBuilder
110    pub fn new() -> ConfigBuilder {
111        ConfigBuilder(Config::default())
112    }
113
114    /// Set at which level and above (more verbose) the level itself shall be logged (default is Error)
115    pub fn set_max_level(&mut self, level: LevelFilter) -> &mut ConfigBuilder {
116        self.0.level = level;
117        self
118    }
119
120    /// Set at which level and  above (more verbose) the current time shall be logged (default is Error)
121    pub fn set_time_level(&mut self, time: LevelFilter) -> &mut ConfigBuilder {
122        self.0.time = time;
123        self
124    }
125
126    /// Set at which level and above (more verbose) the thread id shall be logged. (default is Debug)
127    pub fn set_thread_level(&mut self, thread: LevelFilter) -> &mut ConfigBuilder {
128        self.0.thread = thread;
129        self
130    }
131
132    /// Set at which level and above (more verbose) the target shall be logged. (default is Debug)
133    pub fn set_target_level(&mut self, target: LevelFilter) -> &mut ConfigBuilder {
134        self.0.target = target;
135        self
136    }
137
138    /// Set how the thread should be padded
139    pub fn set_target_padding(&mut self, padding: TargetPadding) -> &mut ConfigBuilder {
140        self.0.target_padding = padding;
141        self
142    }
143
144    /// Set at which level and above (more verbose) a source code reference shall be logged (default is Trace)
145    pub fn set_location_level(&mut self, location: LevelFilter) -> &mut ConfigBuilder {
146        self.0.location = location;
147        self
148    }
149
150    /// Set how the levels should be padded, when logging (default is Off)
151    pub fn set_level_padding(&mut self, padding: LevelPadding) -> &mut ConfigBuilder {
152        self.0.level_padding = padding;
153        self
154    }
155
156    /// Set how the thread should be padded
157    pub fn set_thread_padding(&mut self, padding: ThreadPadding) -> &mut ConfigBuilder {
158        self.0.thread_padding = padding;
159        self
160    }
161
162    /// Set the mode for logging the thread
163    pub fn set_thread_mode(&mut self, mode: ThreadLogMode) -> &mut ConfigBuilder {
164        self.0.thread_log_mode = mode;
165        self
166    }
167
168    /// Set the color used for printing the level (if the logger supports it),
169    /// or None to use the default foreground color
170    #[cfg(feature = "termcolor")]
171    pub fn set_level_color(&mut self, level: Level, color: Option<Color>) -> &mut ConfigBuilder {
172        self.0.level_color[level as usize] = color;
173        self
174    }
175
176    /// Sets the time format to a custom representation.
177    ///
178    /// The easiest way to satisfy the static lifetime of the argument is to directly use the
179    /// re-exported [`time::macros::format_description`] macro.
180    ///
181    /// *Note*: The default time format is "[hour]:[minute]:[second]".
182    ///
183    /// The syntax for the format_description macro can be found in the
184    /// [`time` crate book](https://time-rs.github.io/book/api/format-description.html).
185    ///
186    /// # Usage
187    ///
188    /// ```
189    /// # use simplelog::{ConfigBuilder, format_description};
190    /// let config = ConfigBuilder::new()
191    ///     .set_time_format_custom(format_description!("[hour]:[minute]:[second].[subsecond]"))
192    ///     .build();
193    /// ```
194    pub fn set_time_format_custom(
195        &mut self,
196        time_format: &'static [FormatItem<'static>],
197    ) -> &mut ConfigBuilder {
198        self.0.time_format = TimeFormat::Custom(time_format);
199        self
200    }
201
202    /// Set time format string to use rfc2822.
203    pub fn set_time_format_rfc2822(&mut self) -> &mut ConfigBuilder {
204        self.0.time_format = TimeFormat::Rfc2822;
205        self
206    }
207
208    /// Set time format string to use rfc3339.
209    pub fn set_time_format_rfc3339(&mut self) -> &mut ConfigBuilder {
210        self.0.time_format = TimeFormat::Rfc3339;
211        self
212    }
213
214    /// Set offset used for logging time (default is UTC)
215    pub fn set_time_offset(&mut self, offset: UtcOffset) -> &mut ConfigBuilder {
216        self.0.time_offset = offset;
217        self
218    }
219
220    /// Sets the offset used to the current local time offset
221    /// (overriding values previously set by [`ConfigBuilder::set_time_offset`]).
222    ///
223    /// This function may fail if the offset cannot be determined soundly.
224    /// This may be the case, when the program is multi-threaded by the time of calling this function.
225    /// One can opt-out of this behavior by setting `RUSTFLAGS="--cfg unsound_local_offset"`.
226    /// Doing so is not recommended, completely untested and may cause unexpected segfaults.
227    #[cfg(feature = "local-offset")]
228    pub fn set_time_offset_to_local(&mut self) -> Result<&mut ConfigBuilder, &mut ConfigBuilder> {
229        match UtcOffset::current_local_offset() {
230            Ok(offset) => {
231                self.0.time_offset = offset;
232                Ok(self)
233            }
234            Err(_) => Err(self),
235        }
236    }
237
238    /// set if you want to write colors in the logfile (default is Off)
239    #[cfg(feature = "ansi_term")]
240    pub fn set_write_log_enable_colors(&mut self, local: bool) -> &mut ConfigBuilder {
241        self.0.write_log_enable_colors = local;
242        self
243    }
244
245    /// Add allowed module filters.
246    /// If any are specified, only records from modules starting with one of these entries will be printed
247    ///
248    /// For example, `add_filter_allow_str("tokio::uds")` would allow only logging from the `tokio` crates `uds` module.
249    pub fn add_filter_allow_str(&mut self, filter_allow: &'static str) -> &mut ConfigBuilder {
250        let mut list = Vec::from(&*self.0.filter_allow);
251        list.push(Cow::Borrowed(filter_allow));
252        self.0.filter_allow = Cow::Owned(list);
253        self
254    }
255
256    /// Add allowed module filters.
257    /// If any are specified, only records from modules starting with one of these entries will be printed
258    ///
259    /// For example, `add_filter_allow(format!("{}{}","tokio", "uds"))` would allow only logging from the `tokio` crates `uds` module.
260    pub fn add_filter_allow(&mut self, filter_allow: String) -> &mut ConfigBuilder {
261        let mut list = Vec::from(&*self.0.filter_allow);
262        list.push(Cow::Owned(filter_allow));
263        self.0.filter_allow = Cow::Owned(list);
264        self
265    }
266
267    /// Clear allowed module filters.
268    /// If none are specified, nothing is filtered out
269    pub fn clear_filter_allow(&mut self) -> &mut ConfigBuilder {
270        self.0.filter_allow = Cow::Borrowed(&[]);
271        self
272    }
273
274    /// Add denied module filters.
275    /// If any are specified, records from modules starting with one of these entries will be ignored
276    ///
277    /// For example, `add_filter_ignore_str("tokio::uds")` would deny logging from the `tokio` crates `uds` module.
278    pub fn add_filter_ignore_str(&mut self, filter_ignore: &'static str) -> &mut ConfigBuilder {
279        let mut list = Vec::from(&*self.0.filter_ignore);
280        list.push(Cow::Borrowed(filter_ignore));
281        self.0.filter_ignore = Cow::Owned(list);
282        self
283    }
284
285    /// Add denied module filters.
286    /// If any are specified, records from modules starting with one of these entries will be ignored
287    ///
288    /// For example, `add_filter_ignore(format!("{}{}","tokio", "uds"))` would deny logging from the `tokio` crates `uds` module.
289    pub fn add_filter_ignore(&mut self, filter_ignore: String) -> &mut ConfigBuilder {
290        let mut list = Vec::from(&*self.0.filter_ignore);
291        list.push(Cow::Owned(filter_ignore));
292        self.0.filter_ignore = Cow::Owned(list);
293        self
294    }
295
296    /// Clear ignore module filters.
297    /// If none are specified, nothing is filtered
298    pub fn clear_filter_ignore(&mut self) -> &mut ConfigBuilder {
299        self.0.filter_ignore = Cow::Borrowed(&[]);
300        self
301    }
302
303    /// Build new `Config`
304    pub fn build(&mut self) -> Config {
305        self.0.clone()
306    }
307}
308
309impl Default for ConfigBuilder {
310    fn default() -> Self {
311        ConfigBuilder::new()
312    }
313}
314
315impl Default for Config {
316    fn default() -> Config {
317        Config {
318            time: LevelFilter::Error,
319            level: LevelFilter::Error,
320            level_padding: LevelPadding::Off,
321            thread: LevelFilter::Debug,
322            thread_log_mode: ThreadLogMode::IDs,
323            thread_padding: ThreadPadding::Off,
324            target: LevelFilter::Debug,
325            target_padding: TargetPadding::Off,
326            location: LevelFilter::Trace,
327            time_format: TimeFormat::Custom(format_description!("[hour]:[minute]:[second]")),
328            time_offset: UtcOffset::UTC,
329            filter_allow: Cow::Borrowed(&[]),
330            filter_ignore: Cow::Borrowed(&[]),
331            write_log_enable_colors: false,
332
333            #[cfg(feature = "termcolor")]
334            level_color: [
335                None,                // Default foreground
336                Some(Color::Red),    // Error
337                Some(Color::Yellow), // Warn
338                Some(Color::Blue),   // Info
339                Some(Color::Cyan),   // Debug
340                Some(Color::White),  // Trace
341            ],
342        }
343    }
344}