// 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)))] externcrate 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")] pubmod 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;
// 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"))] unsafeimpl 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. staticmut 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 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)] pubenum 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,
}
/// Returns the most verbose logging level. #[inline] pubfn max() -> Level {
Level::Trace
}
/// Converts the `Level` to the equivalent `LevelFilter`. #[inline] pubfn to_level_filter(&self) -> LevelFilter {
LevelFilter::from_usize(*selfas usize).unwrap()
}
/// Returns the string representation of the `Level`. /// /// This returns the same string as the `fmt::Display` implementation. pubfn as_str(&self) -> &'static str {
LOG_LEVEL_NAMES[*selfas 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()); /// ``` pubfn 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)] pubenum 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,
}
/// Returns the most verbose logging level filter. #[inline] pubfn max() -> LevelFilter {
LevelFilter::Trace
}
/// Converts `self` to the equivalent `Level`. /// /// Returns `None` if `self` is `LevelFilter::Off`. #[inline] pubfn to_level(&self) -> Option<Level> {
Level::from_usize(*selfas usize)
}
/// Returns the string representation of the `LevelFilter`. /// /// This returns the same string as the `fmt::Display` implementation. pubfn as_str(&self) -> &'static str {
LOG_LEVEL_NAMES[*selfas 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()); /// ``` pubfn iter() -> impl Iterator<Item = Self> {
(0..6).map(|i| Self::from_usize(i).unwrap())
}
}
/// 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)] pubstruct 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);
/// Metadata about the log directive. #[inline] pubfn metadata(&self) -> &Metadata<'a> {
&self.metadata
}
/// The verbosity level of the message. #[inline] pubfn level(&self) -> Level { self.metadata.level()
}
/// The name of the target of the directive. #[inline] pubfn target(&self) -> &'a str { self.metadata.target()
}
/// The module path of the message. #[inline] pubfn 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] pubfn module_path_static(&self) -> Option<&'static str> { matchself.module_path {
Some(MaybeStaticStr::Static(s)) => Some(s),
_ => None,
}
}
/// The source file containing the message. #[inline] pubfn file(&self) -> Option<&'a str> { self.file.map(|s| s.get())
}
/// The module path of the message, if it is a `'static` string. #[inline] pubfn file_static(&self) -> Option<&'static str> { matchself.file {
Some(MaybeStaticStr::Static(s)) => Some(s),
_ => None,
}
}
/// The line containing the message. #[inline] pubfn line(&self) -> Option<u32> { self.line
}
/// The structured key-value pairs associated with the message. #[cfg(feature = "kv_unstable")] #[inline] pubfn 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] pubfn 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)] pubstruct RecordBuilder<'a> {
record: Record<'a>,
}
/// 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)] pubstruct Metadata<'a> {
level: Level,
target: &'a str,
}
impl<'a> Metadata<'a> { /// Returns a new builder. #[inline] pubfn builder() -> MetadataBuilder<'a> {
MetadataBuilder::new()
}
/// The verbosity level of the message. #[inline] pubfn level(&self) -> Level { self.level
}
/// The name of the target of the directive. #[inline] pubfn 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)] pubstruct MetadataBuilder<'a> {
metadata: Metadata<'a>,
}
/// A trait encapsulating the operations required of a logger. pubtrait 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;
/// 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")] pubfn 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] pubunsafefn 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)] pubfn 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"))] pubfn 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")] pubfn 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 pubunsafefn 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)] pubstruct SetLoggerError(());
// 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)] pubstruct ParseLevelError(());
// 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. pubfn 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)] pubmod __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 pubconst STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL_INNER;
#[test] #[cfg(feature = "std")] fn test_error_trait() { usesuper::SetLoggerError; let e = SetLoggerError(());
assert_eq!(
&e.to_string(), "attempted to set a logger after the logging system \
was already initialized"
);
}
// 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() { usesuper::Log; #[cfg(feature = "std")] use std::sync::Arc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.