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}