/rust/registry/src/index.crates.io-6f17d22bba15001f/simple_logger-4.3.3/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! A logger that prints all messages with a simple, readable output format. |
2 | | //! |
3 | | //! Optional features include timestamps, colored output and logging to stderr. |
4 | | //! |
5 | | //! ```rust |
6 | | //! simple_logger::SimpleLogger::new().env().init().unwrap(); |
7 | | //! |
8 | | //! log::warn!("This is an example message."); |
9 | | //! ``` |
10 | | //! |
11 | | //! Some shortcuts are available for common use cases. |
12 | | //! |
13 | | //! Just initialize logging without any configuration: |
14 | | //! |
15 | | //! ```rust |
16 | | //! simple_logger::init().unwrap(); |
17 | | //! ``` |
18 | | //! |
19 | | //! Set the log level from the `RUST_LOG` environment variable: |
20 | | //! |
21 | | //! ```rust |
22 | | //! simple_logger::init_with_env().unwrap(); |
23 | | //! ``` |
24 | | //! |
25 | | //! Hardcode a default log level: |
26 | | //! |
27 | | //! ```rust |
28 | | //! simple_logger::init_with_level(log::Level::Warn).unwrap(); |
29 | | //! ``` |
30 | | |
31 | | #![cfg_attr(feature = "nightly", feature(thread_id_value))] |
32 | | |
33 | | #[cfg(feature = "colored")] |
34 | | use colored::*; |
35 | | use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; |
36 | | use std::{collections::HashMap, str::FromStr}; |
37 | | #[cfg(feature = "timestamps")] |
38 | | use time::{format_description::FormatItem, OffsetDateTime, UtcOffset}; |
39 | | |
40 | | #[cfg(feature = "timestamps")] |
41 | | const TIMESTAMP_FORMAT_OFFSET: &[FormatItem] = time::macros::format_description!( |
42 | | "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3][offset_hour sign:mandatory]:[offset_minute]" |
43 | | ); |
44 | | |
45 | | #[cfg(feature = "timestamps")] |
46 | | const TIMESTAMP_FORMAT_UTC: &[FormatItem] = |
47 | | time::macros::format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z"); |
48 | | |
49 | | #[cfg(feature = "timestamps")] |
50 | | #[derive(PartialEq)] |
51 | | enum Timestamps { |
52 | | None, |
53 | | Local, |
54 | | Utc, |
55 | | UtcOffset(UtcOffset), |
56 | | } |
57 | | |
58 | | /// Implements [`Log`] and a set of simple builder methods for configuration. |
59 | | /// |
60 | | /// Use the various "builder" methods on this struct to configure the logger, |
61 | | /// then call [`init`] to configure the [`log`] crate. |
62 | | pub struct SimpleLogger { |
63 | | /// The default logging level |
64 | | default_level: LevelFilter, |
65 | | |
66 | | /// The specific logging level for each module |
67 | | /// |
68 | | /// This is used to override the default value for some specific modules. |
69 | | /// |
70 | | /// This must be sorted from most-specific to least-specific, so that [`enabled`](#method.enabled) can scan the |
71 | | /// vector for the first match to give us the desired log level for a module. |
72 | | module_levels: Vec<(String, LevelFilter)>, |
73 | | |
74 | | /// Whether to include thread names (and IDs) or not |
75 | | /// |
76 | | /// This field is only available if the `threads` feature is enabled. |
77 | | #[cfg(feature = "threads")] |
78 | | threads: bool, |
79 | | |
80 | | /// Control how timestamps are displayed. |
81 | | /// |
82 | | /// This field is only available if the `timestamps` feature is enabled. |
83 | | #[cfg(feature = "timestamps")] |
84 | | timestamps: Timestamps, |
85 | | #[cfg(feature = "timestamps")] |
86 | | timestamps_format: Option<&'static [FormatItem<'static>]>, |
87 | | |
88 | | /// Whether to use color output or not. |
89 | | /// |
90 | | /// This field is only available if the `color` feature is enabled. |
91 | | #[cfg(feature = "colored")] |
92 | | colors: bool, |
93 | | } |
94 | | |
95 | | impl SimpleLogger { |
96 | | /// Initializes the global logger with a SimpleLogger instance with |
97 | | /// default log level set to `Level::Trace`. |
98 | | /// |
99 | | /// ```no_run |
100 | | /// use simple_logger::SimpleLogger; |
101 | | /// SimpleLogger::new().env().init().unwrap(); |
102 | | /// log::warn!("This is an example message."); |
103 | | /// ``` |
104 | | /// |
105 | | /// [`init`]: #method.init |
106 | | #[must_use = "You must call init() to begin logging"] |
107 | 0 | pub fn new() -> SimpleLogger { |
108 | 0 | SimpleLogger { |
109 | 0 | default_level: LevelFilter::Trace, |
110 | 0 | module_levels: Vec::new(), |
111 | 0 |
|
112 | 0 | #[cfg(feature = "threads")] |
113 | 0 | threads: false, |
114 | 0 |
|
115 | 0 | #[cfg(feature = "timestamps")] |
116 | 0 | timestamps: Timestamps::Utc, |
117 | 0 |
|
118 | 0 | #[cfg(feature = "timestamps")] |
119 | 0 | timestamps_format: None, |
120 | 0 |
|
121 | 0 | #[cfg(feature = "colored")] |
122 | 0 | colors: true, |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | /// Initializes the global logger with log level read from `RUST_LOG` environment |
127 | | /// variable value. Deprecated in favor of `env()`. |
128 | | /// |
129 | | /// You may use the various builder-style methods on this type to configure |
130 | | /// the logger, and you must call [`init`] in order to start logging messages. |
131 | | /// |
132 | | /// ```no_run |
133 | | /// use simple_logger::SimpleLogger; |
134 | | /// SimpleLogger::from_env().init().unwrap(); |
135 | | /// log::warn!("This is an example message."); |
136 | | /// ``` |
137 | | /// |
138 | | /// [`init`]: #method.init |
139 | | #[must_use = "You must call init() to begin logging"] |
140 | | #[deprecated( |
141 | | since = "1.12.0", |
142 | | note = "Use [`env`](#method.env) instead. Will be removed in version 2.0.0." |
143 | | )] |
144 | 0 | pub fn from_env() -> SimpleLogger { |
145 | 0 | SimpleLogger::new().with_level(log::LevelFilter::Error).env() |
146 | 0 | } |
147 | | |
148 | | /// Enables the user to choose log level by setting `RUST_LOG=<level>` |
149 | | /// environment variable. This will use the default level set by |
150 | | /// [`with_level`] if `RUST_LOG` is not set or can't be parsed as a |
151 | | /// standard log level. |
152 | | /// |
153 | | /// This must be called after [`with_level`]. If called before |
154 | | /// [`with_level`], it will have no effect. |
155 | | /// |
156 | | /// [`with_level`]: #method.with_level |
157 | | #[must_use = "You must call init() to begin logging"] |
158 | 0 | pub fn env(mut self) -> SimpleLogger { |
159 | 0 | self.default_level = std::env::var("RUST_LOG") |
160 | 0 | .ok() |
161 | 0 | .as_deref() |
162 | 0 | .map(log::LevelFilter::from_str) |
163 | 0 | .and_then(Result::ok) |
164 | 0 | .unwrap_or(self.default_level); |
165 | 0 |
|
166 | 0 | self |
167 | 0 | } |
168 | | |
169 | | /// Set the 'default' log level. |
170 | | /// |
171 | | /// You can override the default level for specific modules and their sub-modules using [`with_module_level`] |
172 | | /// |
173 | | /// This must be called before [`env`]. If called after [`env`], it will override the value loaded from the environment. |
174 | | /// |
175 | | /// [`env`]: #method.env |
176 | | /// [`with_module_level`]: #method.with_module_level |
177 | | #[must_use = "You must call init() to begin logging"] |
178 | 0 | pub fn with_level(mut self, level: LevelFilter) -> SimpleLogger { |
179 | 0 | self.default_level = level; |
180 | 0 | self |
181 | 0 | } |
182 | | |
183 | | /// Override the log level for some specific modules. |
184 | | /// |
185 | | /// This sets the log level of a specific module and all its sub-modules. |
186 | | /// When both the level for a parent module as well as a child module are set, |
187 | | /// the more specific value is taken. If the log level for the same module is |
188 | | /// specified twice, the resulting log level is implementation defined. |
189 | | /// |
190 | | /// # Examples |
191 | | /// |
192 | | /// Silence an overly verbose crate: |
193 | | /// |
194 | | /// ```no_run |
195 | | /// use simple_logger::SimpleLogger; |
196 | | /// use log::LevelFilter; |
197 | | /// |
198 | | /// SimpleLogger::new().with_module_level("chatty_dependency", LevelFilter::Warn).init().unwrap(); |
199 | | /// ``` |
200 | | /// |
201 | | /// Disable logging for all dependencies: |
202 | | /// |
203 | | /// ```no_run |
204 | | /// use simple_logger::SimpleLogger; |
205 | | /// use log::LevelFilter; |
206 | | /// |
207 | | /// SimpleLogger::new() |
208 | | /// .with_level(LevelFilter::Off) |
209 | | /// .with_module_level("my_crate", LevelFilter::Info) |
210 | | /// .init() |
211 | | /// .unwrap(); |
212 | | /// ``` |
213 | | // |
214 | | // This method *must* sort `module_levels` for the [`enabled`](#method.enabled) method to work correctly. |
215 | | #[must_use = "You must call init() to begin logging"] |
216 | 0 | pub fn with_module_level(mut self, target: &str, level: LevelFilter) -> SimpleLogger { |
217 | 0 | self.module_levels.push((target.to_string(), level)); |
218 | 0 | self.module_levels |
219 | 0 | .sort_by_key(|(name, _level)| name.len().wrapping_neg()); |
220 | 0 | self |
221 | 0 | } |
222 | | |
223 | | /// Override the log level for specific targets. |
224 | | // This method *must* sort `module_levels` for the [`enabled`](#method.enabled) method to work correctly. |
225 | | #[must_use = "You must call init() to begin logging"] |
226 | | #[deprecated( |
227 | | since = "1.11.0", |
228 | | note = "Use [`with_module_level`](#method.with_module_level) instead. Will be removed in version 2.0.0." |
229 | | )] |
230 | 0 | pub fn with_target_levels(mut self, target_levels: HashMap<String, LevelFilter>) -> SimpleLogger { |
231 | 0 | self.module_levels = target_levels.into_iter().collect(); |
232 | 0 | self.module_levels |
233 | 0 | .sort_by_key(|(name, _level)| name.len().wrapping_neg()); |
234 | 0 | self |
235 | 0 | } |
236 | | |
237 | | /// Control whether thread names (and IDs) are printed or not. |
238 | | /// |
239 | | /// This method is only available if the `threads` feature is enabled. |
240 | | /// Thread names are disabled by default. |
241 | | #[must_use = "You must call init() to begin logging"] |
242 | | #[cfg(feature = "threads")] |
243 | | pub fn with_threads(mut self, threads: bool) -> SimpleLogger { |
244 | | self.threads = threads; |
245 | | self |
246 | | } |
247 | | |
248 | | /// Control whether timestamps are printed or not. |
249 | | /// |
250 | | /// Timestamps will be displayed in the local timezone. |
251 | | /// |
252 | | /// This method is only available if the `timestamps` feature is enabled. |
253 | | #[must_use = "You must call init() to begin logging"] |
254 | | #[cfg(feature = "timestamps")] |
255 | | #[deprecated( |
256 | | since = "1.16.0", |
257 | | note = "Use [`with_local_timestamps`] or [`with_utc_timestamps`] instead. Will be removed in version 2.0.0." |
258 | | )] |
259 | 0 | pub fn with_timestamps(mut self, timestamps: bool) -> SimpleLogger { |
260 | 0 | if timestamps { |
261 | 0 | self.timestamps = Timestamps::Local |
262 | | } else { |
263 | 0 | self.timestamps = Timestamps::None |
264 | | } |
265 | 0 | self |
266 | 0 | } |
267 | | |
268 | | /// Control the format used for timestamps. |
269 | | /// |
270 | | /// Without this, a default format is used depending on the timestamps type. |
271 | | /// |
272 | | /// The syntax for the format_description macro can be found in the |
273 | | /// [`time` crate book](https://time-rs.github.io/book/api/format-description.html). |
274 | | /// |
275 | | /// ``` |
276 | | /// simple_logger::SimpleLogger::new() |
277 | | /// .with_level(log::LevelFilter::Debug) |
278 | | /// .env() |
279 | | /// .with_timestamp_format(time::macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]")) |
280 | | /// .init() |
281 | | /// .unwrap(); |
282 | | /// ``` |
283 | | #[must_use = "You must call init() to begin logging"] |
284 | | #[cfg(feature = "timestamps")] |
285 | 0 | pub fn with_timestamp_format(mut self, format: &'static [FormatItem<'static>]) -> SimpleLogger { |
286 | 0 | self.timestamps_format = Some(format); |
287 | 0 | self |
288 | 0 | } |
289 | | |
290 | | /// Don't display any timestamps. |
291 | | /// |
292 | | /// This method is only available if the `timestamps` feature is enabled. |
293 | | #[must_use = "You must call init() to begin logging"] |
294 | | #[cfg(feature = "timestamps")] |
295 | 0 | pub fn without_timestamps(mut self) -> SimpleLogger { |
296 | 0 | self.timestamps = Timestamps::None; |
297 | 0 | self |
298 | 0 | } |
299 | | |
300 | | /// Display timestamps using the local timezone. |
301 | | /// |
302 | | /// This method is only available if the `timestamps` feature is enabled. |
303 | | #[must_use = "You must call init() to begin logging"] |
304 | | #[cfg(feature = "timestamps")] |
305 | 0 | pub fn with_local_timestamps(mut self) -> SimpleLogger { |
306 | 0 | self.timestamps = Timestamps::Local; |
307 | 0 | self |
308 | 0 | } |
309 | | |
310 | | /// Display timestamps using UTC. |
311 | | /// |
312 | | /// This method is only available if the `timestamps` feature is enabled. |
313 | | #[must_use = "You must call init() to begin logging"] |
314 | | #[cfg(feature = "timestamps")] |
315 | 0 | pub fn with_utc_timestamps(mut self) -> SimpleLogger { |
316 | 0 | self.timestamps = Timestamps::Utc; |
317 | 0 | self |
318 | 0 | } |
319 | | |
320 | | /// Display timestamps using a static UTC offset. |
321 | | /// |
322 | | /// This method is only available if the `timestamps` feature is enabled. |
323 | | #[must_use = "You must call init() to begin logging"] |
324 | | #[cfg(feature = "timestamps")] |
325 | 0 | pub fn with_utc_offset(mut self, offset: UtcOffset) -> SimpleLogger { |
326 | 0 | self.timestamps = Timestamps::UtcOffset(offset); |
327 | 0 | self |
328 | 0 | } |
329 | | |
330 | | /// Control whether messages are colored or not. |
331 | | /// |
332 | | /// This method is only available if the `colored` feature is enabled. |
333 | | #[must_use = "You must call init() to begin logging"] |
334 | | #[cfg(feature = "colored")] |
335 | 0 | pub fn with_colors(mut self, colors: bool) -> SimpleLogger { |
336 | 0 | self.colors = colors; |
337 | 0 | self |
338 | 0 | } |
339 | | |
340 | | /// Configure the logger |
341 | 0 | pub fn max_level(&self) -> LevelFilter { |
342 | 0 | let max_level = self.module_levels.iter().map(|(_name, level)| level).copied().max(); |
343 | 0 | max_level |
344 | 0 | .map(|lvl| lvl.max(self.default_level)) |
345 | 0 | .unwrap_or(self.default_level) |
346 | 0 | } |
347 | | |
348 | | /// 'Init' the actual logger and instantiate it, |
349 | | /// this method MUST be called in order for the logger to be effective. |
350 | 0 | pub fn init(self) -> Result<(), SetLoggerError> { |
351 | 0 | #[cfg(all(windows, feature = "colored"))] |
352 | 0 | set_up_color_terminal(); |
353 | 0 |
|
354 | 0 | log::set_max_level(self.max_level()); |
355 | 0 | log::set_boxed_logger(Box::new(self)) |
356 | 0 | } |
357 | | } |
358 | | |
359 | | impl Default for SimpleLogger { |
360 | | /// See [this](struct.SimpleLogger.html#method.new) |
361 | 0 | fn default() -> Self { |
362 | 0 | SimpleLogger::new() |
363 | 0 | } |
364 | | } |
365 | | |
366 | | impl Log for SimpleLogger { |
367 | 0 | fn enabled(&self, metadata: &Metadata) -> bool { |
368 | 0 | &metadata.level().to_level_filter() |
369 | 0 | <= self |
370 | 0 | .module_levels |
371 | 0 | .iter() |
372 | 0 | /* At this point the Vec is already sorted so that we can simply take |
373 | 0 | * the first match |
374 | 0 | */ |
375 | 0 | .find(|(name, _level)| metadata.target().starts_with(name)) |
376 | 0 | .map(|(_name, level)| level) |
377 | 0 | .unwrap_or(&self.default_level) |
378 | 0 | } |
379 | | |
380 | 0 | fn log(&self, record: &Record) { |
381 | 0 | if self.enabled(record.metadata()) { |
382 | 0 | let level_string = { |
383 | | #[cfg(feature = "colored")] |
384 | | { |
385 | 0 | if self.colors { |
386 | 0 | match record.level() { |
387 | 0 | Level::Error => format!("{:<5}", record.level().to_string()).red().to_string(), |
388 | 0 | Level::Warn => format!("{:<5}", record.level().to_string()).yellow().to_string(), |
389 | 0 | Level::Info => format!("{:<5}", record.level().to_string()).cyan().to_string(), |
390 | 0 | Level::Debug => format!("{:<5}", record.level().to_string()).purple().to_string(), |
391 | 0 | Level::Trace => format!("{:<5}", record.level().to_string()).normal().to_string(), |
392 | | } |
393 | | } else { |
394 | 0 | format!("{:<5}", record.level().to_string()) |
395 | | } |
396 | | } |
397 | | #[cfg(not(feature = "colored"))] |
398 | | { |
399 | | format!("{:<5}", record.level().to_string()) |
400 | | } |
401 | | }; |
402 | | |
403 | 0 | let target = if !record.target().is_empty() { |
404 | 0 | record.target() |
405 | | } else { |
406 | 0 | record.module_path().unwrap_or_default() |
407 | | }; |
408 | | |
409 | 0 | let thread = { |
410 | 0 | #[cfg(feature = "threads")] |
411 | 0 | if self.threads { |
412 | 0 | let thread = std::thread::current(); |
413 | 0 |
|
414 | 0 | format!("@{}", { |
415 | 0 | #[cfg(feature = "nightly")] |
416 | 0 | { |
417 | 0 | thread.name().unwrap_or(&thread.id().as_u64().to_string()) |
418 | 0 | } |
419 | 0 |
|
420 | 0 | #[cfg(not(feature = "nightly"))] |
421 | 0 | { |
422 | 0 | thread.name().unwrap_or("?") |
423 | 0 | } |
424 | 0 | }) |
425 | 0 | } else { |
426 | 0 | "".to_string() |
427 | 0 | } |
428 | 0 |
|
429 | 0 | #[cfg(not(feature = "threads"))] |
430 | 0 | "" |
431 | | }; |
432 | | |
433 | 0 | let timestamp = { |
434 | | #[cfg(feature = "timestamps")] |
435 | 0 | match self.timestamps { |
436 | 0 | Timestamps::None => "".to_string(), |
437 | 0 | Timestamps::Local => format!( |
438 | 0 | "{} ", |
439 | 0 | OffsetDateTime::now_local() |
440 | 0 | .expect(concat!( |
441 | 0 | "Could not determine the UTC offset on this system. ", |
442 | 0 | "Consider displaying UTC time instead. ", |
443 | 0 | "Possible causes are that the time crate does not implement \"local_offset_at\" ", |
444 | 0 | "on your system, or that you are running in a multi-threaded environment and ", |
445 | 0 | "the time crate is returning \"None\" from \"local_offset_at\" to avoid unsafe ", |
446 | 0 | "behaviour. See the time crate's documentation for more information. ", |
447 | 0 | "(https://time-rs.github.io/internal-api/time/index.html#feature-flags)" |
448 | 0 | )) |
449 | 0 | .format(&self.timestamps_format.unwrap_or(TIMESTAMP_FORMAT_OFFSET)) |
450 | 0 | .unwrap() |
451 | 0 | ), |
452 | 0 | Timestamps::Utc => format!( |
453 | 0 | "{} ", |
454 | 0 | OffsetDateTime::now_utc() |
455 | 0 | .format(&self.timestamps_format.unwrap_or(TIMESTAMP_FORMAT_UTC)) |
456 | 0 | .unwrap() |
457 | 0 | ), |
458 | 0 | Timestamps::UtcOffset(offset) => format!( |
459 | 0 | "{} ", |
460 | 0 | OffsetDateTime::now_utc() |
461 | 0 | .to_offset(offset) |
462 | 0 | .format(&self.timestamps_format.unwrap_or(TIMESTAMP_FORMAT_OFFSET)) |
463 | 0 | .unwrap() |
464 | 0 | ), |
465 | | } |
466 | | |
467 | | #[cfg(not(feature = "timestamps"))] |
468 | | "" |
469 | | }; |
470 | | |
471 | 0 | let message = format!("{}{} [{}{}] {}", timestamp, level_string, target, thread, record.args()); |
472 | 0 |
|
473 | 0 | #[cfg(not(feature = "stderr"))] |
474 | 0 | println!("{}", message); |
475 | | |
476 | | #[cfg(feature = "stderr")] |
477 | | eprintln!("{}", message); |
478 | 0 | } |
479 | 0 | } |
480 | | |
481 | 0 | fn flush(&self) {} |
482 | | } |
483 | | |
484 | | /// Configure the console to display colours. |
485 | | /// |
486 | | /// This is only needed on Windows when using the 'colored' feature. |
487 | | #[cfg(all(windows, feature = "colored"))] |
488 | | pub fn set_up_color_terminal() { |
489 | | use std::io::{stdout, IsTerminal}; |
490 | | |
491 | | if stdout().is_terminal() { |
492 | | unsafe { |
493 | | use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; |
494 | | use windows_sys::Win32::System::Console::{ |
495 | | GetConsoleMode, GetStdHandle, SetConsoleMode, CONSOLE_MODE, ENABLE_VIRTUAL_TERMINAL_PROCESSING, |
496 | | STD_OUTPUT_HANDLE, |
497 | | }; |
498 | | |
499 | | let stdout = GetStdHandle(STD_OUTPUT_HANDLE); |
500 | | |
501 | | if stdout == INVALID_HANDLE_VALUE { |
502 | | return; |
503 | | } |
504 | | |
505 | | let mut mode: CONSOLE_MODE = 0; |
506 | | |
507 | | if GetConsoleMode(stdout, &mut mode) == 0 { |
508 | | return; |
509 | | } |
510 | | |
511 | | SetConsoleMode(stdout, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); |
512 | | } |
513 | | } |
514 | | } |
515 | | |
516 | | /// Configure the console to display colours. |
517 | | /// |
518 | | /// This method does nothing if not running on Windows with the colored feature. |
519 | | #[cfg(not(all(windows, feature = "colored")))] |
520 | 0 | pub fn set_up_color_terminal() {} |
521 | | |
522 | | /// Initialise the logger with its default configuration. |
523 | | /// |
524 | | /// Log messages will not be filtered. |
525 | | /// The `RUST_LOG` environment variable is not used. |
526 | 0 | pub fn init() -> Result<(), SetLoggerError> { |
527 | 0 | SimpleLogger::new().init() |
528 | 0 | } |
529 | | |
530 | | /// Initialise the logger with its default configuration. |
531 | | /// |
532 | | /// Log messages will not be filtered. |
533 | | /// The `RUST_LOG` environment variable is not used. |
534 | | /// |
535 | | /// This function is only available if the `timestamps` feature is enabled. |
536 | | #[cfg(feature = "timestamps")] |
537 | 0 | pub fn init_utc() -> Result<(), SetLoggerError> { |
538 | 0 | SimpleLogger::new().with_utc_timestamps().init() |
539 | 0 | } |
540 | | |
541 | | /// Initialise the logger with the `RUST_LOG` environment variable. |
542 | | /// |
543 | | /// Log messages will be filtered based on the `RUST_LOG` environment variable. |
544 | 0 | pub fn init_with_env() -> Result<(), SetLoggerError> { |
545 | 0 | SimpleLogger::new().env().init() |
546 | 0 | } |
547 | | |
548 | | /// Initialise the logger with a specific log level. |
549 | | /// |
550 | | /// Log messages below the given [`Level`] will be filtered. |
551 | | /// The `RUST_LOG` environment variable is not used. |
552 | 0 | pub fn init_with_level(level: Level) -> Result<(), SetLoggerError> { |
553 | 0 | SimpleLogger::new().with_level(level.to_level_filter()).init() |
554 | 0 | } |
555 | | |
556 | | /// Use [`init_with_env`] instead. |
557 | | /// |
558 | | /// This does the same as [`init_with_env`] but unwraps the result. |
559 | | #[deprecated( |
560 | | since = "1.12.0", |
561 | | note = "Use [`init_with_env`] instead, which does not unwrap the result. Will be removed in version 2.0.0." |
562 | | )] |
563 | 0 | pub fn init_by_env() { |
564 | 0 | init_with_env().unwrap() |
565 | 0 | } |
566 | | |
567 | | #[cfg(test)] |
568 | | mod test { |
569 | | use super::*; |
570 | | |
571 | | #[test] |
572 | | fn test_module_levels_allowlist() { |
573 | | let logger = SimpleLogger::new() |
574 | | .with_level(LevelFilter::Off) |
575 | | .with_module_level("my_crate", LevelFilter::Info); |
576 | | |
577 | | assert!(logger.enabled(&create_log("my_crate", Level::Info))); |
578 | | assert!(logger.enabled(&create_log("my_crate::module", Level::Info))); |
579 | | assert!(!logger.enabled(&create_log("my_crate::module", Level::Debug))); |
580 | | assert!(!logger.enabled(&create_log("not_my_crate", Level::Debug))); |
581 | | assert!(!logger.enabled(&create_log("not_my_crate::module", Level::Error))); |
582 | | } |
583 | | |
584 | | #[test] |
585 | | fn test_module_levels_denylist() { |
586 | | let logger = SimpleLogger::new() |
587 | | .with_level(LevelFilter::Debug) |
588 | | .with_module_level("my_crate", LevelFilter::Trace) |
589 | | .with_module_level("chatty_dependency", LevelFilter::Info); |
590 | | |
591 | | assert!(logger.enabled(&create_log("my_crate", Level::Info))); |
592 | | assert!(logger.enabled(&create_log("my_crate", Level::Trace))); |
593 | | assert!(logger.enabled(&create_log("my_crate::module", Level::Info))); |
594 | | assert!(logger.enabled(&create_log("my_crate::module", Level::Trace))); |
595 | | assert!(logger.enabled(&create_log("not_my_crate", Level::Debug))); |
596 | | assert!(!logger.enabled(&create_log("not_my_crate::module", Level::Trace))); |
597 | | assert!(logger.enabled(&create_log("chatty_dependency", Level::Info))); |
598 | | assert!(!logger.enabled(&create_log("chatty_dependency", Level::Debug))); |
599 | | assert!(!logger.enabled(&create_log("chatty_dependency::module", Level::Debug))); |
600 | | assert!(logger.enabled(&create_log("chatty_dependency::module", Level::Warn))); |
601 | | } |
602 | | |
603 | | /// Test that enabled() looks for the most specific target. |
604 | | #[test] |
605 | | fn test_module_levels() { |
606 | | let logger = SimpleLogger::new() |
607 | | .with_level(LevelFilter::Off) |
608 | | .with_module_level("a", LevelFilter::Off) |
609 | | .with_module_level("a::b::c", LevelFilter::Off) |
610 | | .with_module_level("a::b", LevelFilter::Info); |
611 | | |
612 | | assert_eq!(logger.enabled(&create_log("a", Level::Info)), false); |
613 | | assert_eq!(logger.enabled(&create_log("a::b", Level::Info)), true); |
614 | | assert_eq!(logger.enabled(&create_log("a::b::c", Level::Info)), false); |
615 | | } |
616 | | |
617 | | #[test] |
618 | | fn test_max_level() { |
619 | | let builder = SimpleLogger::new(); |
620 | | assert_eq!(builder.max_level(), LevelFilter::Trace); |
621 | | } |
622 | | |
623 | | #[test] |
624 | | #[cfg(feature = "timestamps")] |
625 | | fn test_timestamps_defaults() { |
626 | | let builder = SimpleLogger::new(); |
627 | | assert!(builder.timestamps == Timestamps::Utc); |
628 | | } |
629 | | |
630 | | #[test] |
631 | | #[cfg(feature = "timestamps")] |
632 | | #[allow(deprecated)] |
633 | | fn test_with_timestamps() { |
634 | | let builder = SimpleLogger::new().with_timestamps(false); |
635 | | assert!(builder.timestamps == Timestamps::None); |
636 | | } |
637 | | |
638 | | #[test] |
639 | | #[cfg(feature = "timestamps")] |
640 | | fn test_with_utc_timestamps() { |
641 | | let builder = SimpleLogger::new().with_utc_timestamps(); |
642 | | assert!(builder.timestamps == Timestamps::Utc); |
643 | | } |
644 | | |
645 | | #[test] |
646 | | #[cfg(feature = "timestamps")] |
647 | | fn test_with_local_timestamps() { |
648 | | let builder = SimpleLogger::new().with_local_timestamps(); |
649 | | assert!(builder.timestamps == Timestamps::Local); |
650 | | } |
651 | | |
652 | | #[test] |
653 | | #[cfg(feature = "timestamps")] |
654 | | #[allow(deprecated)] |
655 | | fn test_with_timestamps_format() { |
656 | | let builder = |
657 | | SimpleLogger::new().with_timestamp_format(time::macros::format_description!("[hour]:[minute]:[second]")); |
658 | | assert!(builder.timestamps_format.is_some()); |
659 | | } |
660 | | |
661 | | #[test] |
662 | | #[cfg(feature = "colored")] |
663 | | fn test_with_colors() { |
664 | | let mut builder = SimpleLogger::new(); |
665 | | assert!(builder.colors == true); |
666 | | |
667 | | builder = builder.with_colors(false); |
668 | | assert!(builder.colors == false); |
669 | | } |
670 | | |
671 | | /// > And, without sorting, this would lead to all serde_json logs being treated as if they were configured to |
672 | | /// > Error level instead of Trace (since to determine the logging level for target, the code finds first match in |
673 | | /// > module_levels by a string prefix). |
674 | | #[test] |
675 | | fn test_issue_90() { |
676 | | let logger = SimpleLogger::new() |
677 | | .with_level(LevelFilter::Off) |
678 | | .with_module_level("serde", LevelFilter::Error) |
679 | | .with_module_level("serde_json", LevelFilter::Trace); |
680 | | |
681 | | assert_eq!(logger.enabled(&create_log("serde", Level::Trace)), false); |
682 | | assert_eq!(logger.enabled(&create_log("serde_json", Level::Trace)), true); |
683 | | } |
684 | | |
685 | | fn create_log(name: &str, level: Level) -> Metadata { |
686 | | let mut builder = Metadata::builder(); |
687 | | builder.level(level); |
688 | | builder.target(name); |
689 | | builder.build() |
690 | | } |
691 | | } |