]> git.proxmox.com Git - rustc.git/blame - vendor/log/src/lib.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / vendor / log / src / lib.rs
CommitLineData
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
328extern crate core as std;\r
329\r
330#[macro_use]\r
331extern crate cfg_if;\r
332\r
333use std::cmp;\r
334#[cfg(feature = "std")]\r
335use std::error;\r
336use std::fmt;\r
337use std::mem;\r
338use std::str::FromStr;\r
3dfed10e
XL
339\r
340#[macro_use]\r
341mod macros;\r
342mod serde;\r
343\r
344#[cfg(feature = "kv_unstable")]\r
345pub mod kv;\r
346\r
5869c6ff
XL
347#[cfg(has_atomics)]\r
348use std::sync::atomic::{AtomicUsize, Ordering};\r
349\r
350#[cfg(not(has_atomics))]\r
351use std::cell::Cell;\r
352#[cfg(not(has_atomics))]\r
353use std::sync::atomic::Ordering;\r
354\r
355#[cfg(not(has_atomics))]\r
356struct AtomicUsize {\r
357 v: Cell<usize>,\r
358}\r
359\r
360#[cfg(not(has_atomics))]\r
361impl 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
393unsafe 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
397static mut LOGGER: &dyn Log = &NopLogger;\r
398\r
399static 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
404const UNINITIALIZED: usize = 0;\r
405const INITIALIZING: usize = 1;\r
406const INITIALIZED: usize = 2;\r
407\r
408static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0);\r
409\r
410static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];\r
411\r
412static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \\r
413 was already initialized";\r
414static 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
425pub 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
451impl Clone for Level {\r
452 #[inline]\r
453 fn clone(&self) -> Level {\r
454 *self\r
455 }\r
456}\r
457\r
458impl 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
465impl 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
472impl 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
499impl 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
526impl 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
533fn 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
541fn 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
559impl 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
575impl 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
581impl 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
641pub 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
658impl Clone for LevelFilter {\r
659 #[inline]\r
660 fn clone(&self) -> LevelFilter {\r
661 *self\r
662 }\r
663}\r
664\r
665impl 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
672impl 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
679impl 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
706impl 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
733impl 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
740impl 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
753impl 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
759impl 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
813enum MaybeStaticStr<'a> {\r
814 Static(&'static str),\r
815 Borrowed(&'a str),\r
816}\r
817\r
818impl<'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
874pub 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
890struct KeyValues<'a>(&'a dyn kv::Source);\r
891\r
892#[cfg(feature = "kv_unstable")]\r
893impl<'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
901impl<'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
1035pub struct RecordBuilder<'a> {\r
1036 record: Record<'a>,\r
1037}\r
1038\r
1039impl<'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
1184pub struct Metadata<'a> {\r
1185 level: Level,\r
1186 target: &'a str,\r
1187}\r
1188\r
1189impl<'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
1226pub struct MetadataBuilder<'a> {\r
1227 metadata: Metadata<'a>,\r
1228}\r
1229\r
1230impl<'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
1269pub 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
1298struct NopLogger;\r
1299\r
1300impl 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
1309impl<T> Log for &'_ T\r
1310where\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
1326impl<T> Log for std::boxed::Box<T>\r
1327where\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
1343impl<T> Log for std::sync::Arc<T>\r
1344where\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
1365pub 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
1383pub 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
1407pub 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
1465pub 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
1470fn set_logger_inner<F>(make_logger: F) -> Result<(), SetLoggerError>\r
1471where\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
1521pub 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
1541pub struct SetLoggerError(());\r
1542\r
1543impl 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
1551impl 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
1558pub struct ParseLevelError(());\r
1559\r
1560impl 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
1568impl 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
1573pub 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
1585pub 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
1612pub 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
1633pub 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
1639pub 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
1652pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL_INNER;\r
1653\r
1654cfg_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
1683mod 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