]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT\r |
2 | // file at the top-level directory of this distribution and at\r | |
3 | // http://rust-lang.org/COPYRIGHT.\r | |
4 | //\r | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\r | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\r | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your\r | |
8 | // option. This file may not be copied, modified, or distributed\r | |
9 | // except according to those terms.\r | |
10 | \r | |
11 | //! A lightweight logging facade.\r | |
12 | //!\r | |
13 | //! The `log` crate provides a single logging API that abstracts over the\r | |
14 | //! actual logging implementation. Libraries can use the logging API provided\r | |
15 | //! by this crate, and the consumer of those libraries can choose the logging\r | |
16 | //! implementation that is most suitable for its use case.\r | |
17 | //!\r | |
18 | //! If no logging implementation is selected, the facade falls back to a "noop"\r | |
19 | //! implementation that ignores all log messages. The overhead in this case\r | |
20 | //! is very small - just an integer load, comparison and jump.\r | |
21 | //!\r | |
22 | //! A log request consists of a _target_, a _level_, and a _body_. A target is a\r | |
23 | //! string which defaults to the module path of the location of the log request,\r | |
24 | //! though that default may be overridden. Logger implementations typically use\r | |
25 | //! the target to filter requests based on some user configuration.\r | |
26 | //!\r | |
04454e1e | 27 | //! # Usage\r |
3dfed10e XL |
28 | //!\r |
29 | //! The basic use of the log crate is through the five logging macros: [`error!`],\r | |
30 | //! [`warn!`], [`info!`], [`debug!`] and [`trace!`]\r | |
31 | //! where `error!` represents the highest-priority log messages\r | |
32 | //! and `trace!` the lowest. The log messages are filtered by configuring\r | |
33 | //! the log level to exclude messages with a lower priority.\r | |
34 | //! Each of these macros accept format strings similarly to [`println!`].\r | |
35 | //!\r | |
36 | //!\r | |
37 | //! [`error!`]: ./macro.error.html\r | |
38 | //! [`warn!`]: ./macro.warn.html\r | |
39 | //! [`info!`]: ./macro.info.html\r | |
40 | //! [`debug!`]: ./macro.debug.html\r | |
41 | //! [`trace!`]: ./macro.trace.html\r | |
42 | //! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html\r | |
43 | //!\r | |
44 | //! ## In libraries\r | |
45 | //!\r | |
46 | //! Libraries should link only to the `log` crate, and use the provided\r | |
47 | //! macros to log whatever information will be useful to downstream consumers.\r | |
48 | //!\r | |
49 | //! ### Examples\r | |
50 | //!\r | |
51 | //! ```edition2018\r | |
52 | //! # #[derive(Debug)] pub struct Yak(String);\r | |
53 | //! # impl Yak { fn shave(&mut self, _: u32) {} }\r | |
54 | //! # fn find_a_razor() -> Result<u32, u32> { Ok(1) }\r | |
55 | //! use log::{info, warn};\r | |
56 | //!\r | |
57 | //! pub fn shave_the_yak(yak: &mut Yak) {\r | |
58 | //! info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);\r | |
59 | //!\r | |
60 | //! loop {\r | |
61 | //! match find_a_razor() {\r | |
62 | //! Ok(razor) => {\r | |
63 | //! info!("Razor located: {}", razor);\r | |
64 | //! yak.shave(razor);\r | |
65 | //! break;\r | |
66 | //! }\r | |
67 | //! Err(err) => {\r | |
68 | //! warn!("Unable to locate a razor: {}, retrying", err);\r | |
69 | //! }\r | |
70 | //! }\r | |
71 | //! }\r | |
72 | //! }\r | |
73 | //! # fn main() {}\r | |
74 | //! ```\r | |
75 | //!\r | |
76 | //! ## In executables\r | |
77 | //!\r | |
78 | //! Executables should choose a logging implementation and initialize it early in the\r | |
79 | //! runtime of the program. Logging implementations will typically include a\r | |
80 | //! function to do this. Any log messages generated before\r | |
81 | //! the implementation is initialized will be ignored.\r | |
82 | //!\r | |
83 | //! The executable itself may use the `log` crate to log as well.\r | |
84 | //!\r | |
85 | //! ### Warning\r | |
86 | //!\r | |
87 | //! The logging system may only be initialized once.\r | |
88 | //!\r | |
04454e1e FG |
89 | //! ## Structured logging\r |
90 | //!\r | |
91 | //! If you enable the `kv_unstable` feature you can associate structured values\r | |
92 | //! with your log records. If we take the example from before, we can include\r | |
93 | //! some additional context besides what's in the formatted message:\r | |
94 | //!\r | |
95 | //! ```edition2018\r | |
96 | //! # #[macro_use] extern crate serde;\r | |
97 | //! # #[derive(Debug, Serialize)] pub struct Yak(String);\r | |
98 | //! # impl Yak { fn shave(&mut self, _: u32) {} }\r | |
99 | //! # fn find_a_razor() -> Result<u32, std::io::Error> { Ok(1) }\r | |
100 | //! # #[cfg(feature = "kv_unstable_serde")]\r | |
101 | //! # fn main() {\r | |
102 | //! use log::{info, warn, as_serde, as_error};\r | |
103 | //!\r | |
104 | //! pub fn shave_the_yak(yak: &mut Yak) {\r | |
105 | //! info!(target: "yak_events", yak = as_serde!(yak); "Commencing yak shaving");\r | |
106 | //!\r | |
107 | //! loop {\r | |
108 | //! match find_a_razor() {\r | |
109 | //! Ok(razor) => {\r | |
110 | //! info!(razor = razor; "Razor located");\r | |
111 | //! yak.shave(razor);\r | |
112 | //! break;\r | |
113 | //! }\r | |
114 | //! Err(err) => {\r | |
115 | //! warn!(err = as_error!(err); "Unable to locate a razor, retrying");\r | |
116 | //! }\r | |
117 | //! }\r | |
118 | //! }\r | |
119 | //! }\r | |
120 | //! # }\r | |
121 | //! # #[cfg(not(feature = "kv_unstable_serde"))]\r | |
122 | //! # fn main() {}\r | |
123 | //! ```\r | |
124 | //!\r | |
3dfed10e XL |
125 | //! # Available logging implementations\r |
126 | //!\r | |
127 | //! In order to produce log output executables have to use\r | |
128 | //! a logger implementation compatible with the facade.\r | |
129 | //! There are many available implementations to choose from,\r | |
130 | //! here are some of the most popular ones:\r | |
131 | //!\r | |
132 | //! * Simple minimal loggers:\r | |
133 | //! * [env_logger]\r | |
134 | //! * [simple_logger]\r | |
135 | //! * [simplelog]\r | |
136 | //! * [pretty_env_logger]\r | |
137 | //! * [stderrlog]\r | |
138 | //! * [flexi_logger]\r | |
139 | //! * Complex configurable frameworks:\r | |
140 | //! * [log4rs]\r | |
141 | //! * [fern]\r | |
142 | //! * Adaptors for other facilities:\r | |
143 | //! * [syslog]\r | |
144 | //! * [slog-stdlog]\r | |
04454e1e FG |
145 | //! * [systemd-journal-logger]\r |
146 | //! * [android_log]\r | |
147 | //! * [win_dbg_logger]\r | |
923072b8 | 148 | //! * [db_logger]\r |
04454e1e FG |
149 | //! * For WebAssembly binaries:\r |
150 | //! * [console_log]\r | |
151 | //! * For dynamic libraries:\r | |
152 | //! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries\r | |
3dfed10e XL |
153 | //!\r |
154 | //! # Implementing a Logger\r | |
155 | //!\r | |
156 | //! Loggers implement the [`Log`] trait. Here's a very basic example that simply\r | |
157 | //! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or\r | |
158 | //! [`Info`][level_link] levels to stdout:\r | |
159 | //!\r | |
160 | //! ```edition2018\r | |
161 | //! use log::{Record, Level, Metadata};\r | |
162 | //!\r | |
163 | //! struct SimpleLogger;\r | |
164 | //!\r | |
165 | //! impl log::Log for SimpleLogger {\r | |
166 | //! fn enabled(&self, metadata: &Metadata) -> bool {\r | |
167 | //! metadata.level() <= Level::Info\r | |
168 | //! }\r | |
169 | //!\r | |
170 | //! fn log(&self, record: &Record) {\r | |
171 | //! if self.enabled(record.metadata()) {\r | |
172 | //! println!("{} - {}", record.level(), record.args());\r | |
173 | //! }\r | |
174 | //! }\r | |
175 | //!\r | |
176 | //! fn flush(&self) {}\r | |
177 | //! }\r | |
178 | //!\r | |
179 | //! # fn main() {}\r | |
180 | //! ```\r | |
181 | //!\r | |
182 | //! Loggers are installed by calling the [`set_logger`] function. The maximum\r | |
183 | //! log level also needs to be adjusted via the [`set_max_level`] function. The\r | |
184 | //! logging facade uses this as an optimization to improve performance of log\r | |
185 | //! messages at levels that are disabled. It's important to set it, as it\r | |
186 | //! defaults to [`Off`][filter_link], so no log messages will ever be captured!\r | |
187 | //! In the case of our example logger, we'll want to set the maximum log level\r | |
188 | //! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or\r | |
189 | //! [`Trace`][level_link] level log messages. A logging implementation should\r | |
190 | //! provide a function that wraps a call to [`set_logger`] and\r | |
191 | //! [`set_max_level`], handling initialization of the logger:\r | |
192 | //!\r | |
193 | //! ```edition2018\r | |
194 | //! # use log::{Level, Metadata};\r | |
195 | //! # struct SimpleLogger;\r | |
196 | //! # impl log::Log for SimpleLogger {\r | |
197 | //! # fn enabled(&self, _: &Metadata) -> bool { false }\r | |
198 | //! # fn log(&self, _: &log::Record) {}\r | |
199 | //! # fn flush(&self) {}\r | |
200 | //! # }\r | |
201 | //! # fn main() {}\r | |
202 | //! use log::{SetLoggerError, LevelFilter};\r | |
203 | //!\r | |
204 | //! static LOGGER: SimpleLogger = SimpleLogger;\r | |
205 | //!\r | |
206 | //! pub fn init() -> Result<(), SetLoggerError> {\r | |
207 | //! log::set_logger(&LOGGER)\r | |
208 | //! .map(|()| log::set_max_level(LevelFilter::Info))\r | |
209 | //! }\r | |
210 | //! ```\r | |
211 | //!\r | |
212 | //! Implementations that adjust their configurations at runtime should take care\r | |
213 | //! to adjust the maximum log level as well.\r | |
214 | //!\r | |
215 | //! # Use with `std`\r | |
216 | //!\r | |
217 | //! `set_logger` requires you to provide a `&'static Log`, which can be hard to\r | |
218 | //! obtain if your logger depends on some runtime configuration. The\r | |
219 | //! `set_boxed_logger` function is available with the `std` Cargo feature. It is\r | |
220 | //! identical to `set_logger` except that it takes a `Box<Log>` rather than a\r | |
221 | //! `&'static Log`:\r | |
222 | //!\r | |
223 | //! ```edition2018\r | |
224 | //! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata};\r | |
225 | //! # struct SimpleLogger;\r | |
226 | //! # impl log::Log for SimpleLogger {\r | |
227 | //! # fn enabled(&self, _: &Metadata) -> bool { false }\r | |
228 | //! # fn log(&self, _: &log::Record) {}\r | |
229 | //! # fn flush(&self) {}\r | |
230 | //! # }\r | |
231 | //! # fn main() {}\r | |
232 | //! # #[cfg(feature = "std")]\r | |
233 | //! pub fn init() -> Result<(), SetLoggerError> {\r | |
234 | //! log::set_boxed_logger(Box::new(SimpleLogger))\r | |
235 | //! .map(|()| log::set_max_level(LevelFilter::Info))\r | |
236 | //! }\r | |
237 | //! ```\r | |
238 | //!\r | |
239 | //! # Compile time filters\r | |
240 | //!\r | |
241 | //! Log levels can be statically disabled at compile time via Cargo features. Log invocations at\r | |
242 | //! disabled levels will be skipped and will not even be present in the resulting binary.\r | |
243 | //! This level is configured separately for release and debug builds. The features are:\r | |
244 | //!\r | |
245 | //! * `max_level_off`\r | |
246 | //! * `max_level_error`\r | |
247 | //! * `max_level_warn`\r | |
248 | //! * `max_level_info`\r | |
249 | //! * `max_level_debug`\r | |
250 | //! * `max_level_trace`\r | |
251 | //! * `release_max_level_off`\r | |
252 | //! * `release_max_level_error`\r | |
253 | //! * `release_max_level_warn`\r | |
254 | //! * `release_max_level_info`\r | |
255 | //! * `release_max_level_debug`\r | |
256 | //! * `release_max_level_trace`\r | |
257 | //!\r | |
258 | //! These features control the value of the `STATIC_MAX_LEVEL` constant. The logging macros check\r | |
259 | //! this value before logging a message. By default, no levels are disabled.\r | |
260 | //!\r | |
261 | //! Libraries should avoid using the max level features because they're global and can't be changed\r | |
262 | //! once they're set.\r | |
263 | //!\r | |
264 | //! For example, a crate can disable trace level logs in debug builds and trace, debug, and info\r | |
265 | //! level logs in release builds with the following configuration:\r | |
266 | //!\r | |
267 | //! ```toml\r | |
268 | //! [dependencies]\r | |
269 | //! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] }\r | |
270 | //! ```\r | |
271 | //! # Crate Feature Flags\r | |
272 | //!\r | |
273 | //! The following crate feature flags are available in addition to the filters. They are\r | |
274 | //! configured in your `Cargo.toml`.\r | |
275 | //!\r | |
276 | //! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and\r | |
277 | //! `set_boxed_logger` functionality.\r | |
278 | //! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`.\r | |
279 | //!\r | |
280 | //! ```toml\r | |
281 | //! [dependencies]\r | |
282 | //! log = { version = "0.4", features = ["std", "serde"] }\r | |
283 | //! ```\r | |
284 | //!\r | |
285 | //! # Version compatibility\r | |
286 | //!\r | |
287 | //! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages\r | |
288 | //! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log\r | |
289 | //! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the\r | |
290 | //! module path and file name information associated with the message will unfortunately be lost.\r | |
291 | //!\r | |
292 | //! [`Log`]: trait.Log.html\r | |
293 | //! [level_link]: enum.Level.html\r | |
294 | //! [filter_link]: enum.LevelFilter.html\r | |
295 | //! [`set_logger`]: fn.set_logger.html\r | |
296 | //! [`set_max_level`]: fn.set_max_level.html\r | |
297 | //! [`try_set_logger_raw`]: fn.try_set_logger_raw.html\r | |
298 | //! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html\r | |
299 | //! [env_logger]: https://docs.rs/env_logger/*/env_logger/\r | |
300 | //! [simple_logger]: https://github.com/borntyping/rust-simple_logger\r | |
301 | //! [simplelog]: https://github.com/drakulix/simplelog.rs\r | |
302 | //! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/\r | |
303 | //! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/\r | |
304 | //! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/\r | |
305 | //! [syslog]: https://docs.rs/syslog/*/syslog/\r | |
306 | //! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/\r | |
307 | //! [log4rs]: https://docs.rs/log4rs/*/log4rs/\r | |
308 | //! [fern]: https://docs.rs/fern/*/fern/\r | |
923072b8 FG |
309 | //! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/\r |
310 | //! [android_log]: https://docs.rs/android_log/*/android_log/\r | |
311 | //! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/\r | |
312 | //! [console_log]: https://docs.rs/console_log/*/console_log/\r | |
3dfed10e XL |
313 | \r |
314 | #![doc(\r | |
315 | html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",\r | |
316 | html_favicon_url = "https://www.rust-lang.org/favicon.ico",\r | |
923072b8 | 317 | html_root_url = "https://docs.rs/log/0.4.17"\r |
3dfed10e XL |
318 | )]\r |
319 | #![warn(missing_docs)]\r | |
04454e1e | 320 | #![deny(missing_debug_implementations, unconditional_recursion)]\r |
3dfed10e XL |
321 | #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]\r |
322 | // When compiled for the rustc compiler itself we want to make sure that this is\r | |
323 | // an unstable crate\r | |
324 | #![cfg_attr(rustbuild, feature(staged_api, rustc_private))]\r | |
325 | #![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))]\r | |
326 | \r | |
327 | #[cfg(all(not(feature = "std"), not(test)))]\r | |
328 | extern crate core as std;\r | |
329 | \r | |
330 | #[macro_use]\r | |
331 | extern crate cfg_if;\r | |
332 | \r | |
333 | use std::cmp;\r | |
334 | #[cfg(feature = "std")]\r | |
335 | use std::error;\r | |
336 | use std::fmt;\r | |
337 | use std::mem;\r | |
338 | use std::str::FromStr;\r | |
3dfed10e XL |
339 | \r |
340 | #[macro_use]\r | |
341 | mod macros;\r | |
342 | mod serde;\r | |
343 | \r | |
344 | #[cfg(feature = "kv_unstable")]\r | |
345 | pub mod kv;\r | |
346 | \r | |
5869c6ff XL |
347 | #[cfg(has_atomics)]\r |
348 | use std::sync::atomic::{AtomicUsize, Ordering};\r | |
349 | \r | |
350 | #[cfg(not(has_atomics))]\r | |
351 | use std::cell::Cell;\r | |
352 | #[cfg(not(has_atomics))]\r | |
353 | use std::sync::atomic::Ordering;\r | |
354 | \r | |
355 | #[cfg(not(has_atomics))]\r | |
356 | struct AtomicUsize {\r | |
357 | v: Cell<usize>,\r | |
358 | }\r | |
359 | \r | |
360 | #[cfg(not(has_atomics))]\r | |
361 | impl AtomicUsize {\r | |
362 | const fn new(v: usize) -> AtomicUsize {\r | |
363 | AtomicUsize { v: Cell::new(v) }\r | |
364 | }\r | |
365 | \r | |
366 | fn load(&self, _order: Ordering) -> usize {\r | |
367 | self.v.get()\r | |
368 | }\r | |
369 | \r | |
370 | fn store(&self, val: usize, _order: Ordering) {\r | |
371 | self.v.set(val)\r | |
372 | }\r | |
373 | \r | |
374 | #[cfg(atomic_cas)]\r | |
375 | fn compare_exchange(\r | |
376 | &self,\r | |
377 | current: usize,\r | |
378 | new: usize,\r | |
379 | _success: Ordering,\r | |
380 | _failure: Ordering,\r | |
381 | ) -> Result<usize, usize> {\r | |
382 | let prev = self.v.get();\r | |
383 | if current == prev {\r | |
384 | self.v.set(new);\r | |
385 | }\r | |
386 | Ok(prev)\r | |
387 | }\r | |
388 | }\r | |
389 | \r | |
390 | // Any platform without atomics is unlikely to have multiple cores, so\r | |
391 | // writing via Cell will not be a race condition.\r | |
392 | #[cfg(not(has_atomics))]\r | |
393 | unsafe impl Sync for AtomicUsize {}\r | |
394 | \r | |
3dfed10e XL |
395 | // The LOGGER static holds a pointer to the global logger. It is protected by\r |
396 | // the STATE static which determines whether LOGGER has been initialized yet.\r | |
397 | static mut LOGGER: &dyn Log = &NopLogger;\r | |
398 | \r | |
399 | static STATE: AtomicUsize = AtomicUsize::new(0);\r | |
400 | \r | |
401 | // There are three different states that we care about: the logger's\r | |
402 | // uninitialized, the logger's initializing (set_logger's been called but\r | |
403 | // LOGGER hasn't actually been set yet), or the logger's active.\r | |
404 | const UNINITIALIZED: usize = 0;\r | |
405 | const INITIALIZING: usize = 1;\r | |
406 | const INITIALIZED: usize = 2;\r | |
407 | \r | |
408 | static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0);\r | |
409 | \r | |
410 | static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];\r | |
411 | \r | |
412 | static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \\r | |
413 | was already initialized";\r | |
414 | static LEVEL_PARSE_ERROR: &str =\r | |
415 | "attempted to convert a string that doesn't match an existing log level";\r | |
416 | \r | |
417 | /// An enum representing the available verbosity levels of the logger.\r | |
418 | ///\r | |
419 | /// Typical usage includes: checking if a certain `Level` is enabled with\r | |
420 | /// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of\r | |
421 | /// [`log!`](macro.log.html), and comparing a `Level` directly to a\r | |
422 | /// [`LevelFilter`](enum.LevelFilter.html).\r | |
423 | #[repr(usize)]\r | |
424 | #[derive(Copy, Eq, Debug, Hash)]\r | |
425 | pub enum Level {\r | |
426 | /// The "error" level.\r | |
427 | ///\r | |
428 | /// Designates very serious errors.\r | |
429 | // This way these line up with the discriminants for LevelFilter below\r | |
430 | // This works because Rust treats field-less enums the same way as C does:\r | |
431 | // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations\r | |
432 | Error = 1,\r | |
433 | /// The "warn" level.\r | |
434 | ///\r | |
435 | /// Designates hazardous situations.\r | |
436 | Warn,\r | |
437 | /// The "info" level.\r | |
438 | ///\r | |
439 | /// Designates useful information.\r | |
440 | Info,\r | |
441 | /// The "debug" level.\r | |
442 | ///\r | |
443 | /// Designates lower priority information.\r | |
444 | Debug,\r | |
445 | /// The "trace" level.\r | |
446 | ///\r | |
447 | /// Designates very low priority, often extremely verbose, information.\r | |
448 | Trace,\r | |
449 | }\r | |
450 | \r | |
451 | impl Clone for Level {\r | |
452 | #[inline]\r | |
453 | fn clone(&self) -> Level {\r | |
454 | *self\r | |
455 | }\r | |
456 | }\r | |
457 | \r | |
458 | impl PartialEq for Level {\r | |
459 | #[inline]\r | |
460 | fn eq(&self, other: &Level) -> bool {\r | |
461 | *self as usize == *other as usize\r | |
462 | }\r | |
463 | }\r | |
464 | \r | |
465 | impl PartialEq<LevelFilter> for Level {\r | |
466 | #[inline]\r | |
467 | fn eq(&self, other: &LevelFilter) -> bool {\r | |
468 | *self as usize == *other as usize\r | |
469 | }\r | |
470 | }\r | |
471 | \r | |
472 | impl PartialOrd for Level {\r | |
473 | #[inline]\r | |
474 | fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {\r | |
475 | Some(self.cmp(other))\r | |
476 | }\r | |
477 | \r | |
478 | #[inline]\r | |
479 | fn lt(&self, other: &Level) -> bool {\r | |
480 | (*self as usize) < *other as usize\r | |
481 | }\r | |
482 | \r | |
483 | #[inline]\r | |
484 | fn le(&self, other: &Level) -> bool {\r | |
485 | *self as usize <= *other as usize\r | |
486 | }\r | |
487 | \r | |
488 | #[inline]\r | |
489 | fn gt(&self, other: &Level) -> bool {\r | |
490 | *self as usize > *other as usize\r | |
491 | }\r | |
492 | \r | |
493 | #[inline]\r | |
494 | fn ge(&self, other: &Level) -> bool {\r | |
495 | *self as usize >= *other as usize\r | |
496 | }\r | |
497 | }\r | |
498 | \r | |
499 | impl PartialOrd<LevelFilter> for Level {\r | |
500 | #[inline]\r | |
501 | fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {\r | |
502 | Some((*self as usize).cmp(&(*other as usize)))\r | |
503 | }\r | |
504 | \r | |
505 | #[inline]\r | |
506 | fn lt(&self, other: &LevelFilter) -> bool {\r | |
507 | (*self as usize) < *other as usize\r | |
508 | }\r | |
509 | \r | |
510 | #[inline]\r | |
511 | fn le(&self, other: &LevelFilter) -> bool {\r | |
512 | *self as usize <= *other as usize\r | |
513 | }\r | |
514 | \r | |
515 | #[inline]\r | |
516 | fn gt(&self, other: &LevelFilter) -> bool {\r | |
517 | *self as usize > *other as usize\r | |
518 | }\r | |
519 | \r | |
520 | #[inline]\r | |
521 | fn ge(&self, other: &LevelFilter) -> bool {\r | |
522 | *self as usize >= *other as usize\r | |
523 | }\r | |
524 | }\r | |
525 | \r | |
526 | impl Ord for Level {\r | |
527 | #[inline]\r | |
528 | fn cmp(&self, other: &Level) -> cmp::Ordering {\r | |
529 | (*self as usize).cmp(&(*other as usize))\r | |
530 | }\r | |
531 | }\r | |
532 | \r | |
533 | fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {\r | |
534 | match t {\r | |
535 | Some(t) => Ok(t),\r | |
536 | None => Err(e),\r | |
537 | }\r | |
538 | }\r | |
539 | \r | |
540 | // Reimplemented here because std::ascii is not available in libcore\r | |
541 | fn eq_ignore_ascii_case(a: &str, b: &str) -> bool {\r | |
542 | fn to_ascii_uppercase(c: u8) -> u8 {\r | |
543 | if c >= b'a' && c <= b'z' {\r | |
544 | c - b'a' + b'A'\r | |
545 | } else {\r | |
546 | c\r | |
547 | }\r | |
548 | }\r | |
549 | \r | |
550 | if a.len() == b.len() {\r | |
551 | a.bytes()\r | |
552 | .zip(b.bytes())\r | |
553 | .all(|(a, b)| to_ascii_uppercase(a) == to_ascii_uppercase(b))\r | |
554 | } else {\r | |
555 | false\r | |
556 | }\r | |
557 | }\r | |
558 | \r | |
559 | impl FromStr for Level {\r | |
560 | type Err = ParseLevelError;\r | |
561 | fn from_str(level: &str) -> Result<Level, Self::Err> {\r | |
562 | ok_or(\r | |
563 | LOG_LEVEL_NAMES\r | |
564 | .iter()\r | |
565 | .position(|&name| eq_ignore_ascii_case(name, level))\r | |
566 | .into_iter()\r | |
567 | .filter(|&idx| idx != 0)\r | |
568 | .map(|idx| Level::from_usize(idx).unwrap())\r | |
569 | .next(),\r | |
570 | ParseLevelError(()),\r | |
571 | )\r | |
572 | }\r | |
573 | }\r | |
574 | \r | |
575 | impl fmt::Display for Level {\r | |
576 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r | |
5869c6ff | 577 | fmt.pad(self.as_str())\r |
3dfed10e XL |
578 | }\r |
579 | }\r | |
580 | \r | |
581 | impl Level {\r | |
582 | fn from_usize(u: usize) -> Option<Level> {\r | |
583 | match u {\r | |
584 | 1 => Some(Level::Error),\r | |
585 | 2 => Some(Level::Warn),\r | |
586 | 3 => Some(Level::Info),\r | |
587 | 4 => Some(Level::Debug),\r | |
588 | 5 => Some(Level::Trace),\r | |
589 | _ => None,\r | |
590 | }\r | |
591 | }\r | |
592 | \r | |
593 | /// Returns the most verbose logging level.\r | |
594 | #[inline]\r | |
595 | pub fn max() -> Level {\r | |
596 | Level::Trace\r | |
597 | }\r | |
598 | \r | |
599 | /// Converts the `Level` to the equivalent `LevelFilter`.\r | |
600 | #[inline]\r | |
601 | pub fn to_level_filter(&self) -> LevelFilter {\r | |
602 | LevelFilter::from_usize(*self as usize).unwrap()\r | |
603 | }\r | |
5869c6ff XL |
604 | \r |
605 | /// Returns the string representation of the `Level`.\r | |
606 | ///\r | |
607 | /// This returns the same string as the `fmt::Display` implementation.\r | |
608 | pub fn as_str(&self) -> &'static str {\r | |
609 | LOG_LEVEL_NAMES[*self as usize]\r | |
610 | }\r | |
04454e1e FG |
611 | \r |
612 | /// Iterate through all supported logging levels.\r | |
613 | ///\r | |
614 | /// The order of iteration is from more severe to less severe log messages.\r | |
615 | ///\r | |
616 | /// # Examples\r | |
617 | ///\r | |
618 | /// ```\r | |
619 | /// use log::Level;\r | |
620 | ///\r | |
621 | /// let mut levels = Level::iter();\r | |
622 | ///\r | |
623 | /// assert_eq!(Some(Level::Error), levels.next());\r | |
624 | /// assert_eq!(Some(Level::Trace), levels.last());\r | |
625 | /// ```\r | |
626 | pub fn iter() -> impl Iterator<Item = Self> {\r | |
627 | (1..6).map(|i| Self::from_usize(i).unwrap())\r | |
628 | }\r | |
3dfed10e XL |
629 | }\r |
630 | \r | |
631 | /// An enum representing the available verbosity level filters of the logger.\r | |
632 | ///\r | |
633 | /// A `LevelFilter` may be compared directly to a [`Level`]. Use this type\r | |
634 | /// to get and set the maximum log level with [`max_level()`] and [`set_max_level`].\r | |
635 | ///\r | |
636 | /// [`Level`]: enum.Level.html\r | |
637 | /// [`max_level()`]: fn.max_level.html\r | |
638 | /// [`set_max_level`]: fn.set_max_level.html\r | |
639 | #[repr(usize)]\r | |
640 | #[derive(Copy, Eq, Debug, Hash)]\r | |
641 | pub enum LevelFilter {\r | |
642 | /// A level lower than all log levels.\r | |
643 | Off,\r | |
644 | /// Corresponds to the `Error` log level.\r | |
645 | Error,\r | |
646 | /// Corresponds to the `Warn` log level.\r | |
647 | Warn,\r | |
648 | /// Corresponds to the `Info` log level.\r | |
649 | Info,\r | |
650 | /// Corresponds to the `Debug` log level.\r | |
651 | Debug,\r | |
652 | /// Corresponds to the `Trace` log level.\r | |
653 | Trace,\r | |
654 | }\r | |
655 | \r | |
656 | // Deriving generates terrible impls of these traits\r | |
657 | \r | |
658 | impl Clone for LevelFilter {\r | |
659 | #[inline]\r | |
660 | fn clone(&self) -> LevelFilter {\r | |
661 | *self\r | |
662 | }\r | |
663 | }\r | |
664 | \r | |
665 | impl PartialEq for LevelFilter {\r | |
666 | #[inline]\r | |
667 | fn eq(&self, other: &LevelFilter) -> bool {\r | |
668 | *self as usize == *other as usize\r | |
669 | }\r | |
670 | }\r | |
671 | \r | |
672 | impl PartialEq<Level> for LevelFilter {\r | |
673 | #[inline]\r | |
674 | fn eq(&self, other: &Level) -> bool {\r | |
675 | other.eq(self)\r | |
676 | }\r | |
677 | }\r | |
678 | \r | |
679 | impl PartialOrd for LevelFilter {\r | |
680 | #[inline]\r | |
681 | fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {\r | |
682 | Some(self.cmp(other))\r | |
683 | }\r | |
684 | \r | |
685 | #[inline]\r | |
686 | fn lt(&self, other: &LevelFilter) -> bool {\r | |
687 | (*self as usize) < *other as usize\r | |
688 | }\r | |
689 | \r | |
690 | #[inline]\r | |
691 | fn le(&self, other: &LevelFilter) -> bool {\r | |
692 | *self as usize <= *other as usize\r | |
693 | }\r | |
694 | \r | |
695 | #[inline]\r | |
696 | fn gt(&self, other: &LevelFilter) -> bool {\r | |
697 | *self as usize > *other as usize\r | |
698 | }\r | |
699 | \r | |
700 | #[inline]\r | |
701 | fn ge(&self, other: &LevelFilter) -> bool {\r | |
702 | *self as usize >= *other as usize\r | |
703 | }\r | |
704 | }\r | |
705 | \r | |
706 | impl PartialOrd<Level> for LevelFilter {\r | |
707 | #[inline]\r | |
708 | fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {\r | |
709 | Some((*self as usize).cmp(&(*other as usize)))\r | |
710 | }\r | |
711 | \r | |
712 | #[inline]\r | |
713 | fn lt(&self, other: &Level) -> bool {\r | |
714 | (*self as usize) < *other as usize\r | |
715 | }\r | |
716 | \r | |
717 | #[inline]\r | |
718 | fn le(&self, other: &Level) -> bool {\r | |
719 | *self as usize <= *other as usize\r | |
720 | }\r | |
721 | \r | |
722 | #[inline]\r | |
723 | fn gt(&self, other: &Level) -> bool {\r | |
724 | *self as usize > *other as usize\r | |
725 | }\r | |
726 | \r | |
727 | #[inline]\r | |
728 | fn ge(&self, other: &Level) -> bool {\r | |
729 | *self as usize >= *other as usize\r | |
730 | }\r | |
731 | }\r | |
732 | \r | |
733 | impl Ord for LevelFilter {\r | |
734 | #[inline]\r | |
735 | fn cmp(&self, other: &LevelFilter) -> cmp::Ordering {\r | |
736 | (*self as usize).cmp(&(*other as usize))\r | |
737 | }\r | |
738 | }\r | |
739 | \r | |
740 | impl FromStr for LevelFilter {\r | |
741 | type Err = ParseLevelError;\r | |
742 | fn from_str(level: &str) -> Result<LevelFilter, Self::Err> {\r | |
743 | ok_or(\r | |
744 | LOG_LEVEL_NAMES\r | |
745 | .iter()\r | |
746 | .position(|&name| eq_ignore_ascii_case(name, level))\r | |
747 | .map(|p| LevelFilter::from_usize(p).unwrap()),\r | |
748 | ParseLevelError(()),\r | |
749 | )\r | |
750 | }\r | |
751 | }\r | |
752 | \r | |
753 | impl fmt::Display for LevelFilter {\r | |
754 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r | |
5869c6ff | 755 | fmt.pad(self.as_str())\r |
3dfed10e XL |
756 | }\r |
757 | }\r | |
758 | \r | |
759 | impl LevelFilter {\r | |
760 | fn from_usize(u: usize) -> Option<LevelFilter> {\r | |
761 | match u {\r | |
762 | 0 => Some(LevelFilter::Off),\r | |
763 | 1 => Some(LevelFilter::Error),\r | |
764 | 2 => Some(LevelFilter::Warn),\r | |
765 | 3 => Some(LevelFilter::Info),\r | |
766 | 4 => Some(LevelFilter::Debug),\r | |
767 | 5 => Some(LevelFilter::Trace),\r | |
768 | _ => None,\r | |
769 | }\r | |
770 | }\r | |
04454e1e | 771 | \r |
3dfed10e XL |
772 | /// Returns the most verbose logging level filter.\r |
773 | #[inline]\r | |
774 | pub fn max() -> LevelFilter {\r | |
775 | LevelFilter::Trace\r | |
776 | }\r | |
777 | \r | |
778 | /// Converts `self` to the equivalent `Level`.\r | |
779 | ///\r | |
780 | /// Returns `None` if `self` is `LevelFilter::Off`.\r | |
781 | #[inline]\r | |
782 | pub fn to_level(&self) -> Option<Level> {\r | |
783 | Level::from_usize(*self as usize)\r | |
784 | }\r | |
5869c6ff XL |
785 | \r |
786 | /// Returns the string representation of the `LevelFilter`.\r | |
787 | ///\r | |
788 | /// This returns the same string as the `fmt::Display` implementation.\r | |
789 | pub fn as_str(&self) -> &'static str {\r | |
790 | LOG_LEVEL_NAMES[*self as usize]\r | |
791 | }\r | |
04454e1e FG |
792 | \r |
793 | /// Iterate through all supported filtering levels.\r | |
794 | ///\r | |
795 | /// The order of iteration is from less to more verbose filtering.\r | |
796 | ///\r | |
797 | /// # Examples\r | |
798 | ///\r | |
799 | /// ```\r | |
800 | /// use log::LevelFilter;\r | |
801 | ///\r | |
802 | /// let mut levels = LevelFilter::iter();\r | |
803 | ///\r | |
804 | /// assert_eq!(Some(LevelFilter::Off), levels.next());\r | |
805 | /// assert_eq!(Some(LevelFilter::Trace), levels.last());\r | |
806 | /// ```\r | |
807 | pub fn iter() -> impl Iterator<Item = Self> {\r | |
808 | (0..6).map(|i| Self::from_usize(i).unwrap())\r | |
809 | }\r | |
3dfed10e XL |
810 | }\r |
811 | \r | |
812 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]\r | |
813 | enum MaybeStaticStr<'a> {\r | |
814 | Static(&'static str),\r | |
815 | Borrowed(&'a str),\r | |
816 | }\r | |
817 | \r | |
818 | impl<'a> MaybeStaticStr<'a> {\r | |
819 | #[inline]\r | |
820 | fn get(&self) -> &'a str {\r | |
821 | match *self {\r | |
822 | MaybeStaticStr::Static(s) => s,\r | |
823 | MaybeStaticStr::Borrowed(s) => s,\r | |
824 | }\r | |
825 | }\r | |
826 | }\r | |
827 | \r | |
828 | /// The "payload" of a log message.\r | |
829 | ///\r | |
830 | /// # Use\r | |
831 | ///\r | |
832 | /// `Record` structures are passed as parameters to the [`log`][method.log]\r | |
833 | /// method of the [`Log`] trait. Logger implementors manipulate these\r | |
834 | /// structures in order to display log messages. `Record`s are automatically\r | |
835 | /// created by the [`log!`] macro and so are not seen by log users.\r | |
836 | ///\r | |
837 | /// Note that the [`level()`] and [`target()`] accessors are equivalent to\r | |
838 | /// `self.metadata().level()` and `self.metadata().target()` respectively.\r | |
839 | /// These methods are provided as a convenience for users of this structure.\r | |
840 | ///\r | |
841 | /// # Example\r | |
842 | ///\r | |
843 | /// The following example shows a simple logger that displays the level,\r | |
844 | /// module path, and message of any `Record` that is passed to it.\r | |
845 | ///\r | |
846 | /// ```edition2018\r | |
847 | /// struct SimpleLogger;\r | |
848 | ///\r | |
849 | /// impl log::Log for SimpleLogger {\r | |
850 | /// fn enabled(&self, metadata: &log::Metadata) -> bool {\r | |
851 | /// true\r | |
852 | /// }\r | |
853 | ///\r | |
854 | /// fn log(&self, record: &log::Record) {\r | |
855 | /// if !self.enabled(record.metadata()) {\r | |
856 | /// return;\r | |
857 | /// }\r | |
858 | ///\r | |
859 | /// println!("{}:{} -- {}",\r | |
860 | /// record.level(),\r | |
861 | /// record.target(),\r | |
862 | /// record.args());\r | |
863 | /// }\r | |
864 | /// fn flush(&self) {}\r | |
865 | /// }\r | |
866 | /// ```\r | |
867 | ///\r | |
868 | /// [method.log]: trait.Log.html#tymethod.log\r | |
869 | /// [`Log`]: trait.Log.html\r | |
870 | /// [`log!`]: macro.log.html\r | |
871 | /// [`level()`]: struct.Record.html#method.level\r | |
872 | /// [`target()`]: struct.Record.html#method.target\r | |
873 | #[derive(Clone, Debug)]\r | |
874 | pub struct Record<'a> {\r | |
875 | metadata: Metadata<'a>,\r | |
876 | args: fmt::Arguments<'a>,\r | |
877 | module_path: Option<MaybeStaticStr<'a>>,\r | |
878 | file: Option<MaybeStaticStr<'a>>,\r | |
879 | line: Option<u32>,\r | |
880 | #[cfg(feature = "kv_unstable")]\r | |
881 | key_values: KeyValues<'a>,\r | |
882 | }\r | |
883 | \r | |
884 | // This wrapper type is only needed so we can\r | |
885 | // `#[derive(Debug)]` on `Record`. It also\r | |
886 | // provides a useful `Debug` implementation for\r | |
887 | // the underlying `Source`.\r | |
888 | #[cfg(feature = "kv_unstable")]\r | |
889 | #[derive(Clone)]\r | |
890 | struct KeyValues<'a>(&'a dyn kv::Source);\r | |
891 | \r | |
892 | #[cfg(feature = "kv_unstable")]\r | |
893 | impl<'a> fmt::Debug for KeyValues<'a> {\r | |
894 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r | |
895 | let mut visitor = f.debug_map();\r | |
896 | self.0.visit(&mut visitor).map_err(|_| fmt::Error)?;\r | |
897 | visitor.finish()\r | |
898 | }\r | |
899 | }\r | |
900 | \r | |
901 | impl<'a> Record<'a> {\r | |
902 | /// Returns a new builder.\r | |
903 | #[inline]\r | |
904 | pub fn builder() -> RecordBuilder<'a> {\r | |
905 | RecordBuilder::new()\r | |
906 | }\r | |
907 | \r | |
908 | /// The message body.\r | |
909 | #[inline]\r | |
910 | pub fn args(&self) -> &fmt::Arguments<'a> {\r | |
911 | &self.args\r | |
912 | }\r | |
913 | \r | |
914 | /// Metadata about the log directive.\r | |
915 | #[inline]\r | |
916 | pub fn metadata(&self) -> &Metadata<'a> {\r | |
917 | &self.metadata\r | |
918 | }\r | |
919 | \r | |
920 | /// The verbosity level of the message.\r | |
921 | #[inline]\r | |
922 | pub fn level(&self) -> Level {\r | |
923 | self.metadata.level()\r | |
924 | }\r | |
925 | \r | |
926 | /// The name of the target of the directive.\r | |
927 | #[inline]\r | |
928 | pub fn target(&self) -> &'a str {\r | |
929 | self.metadata.target()\r | |
930 | }\r | |
931 | \r | |
932 | /// The module path of the message.\r | |
933 | #[inline]\r | |
934 | pub fn module_path(&self) -> Option<&'a str> {\r | |
935 | self.module_path.map(|s| s.get())\r | |
936 | }\r | |
937 | \r | |
938 | /// The module path of the message, if it is a `'static` string.\r | |
939 | #[inline]\r | |
940 | pub fn module_path_static(&self) -> Option<&'static str> {\r | |
941 | match self.module_path {\r | |
942 | Some(MaybeStaticStr::Static(s)) => Some(s),\r | |
943 | _ => None,\r | |
944 | }\r | |
945 | }\r | |
946 | \r | |
947 | /// The source file containing the message.\r | |
948 | #[inline]\r | |
949 | pub fn file(&self) -> Option<&'a str> {\r | |
950 | self.file.map(|s| s.get())\r | |
951 | }\r | |
952 | \r | |
953 | /// The module path of the message, if it is a `'static` string.\r | |
954 | #[inline]\r | |
955 | pub fn file_static(&self) -> Option<&'static str> {\r | |
956 | match self.file {\r | |
957 | Some(MaybeStaticStr::Static(s)) => Some(s),\r | |
958 | _ => None,\r | |
959 | }\r | |
960 | }\r | |
961 | \r | |
962 | /// The line containing the message.\r | |
963 | #[inline]\r | |
964 | pub fn line(&self) -> Option<u32> {\r | |
965 | self.line\r | |
966 | }\r | |
967 | \r | |
04454e1e | 968 | /// The structured key-value pairs associated with the message.\r |
3dfed10e XL |
969 | #[cfg(feature = "kv_unstable")]\r |
970 | #[inline]\r | |
971 | pub fn key_values(&self) -> &dyn kv::Source {\r | |
972 | self.key_values.0\r | |
973 | }\r | |
974 | \r | |
975 | /// Create a new [`RecordBuilder`](struct.RecordBuilder.html) based on this record.\r | |
976 | #[cfg(feature = "kv_unstable")]\r | |
977 | #[inline]\r | |
978 | pub fn to_builder(&self) -> RecordBuilder {\r | |
979 | RecordBuilder {\r | |
980 | record: Record {\r | |
981 | metadata: Metadata {\r | |
982 | level: self.metadata.level,\r | |
983 | target: self.metadata.target,\r | |
984 | },\r | |
985 | args: self.args,\r | |
986 | module_path: self.module_path,\r | |
987 | file: self.file,\r | |
988 | line: self.line,\r | |
989 | key_values: self.key_values.clone(),\r | |
990 | },\r | |
991 | }\r | |
992 | }\r | |
993 | }\r | |
994 | \r | |
995 | /// Builder for [`Record`](struct.Record.html).\r | |
996 | ///\r | |
997 | /// Typically should only be used by log library creators or for testing and "shim loggers".\r | |
998 | /// The `RecordBuilder` can set the different parameters of `Record` object, and returns\r | |
999 | /// the created object when `build` is called.\r | |
1000 | ///\r | |
1001 | /// # Examples\r | |
1002 | ///\r | |
3dfed10e XL |
1003 | /// ```edition2018\r |
1004 | /// use log::{Level, Record};\r | |
1005 | ///\r | |
1006 | /// let record = Record::builder()\r | |
1007 | /// .args(format_args!("Error!"))\r | |
1008 | /// .level(Level::Error)\r | |
1009 | /// .target("myApp")\r | |
1010 | /// .file(Some("server.rs"))\r | |
1011 | /// .line(Some(144))\r | |
1012 | /// .module_path(Some("server"))\r | |
1013 | /// .build();\r | |
1014 | /// ```\r | |
1015 | ///\r | |
1016 | /// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html):\r | |
1017 | ///\r | |
1018 | /// ```edition2018\r | |
1019 | /// use log::{Record, Level, MetadataBuilder};\r | |
1020 | ///\r | |
1021 | /// let error_metadata = MetadataBuilder::new()\r | |
1022 | /// .target("myApp")\r | |
1023 | /// .level(Level::Error)\r | |
1024 | /// .build();\r | |
1025 | ///\r | |
1026 | /// let record = Record::builder()\r | |
1027 | /// .metadata(error_metadata)\r | |
1028 | /// .args(format_args!("Error!"))\r | |
1029 | /// .line(Some(433))\r | |
1030 | /// .file(Some("app.rs"))\r | |
1031 | /// .module_path(Some("server"))\r | |
1032 | /// .build();\r | |
1033 | /// ```\r | |
1034 | #[derive(Debug)]\r | |
1035 | pub struct RecordBuilder<'a> {\r | |
1036 | record: Record<'a>,\r | |
1037 | }\r | |
1038 | \r | |
1039 | impl<'a> RecordBuilder<'a> {\r | |
1040 | /// Construct new `RecordBuilder`.\r | |
1041 | ///\r | |
1042 | /// The default options are:\r | |
1043 | ///\r | |
1044 | /// - `args`: [`format_args!("")`]\r | |
1045 | /// - `metadata`: [`Metadata::builder().build()`]\r | |
1046 | /// - `module_path`: `None`\r | |
1047 | /// - `file`: `None`\r | |
1048 | /// - `line`: `None`\r | |
1049 | ///\r | |
1050 | /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html\r | |
1051 | /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build\r | |
1052 | #[inline]\r | |
1053 | pub fn new() -> RecordBuilder<'a> {\r | |
1054 | RecordBuilder {\r | |
1055 | record: Record {\r | |
1056 | args: format_args!(""),\r | |
1057 | metadata: Metadata::builder().build(),\r | |
1058 | module_path: None,\r | |
1059 | file: None,\r | |
1060 | line: None,\r | |
1061 | #[cfg(feature = "kv_unstable")]\r | |
1062 | key_values: KeyValues(&Option::None::<(kv::Key, kv::Value)>),\r | |
1063 | },\r | |
1064 | }\r | |
1065 | }\r | |
1066 | \r | |
1067 | /// Set [`args`](struct.Record.html#method.args).\r | |
1068 | #[inline]\r | |
1069 | pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> {\r | |
1070 | self.record.args = args;\r | |
1071 | self\r | |
1072 | }\r | |
1073 | \r | |
1074 | /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html).\r | |
1075 | #[inline]\r | |
1076 | pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> {\r | |
1077 | self.record.metadata = metadata;\r | |
1078 | self\r | |
1079 | }\r | |
1080 | \r | |
1081 | /// Set [`Metadata::level`](struct.Metadata.html#method.level).\r | |
1082 | #[inline]\r | |
1083 | pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> {\r | |
1084 | self.record.metadata.level = level;\r | |
1085 | self\r | |
1086 | }\r | |
1087 | \r | |
1088 | /// Set [`Metadata::target`](struct.Metadata.html#method.target)\r | |
1089 | #[inline]\r | |
1090 | pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> {\r | |
1091 | self.record.metadata.target = target;\r | |
1092 | self\r | |
1093 | }\r | |
1094 | \r | |
1095 | /// Set [`module_path`](struct.Record.html#method.module_path)\r | |
1096 | #[inline]\r | |
1097 | pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> {\r | |
1098 | self.record.module_path = path.map(MaybeStaticStr::Borrowed);\r | |
1099 | self\r | |
1100 | }\r | |
1101 | \r | |
1102 | /// Set [`module_path`](struct.Record.html#method.module_path) to a `'static` string\r | |
1103 | #[inline]\r | |
1104 | pub fn module_path_static(&mut self, path: Option<&'static str>) -> &mut RecordBuilder<'a> {\r | |
1105 | self.record.module_path = path.map(MaybeStaticStr::Static);\r | |
1106 | self\r | |
1107 | }\r | |
1108 | \r | |
1109 | /// Set [`file`](struct.Record.html#method.file)\r | |
1110 | #[inline]\r | |
1111 | pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> {\r | |
1112 | self.record.file = file.map(MaybeStaticStr::Borrowed);\r | |
1113 | self\r | |
1114 | }\r | |
1115 | \r | |
1116 | /// Set [`file`](struct.Record.html#method.file) to a `'static` string.\r | |
1117 | #[inline]\r | |
1118 | pub fn file_static(&mut self, file: Option<&'static str>) -> &mut RecordBuilder<'a> {\r | |
1119 | self.record.file = file.map(MaybeStaticStr::Static);\r | |
1120 | self\r | |
1121 | }\r | |
1122 | \r | |
1123 | /// Set [`line`](struct.Record.html#method.line)\r | |
1124 | #[inline]\r | |
1125 | pub fn line(&mut self, line: Option<u32>) -> &mut RecordBuilder<'a> {\r | |
1126 | self.record.line = line;\r | |
1127 | self\r | |
1128 | }\r | |
1129 | \r | |
1130 | /// Set [`key_values`](struct.Record.html#method.key_values)\r | |
1131 | #[cfg(feature = "kv_unstable")]\r | |
1132 | #[inline]\r | |
1133 | pub fn key_values(&mut self, kvs: &'a dyn kv::Source) -> &mut RecordBuilder<'a> {\r | |
1134 | self.record.key_values = KeyValues(kvs);\r | |
1135 | self\r | |
1136 | }\r | |
1137 | \r | |
1138 | /// Invoke the builder and return a `Record`\r | |
1139 | #[inline]\r | |
1140 | pub fn build(&self) -> Record<'a> {\r | |
1141 | self.record.clone()\r | |
1142 | }\r | |
1143 | }\r | |
1144 | \r | |
1145 | /// Metadata about a log message.\r | |
1146 | ///\r | |
1147 | /// # Use\r | |
1148 | ///\r | |
1149 | /// `Metadata` structs are created when users of the library use\r | |
1150 | /// logging macros.\r | |
1151 | ///\r | |
1152 | /// They are consumed by implementations of the `Log` trait in the\r | |
1153 | /// `enabled` method.\r | |
1154 | ///\r | |
1155 | /// `Record`s use `Metadata` to determine the log message's severity\r | |
1156 | /// and target.\r | |
1157 | ///\r | |
1158 | /// Users should use the `log_enabled!` macro in their code to avoid\r | |
1159 | /// constructing expensive log messages.\r | |
1160 | ///\r | |
1161 | /// # Examples\r | |
1162 | ///\r | |
1163 | /// ```edition2018\r | |
1164 | /// use log::{Record, Level, Metadata};\r | |
1165 | ///\r | |
1166 | /// struct MyLogger;\r | |
1167 | ///\r | |
1168 | /// impl log::Log for MyLogger {\r | |
1169 | /// fn enabled(&self, metadata: &Metadata) -> bool {\r | |
1170 | /// metadata.level() <= Level::Info\r | |
1171 | /// }\r | |
1172 | ///\r | |
1173 | /// fn log(&self, record: &Record) {\r | |
1174 | /// if self.enabled(record.metadata()) {\r | |
1175 | /// println!("{} - {}", record.level(), record.args());\r | |
1176 | /// }\r | |
1177 | /// }\r | |
1178 | /// fn flush(&self) {}\r | |
1179 | /// }\r | |
1180 | ///\r | |
1181 | /// # fn main(){}\r | |
1182 | /// ```\r | |
1183 | #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]\r | |
1184 | pub struct Metadata<'a> {\r | |
1185 | level: Level,\r | |
1186 | target: &'a str,\r | |
1187 | }\r | |
1188 | \r | |
1189 | impl<'a> Metadata<'a> {\r | |
1190 | /// Returns a new builder.\r | |
1191 | #[inline]\r | |
1192 | pub fn builder() -> MetadataBuilder<'a> {\r | |
1193 | MetadataBuilder::new()\r | |
1194 | }\r | |
1195 | \r | |
1196 | /// The verbosity level of the message.\r | |
1197 | #[inline]\r | |
1198 | pub fn level(&self) -> Level {\r | |
1199 | self.level\r | |
1200 | }\r | |
1201 | \r | |
1202 | /// The name of the target of the directive.\r | |
1203 | #[inline]\r | |
1204 | pub fn target(&self) -> &'a str {\r | |
1205 | self.target\r | |
1206 | }\r | |
1207 | }\r | |
1208 | \r | |
1209 | /// Builder for [`Metadata`](struct.Metadata.html).\r | |
1210 | ///\r | |
1211 | /// Typically should only be used by log library creators or for testing and "shim loggers".\r | |
1212 | /// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns\r | |
1213 | /// the created object when `build` is called.\r | |
1214 | ///\r | |
1215 | /// # Example\r | |
1216 | ///\r | |
1217 | /// ```edition2018\r | |
1218 | /// let target = "myApp";\r | |
1219 | /// use log::{Level, MetadataBuilder};\r | |
1220 | /// let metadata = MetadataBuilder::new()\r | |
1221 | /// .level(Level::Debug)\r | |
1222 | /// .target(target)\r | |
1223 | /// .build();\r | |
1224 | /// ```\r | |
1225 | #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]\r | |
1226 | pub struct MetadataBuilder<'a> {\r | |
1227 | metadata: Metadata<'a>,\r | |
1228 | }\r | |
1229 | \r | |
1230 | impl<'a> MetadataBuilder<'a> {\r | |
1231 | /// Construct a new `MetadataBuilder`.\r | |
1232 | ///\r | |
1233 | /// The default options are:\r | |
1234 | ///\r | |
1235 | /// - `level`: `Level::Info`\r | |
1236 | /// - `target`: `""`\r | |
1237 | #[inline]\r | |
1238 | pub fn new() -> MetadataBuilder<'a> {\r | |
1239 | MetadataBuilder {\r | |
1240 | metadata: Metadata {\r | |
1241 | level: Level::Info,\r | |
1242 | target: "",\r | |
1243 | },\r | |
1244 | }\r | |
1245 | }\r | |
1246 | \r | |
1247 | /// Setter for [`level`](struct.Metadata.html#method.level).\r | |
1248 | #[inline]\r | |
1249 | pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> {\r | |
1250 | self.metadata.level = arg;\r | |
1251 | self\r | |
1252 | }\r | |
1253 | \r | |
1254 | /// Setter for [`target`](struct.Metadata.html#method.target).\r | |
1255 | #[inline]\r | |
1256 | pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> {\r | |
1257 | self.metadata.target = target;\r | |
1258 | self\r | |
1259 | }\r | |
1260 | \r | |
1261 | /// Returns a `Metadata` object.\r | |
1262 | #[inline]\r | |
1263 | pub fn build(&self) -> Metadata<'a> {\r | |
1264 | self.metadata.clone()\r | |
1265 | }\r | |
1266 | }\r | |
1267 | \r | |
1268 | /// A trait encapsulating the operations required of a logger.\r | |
1269 | pub trait Log: Sync + Send {\r | |
1270 | /// Determines if a log message with the specified metadata would be\r | |
1271 | /// logged.\r | |
1272 | ///\r | |
1273 | /// This is used by the `log_enabled!` macro to allow callers to avoid\r | |
1274 | /// expensive computation of log message arguments if the message would be\r | |
1275 | /// discarded anyway.\r | |
923072b8 FG |
1276 | ///\r |
1277 | /// # For implementors\r | |
1278 | ///\r | |
1279 | /// This method isn't called automatically by the `log!` macros.\r | |
1280 | /// It's up to an implementation of the `Log` trait to call `enabled` in its own\r | |
1281 | /// `log` method implementation to guarantee that filtering is applied.\r | |
3dfed10e XL |
1282 | fn enabled(&self, metadata: &Metadata) -> bool;\r |
1283 | \r | |
1284 | /// Logs the `Record`.\r | |
1285 | ///\r | |
923072b8 FG |
1286 | /// # For implementors\r |
1287 | ///\r | |
3dfed10e XL |
1288 | /// Note that `enabled` is *not* necessarily called before this method.\r |
1289 | /// Implementations of `log` should perform all necessary filtering\r | |
1290 | /// internally.\r | |
1291 | fn log(&self, record: &Record);\r | |
1292 | \r | |
1293 | /// Flushes any buffered records.\r | |
1294 | fn flush(&self);\r | |
1295 | }\r | |
1296 | \r | |
1297 | // Just used as a dummy initial value for LOGGER\r | |
1298 | struct NopLogger;\r | |
1299 | \r | |
1300 | impl Log for NopLogger {\r | |
1301 | fn enabled(&self, _: &Metadata) -> bool {\r | |
1302 | false\r | |
1303 | }\r | |
1304 | \r | |
1305 | fn log(&self, _: &Record) {}\r | |
1306 | fn flush(&self) {}\r | |
1307 | }\r | |
1308 | \r | |
04454e1e FG |
1309 | impl<T> Log for &'_ T\r |
1310 | where\r | |
1311 | T: ?Sized + Log,\r | |
1312 | {\r | |
1313 | fn enabled(&self, metadata: &Metadata) -> bool {\r | |
1314 | (**self).enabled(metadata)\r | |
1315 | }\r | |
1316 | \r | |
1317 | fn log(&self, record: &Record) {\r | |
1318 | (**self).log(record)\r | |
1319 | }\r | |
1320 | fn flush(&self) {\r | |
1321 | (**self).flush()\r | |
1322 | }\r | |
1323 | }\r | |
1324 | \r | |
5869c6ff XL |
1325 | #[cfg(feature = "std")]\r |
1326 | impl<T> Log for std::boxed::Box<T>\r | |
1327 | where\r | |
1328 | T: ?Sized + Log,\r | |
1329 | {\r | |
1330 | fn enabled(&self, metadata: &Metadata) -> bool {\r | |
1331 | self.as_ref().enabled(metadata)\r | |
1332 | }\r | |
1333 | \r | |
1334 | fn log(&self, record: &Record) {\r | |
1335 | self.as_ref().log(record)\r | |
1336 | }\r | |
1337 | fn flush(&self) {\r | |
1338 | self.as_ref().flush()\r | |
1339 | }\r | |
1340 | }\r | |
1341 | \r | |
04454e1e FG |
1342 | #[cfg(feature = "std")]\r |
1343 | impl<T> Log for std::sync::Arc<T>\r | |
1344 | where\r | |
1345 | T: ?Sized + Log,\r | |
1346 | {\r | |
1347 | fn enabled(&self, metadata: &Metadata) -> bool {\r | |
1348 | self.as_ref().enabled(metadata)\r | |
1349 | }\r | |
1350 | \r | |
1351 | fn log(&self, record: &Record) {\r | |
1352 | self.as_ref().log(record)\r | |
1353 | }\r | |
1354 | fn flush(&self) {\r | |
1355 | self.as_ref().flush()\r | |
1356 | }\r | |
1357 | }\r | |
1358 | \r | |
3dfed10e XL |
1359 | /// Sets the global maximum log level.\r |
1360 | ///\r | |
1361 | /// Generally, this should only be called by the active logging implementation.\r | |
04454e1e FG |
1362 | ///\r |
1363 | /// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs.\r | |
3dfed10e XL |
1364 | #[inline]\r |
1365 | pub fn set_max_level(level: LevelFilter) {\r | |
04454e1e | 1366 | MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed)\r |
3dfed10e XL |
1367 | }\r |
1368 | \r | |
1369 | /// Returns the current maximum log level.\r | |
1370 | ///\r | |
1371 | /// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check\r | |
1372 | /// this value and discard any message logged at a higher level. The maximum\r | |
1373 | /// log level is set by the [`set_max_level`] function.\r | |
1374 | ///\r | |
1375 | /// [`log!`]: macro.log.html\r | |
1376 | /// [`error!`]: macro.error.html\r | |
1377 | /// [`warn!`]: macro.warn.html\r | |
1378 | /// [`info!`]: macro.info.html\r | |
1379 | /// [`debug!`]: macro.debug.html\r | |
1380 | /// [`trace!`]: macro.trace.html\r | |
1381 | /// [`set_max_level`]: fn.set_max_level.html\r | |
1382 | #[inline(always)]\r | |
1383 | pub fn max_level() -> LevelFilter {\r | |
1384 | // Since `LevelFilter` is `repr(usize)`,\r | |
1385 | // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER`\r | |
1386 | // is set to a usize that is a valid discriminant for `LevelFilter`.\r | |
1387 | // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set\r | |
1388 | // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`.\r | |
1389 | // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant.\r | |
1390 | unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) }\r | |
1391 | }\r | |
1392 | \r | |
1393 | /// Sets the global logger to a `Box<Log>`.\r | |
1394 | ///\r | |
1395 | /// This is a simple convenience wrapper over `set_logger`, which takes a\r | |
1396 | /// `Box<Log>` rather than a `&'static Log`. See the documentation for\r | |
1397 | /// [`set_logger`] for more details.\r | |
1398 | ///\r | |
1399 | /// Requires the `std` feature.\r | |
1400 | ///\r | |
1401 | /// # Errors\r | |
1402 | ///\r | |
1403 | /// An error is returned if a logger has already been set.\r | |
1404 | ///\r | |
1405 | /// [`set_logger`]: fn.set_logger.html\r | |
1406 | #[cfg(all(feature = "std", atomic_cas))]\r | |
1407 | pub fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), SetLoggerError> {\r | |
1408 | set_logger_inner(|| Box::leak(logger))\r | |
1409 | }\r | |
1410 | \r | |
1411 | /// Sets the global logger to a `&'static Log`.\r | |
1412 | ///\r | |
1413 | /// This function may only be called once in the lifetime of a program. Any log\r | |
1414 | /// events that occur before the call to `set_logger` completes will be ignored.\r | |
1415 | ///\r | |
1416 | /// This function does not typically need to be called manually. Logger\r | |
1417 | /// implementations should provide an initialization method that installs the\r | |
1418 | /// logger internally.\r | |
1419 | ///\r | |
1420 | /// # Availability\r | |
1421 | ///\r | |
1422 | /// This method is available even when the `std` feature is disabled. However,\r | |
1423 | /// it is currently unavailable on `thumbv6` targets, which lack support for\r | |
1424 | /// some atomic operations which are used by this function. Even on those\r | |
1425 | /// targets, [`set_logger_racy`] will be available.\r | |
1426 | ///\r | |
1427 | /// # Errors\r | |
1428 | ///\r | |
1429 | /// An error is returned if a logger has already been set.\r | |
1430 | ///\r | |
1431 | /// # Examples\r | |
1432 | ///\r | |
1433 | /// ```edition2018\r | |
1434 | /// use log::{error, info, warn, Record, Level, Metadata, LevelFilter};\r | |
1435 | ///\r | |
1436 | /// static MY_LOGGER: MyLogger = MyLogger;\r | |
1437 | ///\r | |
1438 | /// struct MyLogger;\r | |
1439 | ///\r | |
1440 | /// impl log::Log for MyLogger {\r | |
1441 | /// fn enabled(&self, metadata: &Metadata) -> bool {\r | |
1442 | /// metadata.level() <= Level::Info\r | |
1443 | /// }\r | |
1444 | ///\r | |
1445 | /// fn log(&self, record: &Record) {\r | |
1446 | /// if self.enabled(record.metadata()) {\r | |
1447 | /// println!("{} - {}", record.level(), record.args());\r | |
1448 | /// }\r | |
1449 | /// }\r | |
1450 | /// fn flush(&self) {}\r | |
1451 | /// }\r | |
1452 | ///\r | |
1453 | /// # fn main(){\r | |
1454 | /// log::set_logger(&MY_LOGGER).unwrap();\r | |
1455 | /// log::set_max_level(LevelFilter::Info);\r | |
1456 | ///\r | |
1457 | /// info!("hello log");\r | |
1458 | /// warn!("warning");\r | |
1459 | /// error!("oops");\r | |
1460 | /// # }\r | |
1461 | /// ```\r | |
1462 | ///\r | |
1463 | /// [`set_logger_racy`]: fn.set_logger_racy.html\r | |
1464 | #[cfg(atomic_cas)]\r | |
1465 | pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> {\r | |
1466 | set_logger_inner(|| logger)\r | |
1467 | }\r | |
1468 | \r | |
1469 | #[cfg(atomic_cas)]\r | |
1470 | fn set_logger_inner<F>(make_logger: F) -> Result<(), SetLoggerError>\r | |
1471 | where\r | |
1472 | F: FnOnce() -> &'static dyn Log,\r | |
1473 | {\r | |
5869c6ff XL |
1474 | let old_state = match STATE.compare_exchange(\r |
1475 | UNINITIALIZED,\r | |
1476 | INITIALIZING,\r | |
1477 | Ordering::SeqCst,\r | |
1478 | Ordering::SeqCst,\r | |
1479 | ) {\r | |
1480 | Ok(s) | Err(s) => s,\r | |
1481 | };\r | |
1482 | match old_state {\r | |
3dfed10e XL |
1483 | UNINITIALIZED => {\r |
1484 | unsafe {\r | |
1485 | LOGGER = make_logger();\r | |
1486 | }\r | |
1487 | STATE.store(INITIALIZED, Ordering::SeqCst);\r | |
1488 | Ok(())\r | |
1489 | }\r | |
1490 | INITIALIZING => {\r | |
1491 | while STATE.load(Ordering::SeqCst) == INITIALIZING {\r | |
04454e1e FG |
1492 | // TODO: replace with `hint::spin_loop` once MSRV is 1.49.0.\r |
1493 | #[allow(deprecated)]\r | |
3dfed10e XL |
1494 | std::sync::atomic::spin_loop_hint();\r |
1495 | }\r | |
1496 | Err(SetLoggerError(()))\r | |
1497 | }\r | |
1498 | _ => Err(SetLoggerError(())),\r | |
1499 | }\r | |
1500 | }\r | |
1501 | \r | |
1502 | /// A thread-unsafe version of [`set_logger`].\r | |
1503 | ///\r | |
1504 | /// This function is available on all platforms, even those that do not have\r | |
1505 | /// support for atomics that is needed by [`set_logger`].\r | |
1506 | ///\r | |
1507 | /// In almost all cases, [`set_logger`] should be preferred.\r | |
1508 | ///\r | |
1509 | /// # Safety\r | |
1510 | ///\r | |
1511 | /// This function is only safe to call when no other logger initialization\r | |
1512 | /// function is called while this function still executes.\r | |
1513 | ///\r | |
1514 | /// This can be upheld by (for example) making sure that **there are no other\r | |
1515 | /// threads**, and (on embedded) that **interrupts are disabled**.\r | |
1516 | ///\r | |
1517 | /// It is safe to use other logging functions while this function runs\r | |
1518 | /// (including all logging macros).\r | |
1519 | ///\r | |
1520 | /// [`set_logger`]: fn.set_logger.html\r | |
1521 | pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> {\r | |
1522 | match STATE.load(Ordering::SeqCst) {\r | |
1523 | UNINITIALIZED => {\r | |
1524 | LOGGER = logger;\r | |
1525 | STATE.store(INITIALIZED, Ordering::SeqCst);\r | |
1526 | Ok(())\r | |
1527 | }\r | |
1528 | INITIALIZING => {\r | |
1529 | // This is just plain UB, since we were racing another initialization function\r | |
1530 | unreachable!("set_logger_racy must not be used with other initialization functions")\r | |
1531 | }\r | |
1532 | _ => Err(SetLoggerError(())),\r | |
1533 | }\r | |
1534 | }\r | |
1535 | \r | |
1536 | /// The type returned by [`set_logger`] if [`set_logger`] has already been called.\r | |
1537 | ///\r | |
1538 | /// [`set_logger`]: fn.set_logger.html\r | |
1539 | #[allow(missing_copy_implementations)]\r | |
1540 | #[derive(Debug)]\r | |
1541 | pub struct SetLoggerError(());\r | |
1542 | \r | |
1543 | impl fmt::Display for SetLoggerError {\r | |
1544 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r | |
1545 | fmt.write_str(SET_LOGGER_ERROR)\r | |
1546 | }\r | |
1547 | }\r | |
1548 | \r | |
1549 | // The Error trait is not available in libcore\r | |
1550 | #[cfg(feature = "std")]\r | |
1551 | impl error::Error for SetLoggerError {}\r | |
1552 | \r | |
1553 | /// The type returned by [`from_str`] when the string doesn't match any of the log levels.\r | |
1554 | ///\r | |
1555 | /// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str\r | |
1556 | #[allow(missing_copy_implementations)]\r | |
1557 | #[derive(Debug, PartialEq)]\r | |
1558 | pub struct ParseLevelError(());\r | |
1559 | \r | |
1560 | impl fmt::Display for ParseLevelError {\r | |
1561 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r | |
1562 | fmt.write_str(LEVEL_PARSE_ERROR)\r | |
1563 | }\r | |
1564 | }\r | |
1565 | \r | |
1566 | // The Error trait is not available in libcore\r | |
1567 | #[cfg(feature = "std")]\r | |
1568 | impl error::Error for ParseLevelError {}\r | |
1569 | \r | |
1570 | /// Returns a reference to the logger.\r | |
1571 | ///\r | |
1572 | /// If a logger has not been set, a no-op implementation is returned.\r | |
1573 | pub fn logger() -> &'static dyn Log {\r | |
1574 | if STATE.load(Ordering::SeqCst) != INITIALIZED {\r | |
1575 | static NOP: NopLogger = NopLogger;\r | |
1576 | &NOP\r | |
1577 | } else {\r | |
1578 | unsafe { LOGGER }\r | |
1579 | }\r | |
1580 | }\r | |
1581 | \r | |
1582 | // WARNING: this is not part of the crate's public API and is subject to change at any time\r | |
1583 | #[doc(hidden)]\r | |
04454e1e FG |
1584 | #[cfg(not(feature = "kv_unstable"))]\r |
1585 | pub fn __private_api_log(\r | |
1586 | args: fmt::Arguments,\r | |
1587 | level: Level,\r | |
1588 | &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),\r | |
1589 | kvs: Option<&[(&str, &str)]>,\r | |
1590 | ) {\r | |
1591 | if kvs.is_some() {\r | |
1592 | panic!(\r | |
1593 | "key-value support is experimental and must be enabled using the `kv_unstable` feature"\r | |
1594 | )\r | |
1595 | }\r | |
1596 | \r | |
1597 | logger().log(\r | |
1598 | &Record::builder()\r | |
1599 | .args(args)\r | |
1600 | .level(level)\r | |
1601 | .target(target)\r | |
1602 | .module_path_static(Some(module_path))\r | |
1603 | .file_static(Some(file))\r | |
1604 | .line(Some(line))\r | |
1605 | .build(),\r | |
1606 | );\r | |
1607 | }\r | |
1608 | \r | |
1609 | // WARNING: this is not part of the crate's public API and is subject to change at any time\r | |
1610 | #[doc(hidden)]\r | |
1611 | #[cfg(feature = "kv_unstable")]\r | |
3dfed10e XL |
1612 | pub fn __private_api_log(\r |
1613 | args: fmt::Arguments,\r | |
1614 | level: Level,\r | |
1615 | &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),\r | |
04454e1e | 1616 | kvs: Option<&[(&str, &dyn kv::ToValue)]>,\r |
3dfed10e XL |
1617 | ) {\r |
1618 | logger().log(\r | |
1619 | &Record::builder()\r | |
1620 | .args(args)\r | |
1621 | .level(level)\r | |
1622 | .target(target)\r | |
1623 | .module_path_static(Some(module_path))\r | |
1624 | .file_static(Some(file))\r | |
1625 | .line(Some(line))\r | |
04454e1e | 1626 | .key_values(&kvs)\r |
3dfed10e XL |
1627 | .build(),\r |
1628 | );\r | |
1629 | }\r | |
1630 | \r | |
3dfed10e XL |
1631 | // WARNING: this is not part of the crate's public API and is subject to change at any time\r |
1632 | #[doc(hidden)]\r | |
1633 | pub fn __private_api_enabled(level: Level, target: &str) -> bool {\r | |
1634 | logger().enabled(&Metadata::builder().level(level).target(target).build())\r | |
1635 | }\r | |
1636 | \r | |
04454e1e FG |
1637 | // WARNING: this is not part of the crate's public API and is subject to change at any time\r |
1638 | #[doc(hidden)]\r | |
1639 | pub mod __private_api {\r | |
1640 | pub use std::option::Option;\r | |
1641 | }\r | |
1642 | \r | |
3dfed10e XL |
1643 | /// The statically resolved maximum log level.\r |
1644 | ///\r | |
1645 | /// See the crate level documentation for information on how to configure this.\r | |
1646 | ///\r | |
1647 | /// This value is checked by the log macros, but not by the `Log`ger returned by\r | |
1648 | /// the [`logger`] function. Code that manually calls functions on that value\r | |
1649 | /// should compare the level against this value.\r | |
1650 | ///\r | |
1651 | /// [`logger`]: fn.logger.html\r | |
1652 | pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL_INNER;\r | |
1653 | \r | |
1654 | cfg_if! {\r | |
1655 | if #[cfg(all(not(debug_assertions), feature = "release_max_level_off"))] {\r | |
1656 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Off;\r | |
1657 | } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_error"))] {\r | |
1658 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Error;\r | |
1659 | } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_warn"))] {\r | |
1660 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Warn;\r | |
1661 | } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_info"))] {\r | |
1662 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Info;\r | |
1663 | } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_debug"))] {\r | |
1664 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Debug;\r | |
1665 | } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_trace"))] {\r | |
1666 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Trace;\r | |
1667 | } else if #[cfg(feature = "max_level_off")] {\r | |
1668 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Off;\r | |
1669 | } else if #[cfg(feature = "max_level_error")] {\r | |
1670 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Error;\r | |
1671 | } else if #[cfg(feature = "max_level_warn")] {\r | |
1672 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Warn;\r | |
1673 | } else if #[cfg(feature = "max_level_info")] {\r | |
1674 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Info;\r | |
1675 | } else if #[cfg(feature = "max_level_debug")] {\r | |
1676 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Debug;\r | |
1677 | } else {\r | |
1678 | const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Trace;\r | |
1679 | }\r | |
1680 | }\r | |
1681 | \r | |
1682 | #[cfg(test)]\r | |
1683 | mod tests {\r | |
1684 | extern crate std;\r | |
1685 | use super::{Level, LevelFilter, ParseLevelError};\r | |
1686 | use tests::std::string::ToString;\r | |
1687 | \r | |
1688 | #[test]\r | |
1689 | fn test_levelfilter_from_str() {\r | |
1690 | let tests = [\r | |
1691 | ("off", Ok(LevelFilter::Off)),\r | |
1692 | ("error", Ok(LevelFilter::Error)),\r | |
1693 | ("warn", Ok(LevelFilter::Warn)),\r | |
1694 | ("info", Ok(LevelFilter::Info)),\r | |
1695 | ("debug", Ok(LevelFilter::Debug)),\r | |
1696 | ("trace", Ok(LevelFilter::Trace)),\r | |
1697 | ("OFF", Ok(LevelFilter::Off)),\r | |
1698 | ("ERROR", Ok(LevelFilter::Error)),\r | |
1699 | ("WARN", Ok(LevelFilter::Warn)),\r | |
1700 | ("INFO", Ok(LevelFilter::Info)),\r | |
1701 | ("DEBUG", Ok(LevelFilter::Debug)),\r | |
1702 | ("TRACE", Ok(LevelFilter::Trace)),\r | |
1703 | ("asdf", Err(ParseLevelError(()))),\r | |
1704 | ];\r | |
1705 | for &(s, ref expected) in &tests {\r | |
1706 | assert_eq!(expected, &s.parse());\r | |
1707 | }\r | |
1708 | }\r | |
1709 | \r | |
1710 | #[test]\r | |
1711 | fn test_level_from_str() {\r | |
1712 | let tests = [\r | |
1713 | ("OFF", Err(ParseLevelError(()))),\r | |
1714 | ("error", Ok(Level::Error)),\r | |
1715 | ("warn", Ok(Level::Warn)),\r | |
1716 | ("info", Ok(Level::Info)),\r | |
1717 | ("debug", Ok(Level::Debug)),\r | |
1718 | ("trace", Ok(Level::Trace)),\r | |
1719 | ("ERROR", Ok(Level::Error)),\r | |
1720 | ("WARN", Ok(Level::Warn)),\r | |
1721 | ("INFO", Ok(Level::Info)),\r | |
1722 | ("DEBUG", Ok(Level::Debug)),\r | |
1723 | ("TRACE", Ok(Level::Trace)),\r | |
1724 | ("asdf", Err(ParseLevelError(()))),\r | |
1725 | ];\r | |
1726 | for &(s, ref expected) in &tests {\r | |
1727 | assert_eq!(expected, &s.parse());\r | |
1728 | }\r | |
1729 | }\r | |
1730 | \r | |
5869c6ff XL |
1731 | #[test]\r |
1732 | fn test_level_as_str() {\r | |
1733 | let tests = &[\r | |
1734 | (Level::Error, "ERROR"),\r | |
1735 | (Level::Warn, "WARN"),\r | |
1736 | (Level::Info, "INFO"),\r | |
1737 | (Level::Debug, "DEBUG"),\r | |
1738 | (Level::Trace, "TRACE"),\r | |
1739 | ];\r | |
1740 | for (input, expected) in tests {\r | |
1741 | assert_eq!(*expected, input.as_str());\r | |
1742 | }\r | |
1743 | }\r | |
1744 | \r | |
3dfed10e XL |
1745 | #[test]\r |
1746 | fn test_level_show() {\r | |
1747 | assert_eq!("INFO", Level::Info.to_string());\r | |
1748 | assert_eq!("ERROR", Level::Error.to_string());\r | |
1749 | }\r | |
1750 | \r | |
1751 | #[test]\r | |
1752 | fn test_levelfilter_show() {\r | |
1753 | assert_eq!("OFF", LevelFilter::Off.to_string());\r | |
1754 | assert_eq!("ERROR", LevelFilter::Error.to_string());\r | |
1755 | }\r | |
1756 | \r | |
1757 | #[test]\r | |
1758 | fn test_cross_cmp() {\r | |
1759 | assert!(Level::Debug > LevelFilter::Error);\r | |
1760 | assert!(LevelFilter::Warn < Level::Trace);\r | |
1761 | assert!(LevelFilter::Off < Level::Error);\r | |
1762 | }\r | |
1763 | \r | |
1764 | #[test]\r | |
1765 | fn test_cross_eq() {\r | |
1766 | assert!(Level::Error == LevelFilter::Error);\r | |
1767 | assert!(LevelFilter::Off != Level::Error);\r | |
1768 | assert!(Level::Trace == LevelFilter::Trace);\r | |
1769 | }\r | |
1770 | \r | |
1771 | #[test]\r | |
1772 | fn test_to_level() {\r | |
1773 | assert_eq!(Some(Level::Error), LevelFilter::Error.to_level());\r | |
1774 | assert_eq!(None, LevelFilter::Off.to_level());\r | |
1775 | assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level());\r | |
1776 | }\r | |
1777 | \r | |
1778 | #[test]\r | |
1779 | fn test_to_level_filter() {\r | |
1780 | assert_eq!(LevelFilter::Error, Level::Error.to_level_filter());\r | |
1781 | assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter());\r | |
1782 | }\r | |
1783 | \r | |
5869c6ff XL |
1784 | #[test]\r |
1785 | fn test_level_filter_as_str() {\r | |
1786 | let tests = &[\r | |
1787 | (LevelFilter::Off, "OFF"),\r | |
1788 | (LevelFilter::Error, "ERROR"),\r | |
1789 | (LevelFilter::Warn, "WARN"),\r | |
1790 | (LevelFilter::Info, "INFO"),\r | |
1791 | (LevelFilter::Debug, "DEBUG"),\r | |
1792 | (LevelFilter::Trace, "TRACE"),\r | |
1793 | ];\r | |
1794 | for (input, expected) in tests {\r | |
1795 | assert_eq!(*expected, input.as_str());\r | |
1796 | }\r | |
1797 | }\r | |
1798 | \r | |
3dfed10e XL |
1799 | #[test]\r |
1800 | #[cfg(feature = "std")]\r | |
1801 | fn test_error_trait() {\r | |
1802 | use super::SetLoggerError;\r | |
1803 | let e = SetLoggerError(());\r | |
1804 | assert_eq!(\r | |
1805 | &e.to_string(),\r | |
1806 | "attempted to set a logger after the logging system \\r | |
1807 | was already initialized"\r | |
1808 | );\r | |
1809 | }\r | |
1810 | \r | |
1811 | #[test]\r | |
1812 | fn test_metadata_builder() {\r | |
1813 | use super::MetadataBuilder;\r | |
1814 | let target = "myApp";\r | |
1815 | let metadata_test = MetadataBuilder::new()\r | |
1816 | .level(Level::Debug)\r | |
1817 | .target(target)\r | |
1818 | .build();\r | |
1819 | assert_eq!(metadata_test.level(), Level::Debug);\r | |
1820 | assert_eq!(metadata_test.target(), "myApp");\r | |
1821 | }\r | |
1822 | \r | |
1823 | #[test]\r | |
1824 | fn test_metadata_convenience_builder() {\r | |
1825 | use super::Metadata;\r | |
1826 | let target = "myApp";\r | |
1827 | let metadata_test = Metadata::builder()\r | |
1828 | .level(Level::Debug)\r | |
1829 | .target(target)\r | |
1830 | .build();\r | |
1831 | assert_eq!(metadata_test.level(), Level::Debug);\r | |
1832 | assert_eq!(metadata_test.target(), "myApp");\r | |
1833 | }\r | |
1834 | \r | |
1835 | #[test]\r | |
1836 | fn test_record_builder() {\r | |
1837 | use super::{MetadataBuilder, RecordBuilder};\r | |
1838 | let target = "myApp";\r | |
1839 | let metadata = MetadataBuilder::new().target(target).build();\r | |
1840 | let fmt_args = format_args!("hello");\r | |
1841 | let record_test = RecordBuilder::new()\r | |
1842 | .args(fmt_args)\r | |
1843 | .metadata(metadata)\r | |
1844 | .module_path(Some("foo"))\r | |
1845 | .file(Some("bar"))\r | |
1846 | .line(Some(30))\r | |
1847 | .build();\r | |
1848 | assert_eq!(record_test.metadata().target(), "myApp");\r | |
1849 | assert_eq!(record_test.module_path(), Some("foo"));\r | |
1850 | assert_eq!(record_test.file(), Some("bar"));\r | |
1851 | assert_eq!(record_test.line(), Some(30));\r | |
1852 | }\r | |
1853 | \r | |
1854 | #[test]\r | |
1855 | fn test_record_convenience_builder() {\r | |
1856 | use super::{Metadata, Record};\r | |
1857 | let target = "myApp";\r | |
1858 | let metadata = Metadata::builder().target(target).build();\r | |
1859 | let fmt_args = format_args!("hello");\r | |
1860 | let record_test = Record::builder()\r | |
1861 | .args(fmt_args)\r | |
1862 | .metadata(metadata)\r | |
1863 | .module_path(Some("foo"))\r | |
1864 | .file(Some("bar"))\r | |
1865 | .line(Some(30))\r | |
1866 | .build();\r | |
1867 | assert_eq!(record_test.target(), "myApp");\r | |
1868 | assert_eq!(record_test.module_path(), Some("foo"));\r | |
1869 | assert_eq!(record_test.file(), Some("bar"));\r | |
1870 | assert_eq!(record_test.line(), Some(30));\r | |
1871 | }\r | |
1872 | \r | |
1873 | #[test]\r | |
1874 | fn test_record_complete_builder() {\r | |
1875 | use super::{Level, Record};\r | |
1876 | let target = "myApp";\r | |
1877 | let record_test = Record::builder()\r | |
1878 | .module_path(Some("foo"))\r | |
1879 | .file(Some("bar"))\r | |
1880 | .line(Some(30))\r | |
1881 | .target(target)\r | |
1882 | .level(Level::Error)\r | |
1883 | .build();\r | |
1884 | assert_eq!(record_test.target(), "myApp");\r | |
1885 | assert_eq!(record_test.level(), Level::Error);\r | |
1886 | assert_eq!(record_test.module_path(), Some("foo"));\r | |
1887 | assert_eq!(record_test.file(), Some("bar"));\r | |
1888 | assert_eq!(record_test.line(), Some(30));\r | |
1889 | }\r | |
1890 | \r | |
1891 | #[test]\r | |
1892 | #[cfg(feature = "kv_unstable")]\r | |
1893 | fn test_record_key_values_builder() {\r | |
1894 | use super::Record;\r | |
1895 | use kv::{self, Visitor};\r | |
1896 | \r | |
1897 | struct TestVisitor {\r | |
1898 | seen_pairs: usize,\r | |
1899 | }\r | |
1900 | \r | |
1901 | impl<'kvs> Visitor<'kvs> for TestVisitor {\r | |
1902 | fn visit_pair(\r | |
1903 | &mut self,\r | |
1904 | _: kv::Key<'kvs>,\r | |
1905 | _: kv::Value<'kvs>,\r | |
1906 | ) -> Result<(), kv::Error> {\r | |
1907 | self.seen_pairs += 1;\r | |
1908 | Ok(())\r | |
1909 | }\r | |
1910 | }\r | |
1911 | \r | |
1912 | let kvs: &[(&str, i32)] = &[("a", 1), ("b", 2)];\r | |
1913 | let record_test = Record::builder().key_values(&kvs).build();\r | |
1914 | \r | |
1915 | let mut visitor = TestVisitor { seen_pairs: 0 };\r | |
1916 | \r | |
1917 | record_test.key_values().visit(&mut visitor).unwrap();\r | |
1918 | \r | |
1919 | assert_eq!(2, visitor.seen_pairs);\r | |
1920 | }\r | |
1921 | \r | |
1922 | #[test]\r | |
1923 | #[cfg(feature = "kv_unstable")]\r | |
1924 | fn test_record_key_values_get_coerce() {\r | |
1925 | use super::Record;\r | |
1926 | \r | |
1927 | let kvs: &[(&str, &str)] = &[("a", "1"), ("b", "2")];\r | |
1928 | let record = Record::builder().key_values(&kvs).build();\r | |
1929 | \r | |
1930 | assert_eq!(\r | |
1931 | "2",\r | |
1932 | record\r | |
1933 | .key_values()\r | |
1934 | .get("b".into())\r | |
1935 | .expect("missing key")\r | |
1936 | .to_borrowed_str()\r | |
1937 | .expect("invalid value")\r | |
1938 | );\r | |
1939 | }\r | |
04454e1e FG |
1940 | \r |
1941 | // Test that the `impl Log for Foo` blocks work\r | |
1942 | // This test mostly operates on a type level, so failures will be compile errors\r | |
1943 | #[test]\r | |
1944 | fn test_foreign_impl() {\r | |
1945 | use super::Log;\r | |
1946 | #[cfg(feature = "std")]\r | |
1947 | use std::sync::Arc;\r | |
1948 | \r | |
1949 | fn assert_is_log<T: Log + ?Sized>() {}\r | |
1950 | \r | |
1951 | assert_is_log::<&dyn Log>();\r | |
1952 | \r | |
1953 | #[cfg(feature = "std")]\r | |
1954 | assert_is_log::<Box<dyn Log>>();\r | |
1955 | \r | |
1956 | #[cfg(feature = "std")]\r | |
1957 | assert_is_log::<Arc<dyn Log>>();\r | |
1958 | \r | |
1959 | // Assert these statements for all T: Log + ?Sized\r | |
1960 | #[allow(unused)]\r | |
1961 | fn forall<T: Log + ?Sized>() {\r | |
1962 | #[cfg(feature = "std")]\r | |
1963 | assert_is_log::<Box<T>>();\r | |
1964 | \r | |
1965 | assert_is_log::<&T>();\r | |
1966 | \r | |
1967 | #[cfg(feature = "std")]\r | |
1968 | assert_is_log::<Arc<T>>();\r | |
1969 | }\r | |
1970 | }\r | |
3dfed10e | 1971 | }\r |