aboutsummaryrefslogtreecommitdiff
path: root/vendor/log/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/log/src/lib.rs')
-rw-r--r--vendor/log/src/lib.rs1827
1 files changed, 1827 insertions, 0 deletions
diff --git a/vendor/log/src/lib.rs b/vendor/log/src/lib.rs
new file mode 100644
index 0000000..ab5cdfa
--- /dev/null
+++ b/vendor/log/src/lib.rs
@@ -0,0 +1,1827 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A lightweight logging facade.
+//!
+//! The `log` crate provides a single logging API that abstracts over the
+//! actual logging implementation. Libraries can use the logging API provided
+//! by this crate, and the consumer of those libraries can choose the logging
+//! implementation that is most suitable for its use case.
+//!
+//! If no logging implementation is selected, the facade falls back to a "noop"
+//! implementation that ignores all log messages. The overhead in this case
+//! is very small - just an integer load, comparison and jump.
+//!
+//! A log request consists of a _target_, a _level_, and a _body_. A target is a
+//! string which defaults to the module path of the location of the log request,
+//! though that default may be overridden. Logger implementations typically use
+//! the target to filter requests based on some user configuration.
+//!
+//! # Usage
+//!
+//! The basic use of the log crate is through the five logging macros: [`error!`],
+//! [`warn!`], [`info!`], [`debug!`] and [`trace!`]
+//! where `error!` represents the highest-priority log messages
+//! and `trace!` the lowest. The log messages are filtered by configuring
+//! the log level to exclude messages with a lower priority.
+//! Each of these macros accept format strings similarly to [`println!`].
+//!
+//!
+//! [`error!`]: ./macro.error.html
+//! [`warn!`]: ./macro.warn.html
+//! [`info!`]: ./macro.info.html
+//! [`debug!`]: ./macro.debug.html
+//! [`trace!`]: ./macro.trace.html
+//! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html
+//!
+//! ## In libraries
+//!
+//! Libraries should link only to the `log` crate, and use the provided
+//! macros to log whatever information will be useful to downstream consumers.
+//!
+//! ### Examples
+//!
+//! ```edition2018
+//! # #[derive(Debug)] pub struct Yak(String);
+//! # impl Yak { fn shave(&mut self, _: u32) {} }
+//! # fn find_a_razor() -> Result<u32, u32> { Ok(1) }
+//! use log::{info, warn};
+//!
+//! pub fn shave_the_yak(yak: &mut Yak) {
+//! info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);
+//!
+//! loop {
+//! match find_a_razor() {
+//! Ok(razor) => {
+//! info!("Razor located: {}", razor);
+//! yak.shave(razor);
+//! break;
+//! }
+//! Err(err) => {
+//! warn!("Unable to locate a razor: {}, retrying", err);
+//! }
+//! }
+//! }
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! ## In executables
+//!
+//! Executables should choose a logging implementation and initialize it early in the
+//! runtime of the program. Logging implementations will typically include a
+//! function to do this. Any log messages generated before
+//! the implementation is initialized will be ignored.
+//!
+//! The executable itself may use the `log` crate to log as well.
+//!
+//! ### Warning
+//!
+//! The logging system may only be initialized once.
+//!
+//! ## Structured logging
+//!
+//! If you enable the `kv_unstable` feature you can associate structured values
+//! with your log records. If we take the example from before, we can include
+//! some additional context besides what's in the formatted message:
+//!
+//! ```edition2018
+//! # #[macro_use] extern crate serde;
+//! # #[derive(Debug, Serialize)] pub struct Yak(String);
+//! # impl Yak { fn shave(&mut self, _: u32) {} }
+//! # fn find_a_razor() -> Result<u32, std::io::Error> { Ok(1) }
+//! # #[cfg(feature = "kv_unstable_serde")]
+//! # fn main() {
+//! use log::{info, warn, as_serde, as_error};
+//!
+//! pub fn shave_the_yak(yak: &mut Yak) {
+//! info!(target: "yak_events", yak = as_serde!(yak); "Commencing yak shaving");
+//!
+//! loop {
+//! match find_a_razor() {
+//! Ok(razor) => {
+//! info!(razor = razor; "Razor located");
+//! yak.shave(razor);
+//! break;
+//! }
+//! Err(err) => {
+//! warn!(err = as_error!(err); "Unable to locate a razor, retrying");
+//! }
+//! }
+//! }
+//! }
+//! # }
+//! # #[cfg(not(feature = "kv_unstable_serde"))]
+//! # fn main() {}
+//! ```
+//!
+//! # Available logging implementations
+//!
+//! In order to produce log output executables have to use
+//! a logger implementation compatible with the facade.
+//! There are many available implementations to choose from,
+//! here are some of the most popular ones:
+//!
+//! * Simple minimal loggers:
+//! * [env_logger]
+//! * [simple_logger]
+//! * [simplelog]
+//! * [pretty_env_logger]
+//! * [stderrlog]
+//! * [flexi_logger]
+//! * [call_logger]
+//! * [structured-logger]
+//! * Complex configurable frameworks:
+//! * [log4rs]
+//! * [fern]
+//! * Adaptors for other facilities:
+//! * [syslog]
+//! * [slog-stdlog]
+//! * [systemd-journal-logger]
+//! * [android_log]
+//! * [win_dbg_logger]
+//! * [db_logger]
+//! * [log-to-defmt]
+//! * For WebAssembly binaries:
+//! * [console_log]
+//! * For dynamic libraries:
+//! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries
+//!
+//! # Implementing a Logger
+//!
+//! Loggers implement the [`Log`] trait. Here's a very basic example that simply
+//! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or
+//! [`Info`][level_link] levels to stdout:
+//!
+//! ```edition2018
+//! use log::{Record, Level, Metadata};
+//!
+//! struct SimpleLogger;
+//!
+//! impl log::Log for SimpleLogger {
+//! fn enabled(&self, metadata: &Metadata) -> bool {
+//! metadata.level() <= Level::Info
+//! }
+//!
+//! fn log(&self, record: &Record) {
+//! if self.enabled(record.metadata()) {
+//! println!("{} - {}", record.level(), record.args());
+//! }
+//! }
+//!
+//! fn flush(&self) {}
+//! }
+//!
+//! # fn main() {}
+//! ```
+//!
+//! Loggers are installed by calling the [`set_logger`] function. The maximum
+//! log level also needs to be adjusted via the [`set_max_level`] function. The
+//! logging facade uses this as an optimization to improve performance of log
+//! messages at levels that are disabled. It's important to set it, as it
+//! defaults to [`Off`][filter_link], so no log messages will ever be captured!
+//! In the case of our example logger, we'll want to set the maximum log level
+//! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or
+//! [`Trace`][level_link] level log messages. A logging implementation should
+//! provide a function that wraps a call to [`set_logger`] and
+//! [`set_max_level`], handling initialization of the logger:
+//!
+//! ```edition2018
+//! # use log::{Level, Metadata};
+//! # struct SimpleLogger;
+//! # impl log::Log for SimpleLogger {
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn log(&self, _: &log::Record) {}
+//! # fn flush(&self) {}
+//! # }
+//! # fn main() {}
+//! use log::{SetLoggerError, LevelFilter};
+//!
+//! static LOGGER: SimpleLogger = SimpleLogger;
+//!
+//! pub fn init() -> Result<(), SetLoggerError> {
+//! log::set_logger(&LOGGER)
+//! .map(|()| log::set_max_level(LevelFilter::Info))
+//! }
+//! ```
+//!
+//! Implementations that adjust their configurations at runtime should take care
+//! to adjust the maximum log level as well.
+//!
+//! # Use with `std`
+//!
+//! `set_logger` requires you to provide a `&'static Log`, which can be hard to
+//! obtain if your logger depends on some runtime configuration. The
+//! `set_boxed_logger` function is available with the `std` Cargo feature. It is
+//! identical to `set_logger` except that it takes a `Box<Log>` rather than a
+//! `&'static Log`:
+//!
+//! ```edition2018
+//! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata};
+//! # struct SimpleLogger;
+//! # impl log::Log for SimpleLogger {
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn log(&self, _: &log::Record) {}
+//! # fn flush(&self) {}
+//! # }
+//! # fn main() {}
+//! # #[cfg(feature = "std")]
+//! pub fn init() -> Result<(), SetLoggerError> {
+//! log::set_boxed_logger(Box::new(SimpleLogger))
+//! .map(|()| log::set_max_level(LevelFilter::Info))
+//! }
+//! ```
+//!
+//! # Compile time filters
+//!
+//! Log levels can be statically disabled at compile time via Cargo features. Log invocations at
+//! disabled levels will be skipped and will not even be present in the resulting binary.
+//! This level is configured separately for release and debug builds. The features are:
+//!
+//! * `max_level_off`
+//! * `max_level_error`
+//! * `max_level_warn`
+//! * `max_level_info`
+//! * `max_level_debug`
+//! * `max_level_trace`
+//! * `release_max_level_off`
+//! * `release_max_level_error`
+//! * `release_max_level_warn`
+//! * `release_max_level_info`
+//! * `release_max_level_debug`
+//! * `release_max_level_trace`
+//!
+//! These features control the value of the `STATIC_MAX_LEVEL` constant. The logging macros check
+//! this value before logging a message. By default, no levels are disabled.
+//!
+//! Libraries should avoid using the max level features because they're global and can't be changed
+//! once they're set.
+//!
+//! For example, a crate can disable trace level logs in debug builds and trace, debug, and info
+//! level logs in release builds with the following configuration:
+//!
+//! ```toml
+//! [dependencies]
+//! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] }
+//! ```
+//! # Crate Feature Flags
+//!
+//! The following crate feature flags are available in addition to the filters. They are
+//! configured in your `Cargo.toml`.
+//!
+//! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and
+//! `set_boxed_logger` functionality.
+//! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`.
+//!
+//! ```toml
+//! [dependencies]
+//! log = { version = "0.4", features = ["std", "serde"] }
+//! ```
+//!
+//! # Version compatibility
+//!
+//! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages
+//! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log
+//! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the
+//! module path and file name information associated with the message will unfortunately be lost.
+//!
+//! [`Log`]: trait.Log.html
+//! [level_link]: enum.Level.html
+//! [filter_link]: enum.LevelFilter.html
+//! [`set_logger`]: fn.set_logger.html
+//! [`set_max_level`]: fn.set_max_level.html
+//! [`try_set_logger_raw`]: fn.try_set_logger_raw.html
+//! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html
+//! [env_logger]: https://docs.rs/env_logger/*/env_logger/
+//! [simple_logger]: https://github.com/borntyping/rust-simple_logger
+//! [simplelog]: https://github.com/drakulix/simplelog.rs
+//! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/
+//! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/
+//! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/
+//! [call_logger]: https://docs.rs/call_logger/*/call_logger/
+//! [syslog]: https://docs.rs/syslog/*/syslog/
+//! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/
+//! [log4rs]: https://docs.rs/log4rs/*/log4rs/
+//! [fern]: https://docs.rs/fern/*/fern/
+//! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/
+//! [android_log]: https://docs.rs/android_log/*/android_log/
+//! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/
+//! [db_logger]: https://docs.rs/db_logger/*/db_logger/
+//! [log-to-defmt]: https://docs.rs/log-to-defmt/*/log_to_defmt/
+//! [console_log]: https://docs.rs/console_log/*/console_log/
+//! [structured-logger]: https://docs.rs/structured-logger/latest/structured_logger/
+
+#![doc(
+ html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://docs.rs/log/0.4.20"
+)]
+#![warn(missing_docs)]
+#![deny(missing_debug_implementations, unconditional_recursion)]
+#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
+// When compiled for the rustc compiler itself we want to make sure that this is
+// an unstable crate
+#![cfg_attr(rustbuild, feature(staged_api, rustc_private))]
+#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))]
+
+#[cfg(all(not(feature = "std"), not(test)))]
+extern crate core as std;
+
+use std::cmp;
+#[cfg(feature = "std")]
+use std::error;
+use std::fmt;
+use std::mem;
+use std::str::FromStr;
+
+#[macro_use]
+mod macros;
+mod serde;
+
+#[cfg(feature = "kv_unstable")]
+pub mod kv;
+
+#[cfg(target_has_atomic = "ptr")]
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+#[cfg(not(target_has_atomic = "ptr"))]
+use std::cell::Cell;
+#[cfg(not(target_has_atomic = "ptr"))]
+use std::sync::atomic::Ordering;
+
+#[cfg(not(target_has_atomic = "ptr"))]
+struct AtomicUsize {
+ v: Cell<usize>,
+}
+
+#[cfg(not(target_has_atomic = "ptr"))]
+impl AtomicUsize {
+ const fn new(v: usize) -> AtomicUsize {
+ AtomicUsize { v: Cell::new(v) }
+ }
+
+ fn load(&self, _order: Ordering) -> usize {
+ self.v.get()
+ }
+
+ fn store(&self, val: usize, _order: Ordering) {
+ self.v.set(val)
+ }
+
+ #[cfg(target_has_atomic = "ptr")]
+ fn compare_exchange(
+ &self,
+ current: usize,
+ new: usize,
+ _success: Ordering,
+ _failure: Ordering,
+ ) -> Result<usize, usize> {
+ let prev = self.v.get();
+ if current == prev {
+ self.v.set(new);
+ }
+ Ok(prev)
+ }
+}
+
+// Any platform without atomics is unlikely to have multiple cores, so
+// writing via Cell will not be a race condition.
+#[cfg(not(target_has_atomic = "ptr"))]
+unsafe impl Sync for AtomicUsize {}
+
+// The LOGGER static holds a pointer to the global logger. It is protected by
+// the STATE static which determines whether LOGGER has been initialized yet.
+static mut LOGGER: &dyn Log = &NopLogger;
+
+static STATE: AtomicUsize = AtomicUsize::new(0);
+
+// There are three different states that we care about: the logger's
+// uninitialized, the logger's initializing (set_logger's been called but
+// LOGGER hasn't actually been set yet), or the logger's active.
+const UNINITIALIZED: usize = 0;
+const INITIALIZING: usize = 1;
+const INITIALIZED: usize = 2;
+
+static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0);
+
+static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];
+
+static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \
+ was already initialized";
+static LEVEL_PARSE_ERROR: &str =
+ "attempted to convert a string that doesn't match an existing log level";
+
+/// An enum representing the available verbosity levels of the logger.
+///
+/// Typical usage includes: checking if a certain `Level` is enabled with
+/// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of
+/// [`log!`](macro.log.html), and comparing a `Level` directly to a
+/// [`LevelFilter`](enum.LevelFilter.html).
+#[repr(usize)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Level {
+ /// The "error" level.
+ ///
+ /// Designates very serious errors.
+ // This way these line up with the discriminants for LevelFilter below
+ // This works because Rust treats field-less enums the same way as C does:
+ // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations
+ Error = 1,
+ /// The "warn" level.
+ ///
+ /// Designates hazardous situations.
+ Warn,
+ /// The "info" level.
+ ///
+ /// Designates useful information.
+ Info,
+ /// The "debug" level.
+ ///
+ /// Designates lower priority information.
+ Debug,
+ /// The "trace" level.
+ ///
+ /// Designates very low priority, often extremely verbose, information.
+ Trace,
+}
+
+impl PartialEq<LevelFilter> for Level {
+ #[inline]
+ fn eq(&self, other: &LevelFilter) -> bool {
+ *self as usize == *other as usize
+ }
+}
+
+impl PartialOrd<LevelFilter> for Level {
+ #[inline]
+ fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
+ Some((*self as usize).cmp(&(*other as usize)))
+ }
+}
+
+fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
+ match t {
+ Some(t) => Ok(t),
+ None => Err(e),
+ }
+}
+
+impl FromStr for Level {
+ type Err = ParseLevelError;
+ fn from_str(level: &str) -> Result<Level, Self::Err> {
+ ok_or(
+ LOG_LEVEL_NAMES
+ .iter()
+ .position(|&name| name.eq_ignore_ascii_case(level))
+ .into_iter()
+ .filter(|&idx| idx != 0)
+ .map(|idx| Level::from_usize(idx).unwrap())
+ .next(),
+ ParseLevelError(()),
+ )
+ }
+}
+
+impl fmt::Display for Level {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.pad(self.as_str())
+ }
+}
+
+impl Level {
+ fn from_usize(u: usize) -> Option<Level> {
+ match u {
+ 1 => Some(Level::Error),
+ 2 => Some(Level::Warn),
+ 3 => Some(Level::Info),
+ 4 => Some(Level::Debug),
+ 5 => Some(Level::Trace),
+ _ => None,
+ }
+ }
+
+ /// Returns the most verbose logging level.
+ #[inline]
+ pub fn max() -> Level {
+ Level::Trace
+ }
+
+ /// Converts the `Level` to the equivalent `LevelFilter`.
+ #[inline]
+ pub fn to_level_filter(&self) -> LevelFilter {
+ LevelFilter::from_usize(*self as usize).unwrap()
+ }
+
+ /// Returns the string representation of the `Level`.
+ ///
+ /// This returns the same string as the `fmt::Display` implementation.
+ pub fn as_str(&self) -> &'static str {
+ LOG_LEVEL_NAMES[*self as usize]
+ }
+
+ /// Iterate through all supported logging levels.
+ ///
+ /// The order of iteration is from more severe to less severe log messages.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use log::Level;
+ ///
+ /// let mut levels = Level::iter();
+ ///
+ /// assert_eq!(Some(Level::Error), levels.next());
+ /// assert_eq!(Some(Level::Trace), levels.last());
+ /// ```
+ pub fn iter() -> impl Iterator<Item = Self> {
+ (1..6).map(|i| Self::from_usize(i).unwrap())
+ }
+}
+
+/// An enum representing the available verbosity level filters of the logger.
+///
+/// A `LevelFilter` may be compared directly to a [`Level`]. Use this type
+/// to get and set the maximum log level with [`max_level()`] and [`set_max_level`].
+///
+/// [`Level`]: enum.Level.html
+/// [`max_level()`]: fn.max_level.html
+/// [`set_max_level`]: fn.set_max_level.html
+#[repr(usize)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum LevelFilter {
+ /// A level lower than all log levels.
+ Off,
+ /// Corresponds to the `Error` log level.
+ Error,
+ /// Corresponds to the `Warn` log level.
+ Warn,
+ /// Corresponds to the `Info` log level.
+ Info,
+ /// Corresponds to the `Debug` log level.
+ Debug,
+ /// Corresponds to the `Trace` log level.
+ Trace,
+}
+
+impl PartialEq<Level> for LevelFilter {
+ #[inline]
+ fn eq(&self, other: &Level) -> bool {
+ other.eq(self)
+ }
+}
+
+impl PartialOrd<Level> for LevelFilter {
+ #[inline]
+ fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
+ Some((*self as usize).cmp(&(*other as usize)))
+ }
+}
+
+impl FromStr for LevelFilter {
+ type Err = ParseLevelError;
+ fn from_str(level: &str) -> Result<LevelFilter, Self::Err> {
+ ok_or(
+ LOG_LEVEL_NAMES
+ .iter()
+ .position(|&name| name.eq_ignore_ascii_case(level))
+ .map(|p| LevelFilter::from_usize(p).unwrap()),
+ ParseLevelError(()),
+ )
+ }
+}
+
+impl fmt::Display for LevelFilter {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.pad(self.as_str())
+ }
+}
+
+impl LevelFilter {
+ fn from_usize(u: usize) -> Option<LevelFilter> {
+ match u {
+ 0 => Some(LevelFilter::Off),
+ 1 => Some(LevelFilter::Error),
+ 2 => Some(LevelFilter::Warn),
+ 3 => Some(LevelFilter::Info),
+ 4 => Some(LevelFilter::Debug),
+ 5 => Some(LevelFilter::Trace),
+ _ => None,
+ }
+ }
+
+ /// Returns the most verbose logging level filter.
+ #[inline]
+ pub fn max() -> LevelFilter {
+ LevelFilter::Trace
+ }
+
+ /// Converts `self` to the equivalent `Level`.
+ ///
+ /// Returns `None` if `self` is `LevelFilter::Off`.
+ #[inline]
+ pub fn to_level(&self) -> Option<Level> {
+ Level::from_usize(*self as usize)
+ }
+
+ /// Returns the string representation of the `LevelFilter`.
+ ///
+ /// This returns the same string as the `fmt::Display` implementation.
+ pub fn as_str(&self) -> &'static str {
+ LOG_LEVEL_NAMES[*self as usize]
+ }
+
+ /// Iterate through all supported filtering levels.
+ ///
+ /// The order of iteration is from less to more verbose filtering.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use log::LevelFilter;
+ ///
+ /// let mut levels = LevelFilter::iter();
+ ///
+ /// assert_eq!(Some(LevelFilter::Off), levels.next());
+ /// assert_eq!(Some(LevelFilter::Trace), levels.last());
+ /// ```
+ pub fn iter() -> impl Iterator<Item = Self> {
+ (0..6).map(|i| Self::from_usize(i).unwrap())
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+enum MaybeStaticStr<'a> {
+ Static(&'static str),
+ Borrowed(&'a str),
+}
+
+impl<'a> MaybeStaticStr<'a> {
+ #[inline]
+ fn get(&self) -> &'a str {
+ match *self {
+ MaybeStaticStr::Static(s) => s,
+ MaybeStaticStr::Borrowed(s) => s,
+ }
+ }
+}
+
+/// The "payload" of a log message.
+///
+/// # Use
+///
+/// `Record` structures are passed as parameters to the [`log`][method.log]
+/// method of the [`Log`] trait. Logger implementors manipulate these
+/// structures in order to display log messages. `Record`s are automatically
+/// created by the [`log!`] macro and so are not seen by log users.
+///
+/// Note that the [`level()`] and [`target()`] accessors are equivalent to
+/// `self.metadata().level()` and `self.metadata().target()` respectively.
+/// These methods are provided as a convenience for users of this structure.
+///
+/// # Example
+///
+/// The following example shows a simple logger that displays the level,
+/// module path, and message of any `Record` that is passed to it.
+///
+/// ```edition2018
+/// struct SimpleLogger;
+///
+/// impl log::Log for SimpleLogger {
+/// fn enabled(&self, _metadata: &log::Metadata) -> bool {
+/// true
+/// }
+///
+/// fn log(&self, record: &log::Record) {
+/// if !self.enabled(record.metadata()) {
+/// return;
+/// }
+///
+/// println!("{}:{} -- {}",
+/// record.level(),
+/// record.target(),
+/// record.args());
+/// }
+/// fn flush(&self) {}
+/// }
+/// ```
+///
+/// [method.log]: trait.Log.html#tymethod.log
+/// [`Log`]: trait.Log.html
+/// [`log!`]: macro.log.html
+/// [`level()`]: struct.Record.html#method.level
+/// [`target()`]: struct.Record.html#method.target
+#[derive(Clone, Debug)]
+pub struct Record<'a> {
+ metadata: Metadata<'a>,
+ args: fmt::Arguments<'a>,
+ module_path: Option<MaybeStaticStr<'a>>,
+ file: Option<MaybeStaticStr<'a>>,
+ line: Option<u32>,
+ #[cfg(feature = "kv_unstable")]
+ key_values: KeyValues<'a>,
+}
+
+// This wrapper type is only needed so we can
+// `#[derive(Debug)]` on `Record`. It also
+// provides a useful `Debug` implementation for
+// the underlying `Source`.
+#[cfg(feature = "kv_unstable")]
+#[derive(Clone)]
+struct KeyValues<'a>(&'a dyn kv::Source);
+
+#[cfg(feature = "kv_unstable")]
+impl<'a> fmt::Debug for KeyValues<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut visitor = f.debug_map();
+ self.0.visit(&mut visitor).map_err(|_| fmt::Error)?;
+ visitor.finish()
+ }
+}
+
+impl<'a> Record<'a> {
+ /// Returns a new builder.
+ #[inline]
+ pub fn builder() -> RecordBuilder<'a> {
+ RecordBuilder::new()
+ }
+
+ /// The message body.
+ #[inline]
+ pub fn args(&self) -> &fmt::Arguments<'a> {
+ &self.args
+ }
+
+ /// Metadata about the log directive.
+ #[inline]
+ pub fn metadata(&self) -> &Metadata<'a> {
+ &self.metadata
+ }
+
+ /// The verbosity level of the message.
+ #[inline]
+ pub fn level(&self) -> Level {
+ self.metadata.level()
+ }
+
+ /// The name of the target of the directive.
+ #[inline]
+ pub fn target(&self) -> &'a str {
+ self.metadata.target()
+ }
+
+ /// The module path of the message.
+ #[inline]
+ pub fn module_path(&self) -> Option<&'a str> {
+ self.module_path.map(|s| s.get())
+ }
+
+ /// The module path of the message, if it is a `'static` string.
+ #[inline]
+ pub fn module_path_static(&self) -> Option<&'static str> {
+ match self.module_path {
+ Some(MaybeStaticStr::Static(s)) => Some(s),
+ _ => None,
+ }
+ }
+
+ /// The source file containing the message.
+ #[inline]
+ pub fn file(&self) -> Option<&'a str> {
+ self.file.map(|s| s.get())
+ }
+
+ /// The module path of the message, if it is a `'static` string.
+ #[inline]
+ pub fn file_static(&self) -> Option<&'static str> {
+ match self.file {
+ Some(MaybeStaticStr::Static(s)) => Some(s),
+ _ => None,
+ }
+ }
+
+ /// The line containing the message.
+ #[inline]
+ pub fn line(&self) -> Option<u32> {
+ self.line
+ }
+
+ /// The structured key-value pairs associated with the message.
+ #[cfg(feature = "kv_unstable")]
+ #[inline]
+ pub fn key_values(&self) -> &dyn kv::Source {
+ self.key_values.0
+ }
+
+ /// Create a new [`RecordBuilder`](struct.RecordBuilder.html) based on this record.
+ #[cfg(feature = "kv_unstable")]
+ #[inline]
+ pub fn to_builder(&self) -> RecordBuilder {
+ RecordBuilder {
+ record: Record {
+ metadata: Metadata {
+ level: self.metadata.level,
+ target: self.metadata.target,
+ },
+ args: self.args,
+ module_path: self.module_path,
+ file: self.file,
+ line: self.line,
+ key_values: self.key_values.clone(),
+ },
+ }
+ }
+}
+
+/// Builder for [`Record`](struct.Record.html).
+///
+/// Typically should only be used by log library creators or for testing and "shim loggers".
+/// The `RecordBuilder` can set the different parameters of `Record` object, and returns
+/// the created object when `build` is called.
+///
+/// # Examples
+///
+/// ```edition2018
+/// use log::{Level, Record};
+///
+/// let record = Record::builder()
+/// .args(format_args!("Error!"))
+/// .level(Level::Error)
+/// .target("myApp")
+/// .file(Some("server.rs"))
+/// .line(Some(144))
+/// .module_path(Some("server"))
+/// .build();
+/// ```
+///
+/// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html):
+///
+/// ```edition2018
+/// use log::{Record, Level, MetadataBuilder};
+///
+/// let error_metadata = MetadataBuilder::new()
+/// .target("myApp")
+/// .level(Level::Error)
+/// .build();
+///
+/// let record = Record::builder()
+/// .metadata(error_metadata)
+/// .args(format_args!("Error!"))
+/// .line(Some(433))
+/// .file(Some("app.rs"))
+/// .module_path(Some("server"))
+/// .build();
+/// ```
+#[derive(Debug)]
+pub struct RecordBuilder<'a> {
+ record: Record<'a>,
+}
+
+impl<'a> RecordBuilder<'a> {
+ /// Construct new `RecordBuilder`.
+ ///
+ /// The default options are:
+ ///
+ /// - `args`: [`format_args!("")`]
+ /// - `metadata`: [`Metadata::builder().build()`]
+ /// - `module_path`: `None`
+ /// - `file`: `None`
+ /// - `line`: `None`
+ ///
+ /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html
+ /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build
+ #[inline]
+ pub fn new() -> RecordBuilder<'a> {
+ RecordBuilder {
+ record: Record {
+ args: format_args!(""),
+ metadata: Metadata::builder().build(),
+ module_path: None,
+ file: None,
+ line: None,
+ #[cfg(feature = "kv_unstable")]
+ key_values: KeyValues(&Option::None::<(kv::Key, kv::Value)>),
+ },
+ }
+ }
+
+ /// Set [`args`](struct.Record.html#method.args).
+ #[inline]
+ pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> {
+ self.record.args = args;
+ self
+ }
+
+ /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html).
+ #[inline]
+ pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> {
+ self.record.metadata = metadata;
+ self
+ }
+
+ /// Set [`Metadata::level`](struct.Metadata.html#method.level).
+ #[inline]
+ pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> {
+ self.record.metadata.level = level;
+ self
+ }
+
+ /// Set [`Metadata::target`](struct.Metadata.html#method.target)
+ #[inline]
+ pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> {
+ self.record.metadata.target = target;
+ self
+ }
+
+ /// Set [`module_path`](struct.Record.html#method.module_path)
+ #[inline]
+ pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> {
+ self.record.module_path = path.map(MaybeStaticStr::Borrowed);
+ self
+ }
+
+ /// Set [`module_path`](struct.Record.html#method.module_path) to a `'static` string
+ #[inline]
+ pub fn module_path_static(&mut self, path: Option<&'static str>) -> &mut RecordBuilder<'a> {
+ self.record.module_path = path.map(MaybeStaticStr::Static);
+ self
+ }
+
+ /// Set [`file`](struct.Record.html#method.file)
+ #[inline]
+ pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> {
+ self.record.file = file.map(MaybeStaticStr::Borrowed);
+ self
+ }
+
+ /// Set [`file`](struct.Record.html#method.file) to a `'static` string.
+ #[inline]
+ pub fn file_static(&mut self, file: Option<&'static str>) -> &mut RecordBuilder<'a> {
+ self.record.file = file.map(MaybeStaticStr::Static);
+ self
+ }
+
+ /// Set [`line`](struct.Record.html#method.line)
+ #[inline]
+ pub fn line(&mut self, line: Option<u32>) -> &mut RecordBuilder<'a> {
+ self.record.line = line;
+ self
+ }
+
+ /// Set [`key_values`](struct.Record.html#method.key_values)
+ #[cfg(feature = "kv_unstable")]
+ #[inline]
+ pub fn key_values(&mut self, kvs: &'a dyn kv::Source) -> &mut RecordBuilder<'a> {
+ self.record.key_values = KeyValues(kvs);
+ self
+ }
+
+ /// Invoke the builder and return a `Record`
+ #[inline]
+ pub fn build(&self) -> Record<'a> {
+ self.record.clone()
+ }
+}
+
+impl<'a> Default for RecordBuilder<'a> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Metadata about a log message.
+///
+/// # Use
+///
+/// `Metadata` structs are created when users of the library use
+/// logging macros.
+///
+/// They are consumed by implementations of the `Log` trait in the
+/// `enabled` method.
+///
+/// `Record`s use `Metadata` to determine the log message's severity
+/// and target.
+///
+/// Users should use the `log_enabled!` macro in their code to avoid
+/// constructing expensive log messages.
+///
+/// # Examples
+///
+/// ```edition2018
+/// use log::{Record, Level, Metadata};
+///
+/// struct MyLogger;
+///
+/// impl log::Log for MyLogger {
+/// fn enabled(&self, metadata: &Metadata) -> bool {
+/// metadata.level() <= Level::Info
+/// }
+///
+/// fn log(&self, record: &Record) {
+/// if self.enabled(record.metadata()) {
+/// println!("{} - {}", record.level(), record.args());
+/// }
+/// }
+/// fn flush(&self) {}
+/// }
+///
+/// # fn main(){}
+/// ```
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+pub struct Metadata<'a> {
+ level: Level,
+ target: &'a str,
+}
+
+impl<'a> Metadata<'a> {
+ /// Returns a new builder.
+ #[inline]
+ pub fn builder() -> MetadataBuilder<'a> {
+ MetadataBuilder::new()
+ }
+
+ /// The verbosity level of the message.
+ #[inline]
+ pub fn level(&self) -> Level {
+ self.level
+ }
+
+ /// The name of the target of the directive.
+ #[inline]
+ pub fn target(&self) -> &'a str {
+ self.target
+ }
+}
+
+/// Builder for [`Metadata`](struct.Metadata.html).
+///
+/// Typically should only be used by log library creators or for testing and "shim loggers".
+/// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns
+/// the created object when `build` is called.
+///
+/// # Example
+///
+/// ```edition2018
+/// let target = "myApp";
+/// use log::{Level, MetadataBuilder};
+/// let metadata = MetadataBuilder::new()
+/// .level(Level::Debug)
+/// .target(target)
+/// .build();
+/// ```
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+pub struct MetadataBuilder<'a> {
+ metadata: Metadata<'a>,
+}
+
+impl<'a> MetadataBuilder<'a> {
+ /// Construct a new `MetadataBuilder`.
+ ///
+ /// The default options are:
+ ///
+ /// - `level`: `Level::Info`
+ /// - `target`: `""`
+ #[inline]
+ pub fn new() -> MetadataBuilder<'a> {
+ MetadataBuilder {
+ metadata: Metadata {
+ level: Level::Info,
+ target: "",
+ },
+ }
+ }
+
+ /// Setter for [`level`](struct.Metadata.html#method.level).
+ #[inline]
+ pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> {
+ self.metadata.level = arg;
+ self
+ }
+
+ /// Setter for [`target`](struct.Metadata.html#method.target).
+ #[inline]
+ pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> {
+ self.metadata.target = target;
+ self
+ }
+
+ /// Returns a `Metadata` object.
+ #[inline]
+ pub fn build(&self) -> Metadata<'a> {
+ self.metadata.clone()
+ }
+}
+
+impl<'a> Default for MetadataBuilder<'a> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// A trait encapsulating the operations required of a logger.
+pub trait Log: Sync + Send {
+ /// Determines if a log message with the specified metadata would be
+ /// logged.
+ ///
+ /// This is used by the `log_enabled!` macro to allow callers to avoid
+ /// expensive computation of log message arguments if the message would be
+ /// discarded anyway.
+ ///
+ /// # For implementors
+ ///
+ /// This method isn't called automatically by the `log!` macros.
+ /// It's up to an implementation of the `Log` trait to call `enabled` in its own
+ /// `log` method implementation to guarantee that filtering is applied.
+ fn enabled(&self, metadata: &Metadata) -> bool;
+
+ /// Logs the `Record`.
+ ///
+ /// # For implementors
+ ///
+ /// Note that `enabled` is *not* necessarily called before this method.
+ /// Implementations of `log` should perform all necessary filtering
+ /// internally.
+ fn log(&self, record: &Record);
+
+ /// Flushes any buffered records.
+ fn flush(&self);
+}
+
+// Just used as a dummy initial value for LOGGER
+struct NopLogger;
+
+impl Log for NopLogger {
+ fn enabled(&self, _: &Metadata) -> bool {
+ false
+ }
+
+ fn log(&self, _: &Record) {}
+ fn flush(&self) {}
+}
+
+impl<T> Log for &'_ T
+where
+ T: ?Sized + Log,
+{
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ (**self).enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ (**self).log(record);
+ }
+ fn flush(&self) {
+ (**self).flush();
+ }
+}
+
+#[cfg(feature = "std")]
+impl<T> Log for std::boxed::Box<T>
+where
+ T: ?Sized + Log,
+{
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ self.as_ref().enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ self.as_ref().log(record)
+ }
+ fn flush(&self) {
+ self.as_ref().flush()
+ }
+}
+
+#[cfg(feature = "std")]
+impl<T> Log for std::sync::Arc<T>
+where
+ T: ?Sized + Log,
+{
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ self.as_ref().enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ self.as_ref().log(record)
+ }
+ fn flush(&self) {
+ self.as_ref().flush()
+ }
+}
+
+/// Sets the global maximum log level.
+///
+/// Generally, this should only be called by the active logging implementation.
+///
+/// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs.
+#[inline]
+#[cfg(target_has_atomic = "ptr")]
+pub fn set_max_level(level: LevelFilter) {
+ MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed);
+}
+
+/// A thread-unsafe version of [`set_max_level`].
+///
+/// This function is available on all platforms, even those that do not have
+/// support for atomics that is needed by [`set_max_level`].
+///
+/// In almost all cases, [`set_max_level`] should be preferred.
+///
+/// # Safety
+///
+/// This function is only safe to call when no other level setting function is
+/// called while this function still executes.
+///
+/// This can be upheld by (for example) making sure that **there are no other
+/// threads**, and (on embedded) that **interrupts are disabled**.
+///
+/// Is is safe to use all other logging functions while this function runs
+/// (including all logging macros).
+///
+/// [`set_max_level`]: fn.set_max_level.html
+#[inline]
+pub unsafe fn set_max_level_racy(level: LevelFilter) {
+ // `MAX_LOG_LEVEL_FILTER` uses a `Cell` as the underlying primitive when a
+ // platform doesn't support `target_has_atomic = "ptr"`, so even though this looks the same
+ // as `set_max_level` it may have different safety properties.
+ MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed);
+}
+
+/// Returns the current maximum log level.
+///
+/// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check
+/// this value and discard any message logged at a higher level. The maximum
+/// log level is set by the [`set_max_level`] function.
+///
+/// [`log!`]: macro.log.html
+/// [`error!`]: macro.error.html
+/// [`warn!`]: macro.warn.html
+/// [`info!`]: macro.info.html
+/// [`debug!`]: macro.debug.html
+/// [`trace!`]: macro.trace.html
+/// [`set_max_level`]: fn.set_max_level.html
+#[inline(always)]
+pub fn max_level() -> LevelFilter {
+ // Since `LevelFilter` is `repr(usize)`,
+ // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER`
+ // is set to a usize that is a valid discriminant for `LevelFilter`.
+ // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set
+ // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`.
+ // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant.
+ unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) }
+}
+
+/// Sets the global logger to a `Box<Log>`.
+///
+/// This is a simple convenience wrapper over `set_logger`, which takes a
+/// `Box<Log>` rather than a `&'static Log`. See the documentation for
+/// [`set_logger`] for more details.
+///
+/// Requires the `std` feature.
+///
+/// # Errors
+///
+/// An error is returned if a logger has already been set.
+///
+/// [`set_logger`]: fn.set_logger.html
+#[cfg(all(feature = "std", target_has_atomic = "ptr"))]
+pub fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), SetLoggerError> {
+ set_logger_inner(|| Box::leak(logger))
+}
+
+/// Sets the global logger to a `&'static Log`.
+///
+/// This function may only be called once in the lifetime of a program. Any log
+/// events that occur before the call to `set_logger` completes will be ignored.
+///
+/// This function does not typically need to be called manually. Logger
+/// implementations should provide an initialization method that installs the
+/// logger internally.
+///
+/// # Availability
+///
+/// This method is available even when the `std` feature is disabled. However,
+/// it is currently unavailable on `thumbv6` targets, which lack support for
+/// some atomic operations which are used by this function. Even on those
+/// targets, [`set_logger_racy`] will be available.
+///
+/// # Errors
+///
+/// An error is returned if a logger has already been set.
+///
+/// # Examples
+///
+/// ```edition2018
+/// use log::{error, info, warn, Record, Level, Metadata, LevelFilter};
+///
+/// static MY_LOGGER: MyLogger = MyLogger;
+///
+/// struct MyLogger;
+///
+/// impl log::Log for MyLogger {
+/// fn enabled(&self, metadata: &Metadata) -> bool {
+/// metadata.level() <= Level::Info
+/// }
+///
+/// fn log(&self, record: &Record) {
+/// if self.enabled(record.metadata()) {
+/// println!("{} - {}", record.level(), record.args());
+/// }
+/// }
+/// fn flush(&self) {}
+/// }
+///
+/// # fn main(){
+/// log::set_logger(&MY_LOGGER).unwrap();
+/// log::set_max_level(LevelFilter::Info);
+///
+/// info!("hello log");
+/// warn!("warning");
+/// error!("oops");
+/// # }
+/// ```
+///
+/// [`set_logger_racy`]: fn.set_logger_racy.html
+#[cfg(target_has_atomic = "ptr")]
+pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
+ set_logger_inner(|| logger)
+}
+
+#[cfg(target_has_atomic = "ptr")]
+fn set_logger_inner<F>(make_logger: F) -> Result<(), SetLoggerError>
+where
+ F: FnOnce() -> &'static dyn Log,
+{
+ let old_state = match STATE.compare_exchange(
+ UNINITIALIZED,
+ INITIALIZING,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ ) {
+ Ok(s) | Err(s) => s,
+ };
+ match old_state {
+ UNINITIALIZED => {
+ unsafe {
+ LOGGER = make_logger();
+ }
+ STATE.store(INITIALIZED, Ordering::SeqCst);
+ Ok(())
+ }
+ INITIALIZING => {
+ while STATE.load(Ordering::SeqCst) == INITIALIZING {
+ // TODO: replace with `hint::spin_loop` once MSRV is 1.49.0.
+ #[allow(deprecated)]
+ std::sync::atomic::spin_loop_hint();
+ }
+ Err(SetLoggerError(()))
+ }
+ _ => Err(SetLoggerError(())),
+ }
+}
+
+/// A thread-unsafe version of [`set_logger`].
+///
+/// This function is available on all platforms, even those that do not have
+/// support for atomics that is needed by [`set_logger`].
+///
+/// In almost all cases, [`set_logger`] should be preferred.
+///
+/// # Safety
+///
+/// This function is only safe to call when no other logger initialization
+/// function is called while this function still executes.
+///
+/// This can be upheld by (for example) making sure that **there are no other
+/// threads**, and (on embedded) that **interrupts are disabled**.
+///
+/// It is safe to use other logging functions while this function runs
+/// (including all logging macros).
+///
+/// [`set_logger`]: fn.set_logger.html
+pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
+ match STATE.load(Ordering::SeqCst) {
+ UNINITIALIZED => {
+ LOGGER = logger;
+ STATE.store(INITIALIZED, Ordering::SeqCst);
+ Ok(())
+ }
+ INITIALIZING => {
+ // This is just plain UB, since we were racing another initialization function
+ unreachable!("set_logger_racy must not be used with other initialization functions")
+ }
+ _ => Err(SetLoggerError(())),
+ }
+}
+
+/// The type returned by [`set_logger`] if [`set_logger`] has already been called.
+///
+/// [`set_logger`]: fn.set_logger.html
+#[allow(missing_copy_implementations)]
+#[derive(Debug)]
+pub struct SetLoggerError(());
+
+impl fmt::Display for SetLoggerError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(SET_LOGGER_ERROR)
+ }
+}
+
+// The Error trait is not available in libcore
+#[cfg(feature = "std")]
+impl error::Error for SetLoggerError {}
+
+/// The type returned by [`from_str`] when the string doesn't match any of the log levels.
+///
+/// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str
+#[allow(missing_copy_implementations)]
+#[derive(Debug, PartialEq, Eq)]
+pub struct ParseLevelError(());
+
+impl fmt::Display for ParseLevelError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(LEVEL_PARSE_ERROR)
+ }
+}
+
+// The Error trait is not available in libcore
+#[cfg(feature = "std")]
+impl error::Error for ParseLevelError {}
+
+/// Returns a reference to the logger.
+///
+/// If a logger has not been set, a no-op implementation is returned.
+pub fn logger() -> &'static dyn Log {
+ if STATE.load(Ordering::SeqCst) != INITIALIZED {
+ static NOP: NopLogger = NopLogger;
+ &NOP
+ } else {
+ unsafe { LOGGER }
+ }
+}
+
+// WARNING: this is not part of the crate's public API and is subject to change at any time
+#[doc(hidden)]
+pub mod __private_api;
+
+/// The statically resolved maximum log level.
+///
+/// See the crate level documentation for information on how to configure this.
+///
+/// This value is checked by the log macros, but not by the `Log`ger returned by
+/// the [`logger`] function. Code that manually calls functions on that value
+/// should compare the level against this value.
+///
+/// [`logger`]: fn.logger.html
+pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL_INNER;
+
+const MAX_LEVEL_INNER: LevelFilter = get_max_level_inner();
+
+const fn get_max_level_inner() -> LevelFilter {
+ #[allow(unreachable_code)]
+ {
+ #[cfg(all(not(debug_assertions), feature = "release_max_level_off"))]
+ {
+ return LevelFilter::Off;
+ }
+ #[cfg(all(not(debug_assertions), feature = "release_max_level_error"))]
+ {
+ return LevelFilter::Error;
+ }
+ #[cfg(all(not(debug_assertions), feature = "release_max_level_warn"))]
+ {
+ return LevelFilter::Warn;
+ }
+ #[cfg(all(not(debug_assertions), feature = "release_max_level_info"))]
+ {
+ return LevelFilter::Info;
+ }
+ #[cfg(all(not(debug_assertions), feature = "release_max_level_debug"))]
+ {
+ return LevelFilter::Debug;
+ }
+ #[cfg(all(not(debug_assertions), feature = "release_max_level_trace"))]
+ {
+ return LevelFilter::Trace;
+ }
+ #[cfg(feature = "max_level_off")]
+ {
+ return LevelFilter::Off;
+ }
+ #[cfg(feature = "max_level_error")]
+ {
+ return LevelFilter::Error;
+ }
+ #[cfg(feature = "max_level_warn")]
+ {
+ return LevelFilter::Warn;
+ }
+ #[cfg(feature = "max_level_info")]
+ {
+ return LevelFilter::Info;
+ }
+ #[cfg(feature = "max_level_debug")]
+ {
+ return LevelFilter::Debug;
+ }
+
+ LevelFilter::Trace
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ extern crate std;
+ use super::{Level, LevelFilter, ParseLevelError};
+ use tests::std::string::ToString;
+
+ #[test]
+ fn test_levelfilter_from_str() {
+ let tests = [
+ ("off", Ok(LevelFilter::Off)),
+ ("error", Ok(LevelFilter::Error)),
+ ("warn", Ok(LevelFilter::Warn)),
+ ("info", Ok(LevelFilter::Info)),
+ ("debug", Ok(LevelFilter::Debug)),
+ ("trace", Ok(LevelFilter::Trace)),
+ ("OFF", Ok(LevelFilter::Off)),
+ ("ERROR", Ok(LevelFilter::Error)),
+ ("WARN", Ok(LevelFilter::Warn)),
+ ("INFO", Ok(LevelFilter::Info)),
+ ("DEBUG", Ok(LevelFilter::Debug)),
+ ("TRACE", Ok(LevelFilter::Trace)),
+ ("asdf", Err(ParseLevelError(()))),
+ ];
+ for &(s, ref expected) in &tests {
+ assert_eq!(expected, &s.parse());
+ }
+ }
+
+ #[test]
+ fn test_level_from_str() {
+ let tests = [
+ ("OFF", Err(ParseLevelError(()))),
+ ("error", Ok(Level::Error)),
+ ("warn", Ok(Level::Warn)),
+ ("info", Ok(Level::Info)),
+ ("debug", Ok(Level::Debug)),
+ ("trace", Ok(Level::Trace)),
+ ("ERROR", Ok(Level::Error)),
+ ("WARN", Ok(Level::Warn)),
+ ("INFO", Ok(Level::Info)),
+ ("DEBUG", Ok(Level::Debug)),
+ ("TRACE", Ok(Level::Trace)),
+ ("asdf", Err(ParseLevelError(()))),
+ ];
+ for &(s, ref expected) in &tests {
+ assert_eq!(expected, &s.parse());
+ }
+ }
+
+ #[test]
+ fn test_level_as_str() {
+ let tests = &[
+ (Level::Error, "ERROR"),
+ (Level::Warn, "WARN"),
+ (Level::Info, "INFO"),
+ (Level::Debug, "DEBUG"),
+ (Level::Trace, "TRACE"),
+ ];
+ for (input, expected) in tests {
+ assert_eq!(*expected, input.as_str());
+ }
+ }
+
+ #[test]
+ fn test_level_show() {
+ assert_eq!("INFO", Level::Info.to_string());
+ assert_eq!("ERROR", Level::Error.to_string());
+ }
+
+ #[test]
+ fn test_levelfilter_show() {
+ assert_eq!("OFF", LevelFilter::Off.to_string());
+ assert_eq!("ERROR", LevelFilter::Error.to_string());
+ }
+
+ #[test]
+ fn test_cross_cmp() {
+ assert!(Level::Debug > LevelFilter::Error);
+ assert!(LevelFilter::Warn < Level::Trace);
+ assert!(LevelFilter::Off < Level::Error);
+ }
+
+ #[test]
+ fn test_cross_eq() {
+ assert!(Level::Error == LevelFilter::Error);
+ assert!(LevelFilter::Off != Level::Error);
+ assert!(Level::Trace == LevelFilter::Trace);
+ }
+
+ #[test]
+ fn test_to_level() {
+ assert_eq!(Some(Level::Error), LevelFilter::Error.to_level());
+ assert_eq!(None, LevelFilter::Off.to_level());
+ assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level());
+ }
+
+ #[test]
+ fn test_to_level_filter() {
+ assert_eq!(LevelFilter::Error, Level::Error.to_level_filter());
+ assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter());
+ }
+
+ #[test]
+ fn test_level_filter_as_str() {
+ let tests = &[
+ (LevelFilter::Off, "OFF"),
+ (LevelFilter::Error, "ERROR"),
+ (LevelFilter::Warn, "WARN"),
+ (LevelFilter::Info, "INFO"),
+ (LevelFilter::Debug, "DEBUG"),
+ (LevelFilter::Trace, "TRACE"),
+ ];
+ for (input, expected) in tests {
+ assert_eq!(*expected, input.as_str());
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn test_error_trait() {
+ use super::SetLoggerError;
+ let e = SetLoggerError(());
+ assert_eq!(
+ &e.to_string(),
+ "attempted to set a logger after the logging system \
+ was already initialized"
+ );
+ }
+
+ #[test]
+ fn test_metadata_builder() {
+ use super::MetadataBuilder;
+ let target = "myApp";
+ let metadata_test = MetadataBuilder::new()
+ .level(Level::Debug)
+ .target(target)
+ .build();
+ assert_eq!(metadata_test.level(), Level::Debug);
+ assert_eq!(metadata_test.target(), "myApp");
+ }
+
+ #[test]
+ fn test_metadata_convenience_builder() {
+ use super::Metadata;
+ let target = "myApp";
+ let metadata_test = Metadata::builder()
+ .level(Level::Debug)
+ .target(target)
+ .build();
+ assert_eq!(metadata_test.level(), Level::Debug);
+ assert_eq!(metadata_test.target(), "myApp");
+ }
+
+ #[test]
+ fn test_record_builder() {
+ use super::{MetadataBuilder, RecordBuilder};
+ let target = "myApp";
+ let metadata = MetadataBuilder::new().target(target).build();
+ let fmt_args = format_args!("hello");
+ let record_test = RecordBuilder::new()
+ .args(fmt_args)
+ .metadata(metadata)
+ .module_path(Some("foo"))
+ .file(Some("bar"))
+ .line(Some(30))
+ .build();
+ assert_eq!(record_test.metadata().target(), "myApp");
+ assert_eq!(record_test.module_path(), Some("foo"));
+ assert_eq!(record_test.file(), Some("bar"));
+ assert_eq!(record_test.line(), Some(30));
+ }
+
+ #[test]
+ fn test_record_convenience_builder() {
+ use super::{Metadata, Record};
+ let target = "myApp";
+ let metadata = Metadata::builder().target(target).build();
+ let fmt_args = format_args!("hello");
+ let record_test = Record::builder()
+ .args(fmt_args)
+ .metadata(metadata)
+ .module_path(Some("foo"))
+ .file(Some("bar"))
+ .line(Some(30))
+ .build();
+ assert_eq!(record_test.target(), "myApp");
+ assert_eq!(record_test.module_path(), Some("foo"));
+ assert_eq!(record_test.file(), Some("bar"));
+ assert_eq!(record_test.line(), Some(30));
+ }
+
+ #[test]
+ fn test_record_complete_builder() {
+ use super::{Level, Record};
+ let target = "myApp";
+ let record_test = Record::builder()
+ .module_path(Some("foo"))
+ .file(Some("bar"))
+ .line(Some(30))
+ .target(target)
+ .level(Level::Error)
+ .build();
+ assert_eq!(record_test.target(), "myApp");
+ assert_eq!(record_test.level(), Level::Error);
+ assert_eq!(record_test.module_path(), Some("foo"));
+ assert_eq!(record_test.file(), Some("bar"));
+ assert_eq!(record_test.line(), Some(30));
+ }
+
+ #[test]
+ #[cfg(feature = "kv_unstable")]
+ fn test_record_key_values_builder() {
+ use super::Record;
+ use kv::{self, Visitor};
+
+ struct TestVisitor {
+ seen_pairs: usize,
+ }
+
+ impl<'kvs> Visitor<'kvs> for TestVisitor {
+ fn visit_pair(
+ &mut self,
+ _: kv::Key<'kvs>,
+ _: kv::Value<'kvs>,
+ ) -> Result<(), kv::Error> {
+ self.seen_pairs += 1;
+ Ok(())
+ }
+ }
+
+ let kvs: &[(&str, i32)] = &[("a", 1), ("b", 2)];
+ let record_test = Record::builder().key_values(&kvs).build();
+
+ let mut visitor = TestVisitor { seen_pairs: 0 };
+
+ record_test.key_values().visit(&mut visitor).unwrap();
+
+ assert_eq!(2, visitor.seen_pairs);
+ }
+
+ #[test]
+ #[cfg(feature = "kv_unstable")]
+ fn test_record_key_values_get_coerce() {
+ use super::Record;
+
+ let kvs: &[(&str, &str)] = &[("a", "1"), ("b", "2")];
+ let record = Record::builder().key_values(&kvs).build();
+
+ assert_eq!(
+ "2",
+ record
+ .key_values()
+ .get("b".into())
+ .expect("missing key")
+ .to_borrowed_str()
+ .expect("invalid value")
+ );
+ }
+
+ // Test that the `impl Log for Foo` blocks work
+ // This test mostly operates on a type level, so failures will be compile errors
+ #[test]
+ fn test_foreign_impl() {
+ use super::Log;
+ #[cfg(feature = "std")]
+ use std::sync::Arc;
+
+ fn assert_is_log<T: Log + ?Sized>() {}
+
+ assert_is_log::<&dyn Log>();
+
+ #[cfg(feature = "std")]
+ assert_is_log::<Box<dyn Log>>();
+
+ #[cfg(feature = "std")]
+ assert_is_log::<Arc<dyn Log>>();
+
+ // Assert these statements for all T: Log + ?Sized
+ #[allow(unused)]
+ fn forall<T: Log + ?Sized>() {
+ #[cfg(feature = "std")]
+ assert_is_log::<Box<T>>();
+
+ assert_is_log::<&T>();
+
+ #[cfg(feature = "std")]
+ assert_is_log::<Arc<T>>();
+ }
+ }
+}