Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pub "-v" macros for inline expression logging #316

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ features = ["std", "serde"]
name = "filters"
harness = false

[[test]]
name = "log_v"
harness = false

[features]
max_level_off = []
max_level_error = []
Expand Down
208 changes: 158 additions & 50 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,152 @@
//! 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.
//! If no logging implementation is selected, the facade falls back to a
//! _no-op_ implementation that ignores all log messages. The overhead in this
//! case is very smalljust 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.
//! A log `Record` includes a target, level, and message body. Logger
//! implementations typically use the target and level to filter records,
//! based on user configuration.
//!
//! # Use
//! ## Logging macros
//!
//! 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!`].
//! The `log` crate is primarly used through logging [macros](#macros). These
//! include formatted logging macros for each of the supported levels, from
//! highest to lowest priority: `error!`, `warn!`, `info!`, `debug!` and
//! `trace!`. There is an additional set of “_-v_” suffix macros
//! (e.g. `debugv!`) that provide _inline expression and value_ logging. Both
//! sets of macros are described below, with examples using arbitrary log
//! levels.
//!
//! ### Formatted logging
//!
//! [`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
//! The formatted logging macros require a literal format string, supporting
//! the same syntax as `println!`, via [`std::fmt`]:
//!
//! ## In libraries
//! ```rust
//! # #[macro_use] extern crate log;
//! # fn main() {
//! info!("Landing gear retracted");
//! let altitude = 3000;
//! let target = 10500;
//! debug!("Altitude target: {}, current: {}", target, altitude);
//! # }
//! ```
//!
//! If for example, the configured maximum logging level is `Info`, then the
//! above `debug!` statement does not log, and the cost of formatting the
//! message string is avoided.
//!
//! ### Testing for output
//!
//! The [`log_enabled!`](macro.log_enabled.html) macro may be used to
//! explicitly test if logging is enabled, and may be useful to avoid
//! expensive computations used only for logging.
//!
//! ```rust
//! # #[macro_use] extern crate log;
//! # struct Foo;
//! # impl Foo {
//! # fn volume(&self) -> f32 { 0.1 }
//! # fn mass(&self) -> f32 { 0.2 }
//! # }
//! # fn analyze(a: u32) -> Foo { Foo }
//! use log::Level::Debug;
//! # fn main() {
//!
//! # let asteroid = 1;
//! if log_enabled!(Debug) {
//! let e = analyze(asteroid); // expensive!
//! debug!("Asteroid volume: {}, mass: {}", e.volume(), e.mass());
//! }
//! # }
//! ```
//!
//! ### Inline expression and value logging
//!
//! The _-v_ macros support inline expression and value logging, as a superset
//! of the [`std::dbg!`] macro, for use with the logging system. A _single_
//! expression argument is evaluated exactly once, regardless of if the
//! logging level is enabled, and its value is returned from the macro. Given
//! this code as a starting point:
//!
//! ```rust
//! use std::time::{Duration, Instant};
//! # fn main() {
//! # let deadline = Instant::now() + Duration::new(0, 950_000);
//!
//! let remaining = deadline - Instant::now();
//! # }
//! ```
//!
//! A _-v_ macro may be inserted inline around any expression or
//! sub-expression:
//!
//! ```rust
//! # #[macro_use] extern crate log;
//! use std::time::{Duration, Instant};
//! # fn main() {
//! # let deadline = Instant::now() + Duration::new(0, 950_000);
//!
//! Libraries should link only to the `log` crate, and use the provided
//! macros to log whatever information will be useful to downstream consumers.
//! let remaining = debugv!(deadline - Instant::now());
//! // ^-- debug log: deadline - Instant::now() → 950µs
//! debugv!(remaining);
//! // or ^-- debug log: remaining → 950µs
//! # }
//! ```
//!
//! Note that the value of the expression is moved and then returned. If the
//! type does not implement `Copy`, ownership may be retained by borrowing by
//! reference, e.g. `debugv!(&expr)`.
//!
//! The _default_ format string for the _-v_ macros is `"{} → {:?}"`, where
//! the `stringify!`-ed expression and resulting value are passed, in that
//! order. If the log record is not filtered out, the `Debug` implementation
//! for the type of the given expression value is used (`{:?}`). A custom
//! format string can _also_ be passed to the _-v_ macros, for more flexible
//! output:
//!
//! ```rust
//! # #[macro_use] extern crate log;
//! # fn main() {
//! let i = 32;
//! infov!("{} → {}", i); // use `Display` instead of `Debug`
//! infov!("{} → {:#x}", i); // hexadecimal format value
//! infov!("{} → {:#?}", i); // use pretty, multi-line format
//! infov!("index {1:5?} ({0})", i); // prefix, value first with padding
//! # }
//! ```
//!
//! ### Specifying the logging target
//!
//! For _all_ logging macros, the _target_ defaults to the module path of the
//! current location of use, but may be overridden with the `target:` marker
//! and string literal as the first argument:
//!
//! ```rust
//! # #[macro_use] extern crate log;
//! # fn stats() -> i32 { 33 }
//! # fn main() {
//! use log::Level::Info;
//!
//! let i = 33;
//! let j = warnv!(target: "maths", (i-1) / 2);
//! assert_eq!(j, 16);
//!
//! if log_enabled!(target: "special", Info) {
//! info!(target: "special", "{}", stats());
//! }
//! # }
//! ```
//!
//! [`std::fmt`]: https://doc.rust-lang.org/stable/std/fmt/index.html
//! [`std::dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
//!
//! ## Use 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
//!
Expand Down Expand Up @@ -75,25 +191,22 @@
//! # 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.
//! ## Use in executables
//!
//! The executable itself may use the `log` crate to log as well.
//! 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.
//!
//! ### Warning
//! _Warning_: The logging system may only be initialized once.
//!
//! The logging system may only be initialized once.
//! The executable may also use the `log` crate to log.
//!
//! # Available logging implementations
//! ### 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:
//! 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]
Expand All @@ -109,7 +222,7 @@
//! * [syslog]
//! * [slog-stdlog]
//!
//! # Implementing a Logger
//! ### 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
Expand Down Expand Up @@ -173,7 +286,7 @@
//! Implementations that adjust their configurations at runtime should take care
//! to adjust the maximum log level as well.
//!
//! # Use with `std`
//! ### 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
Expand Down Expand Up @@ -220,7 +333,7 @@
//!
//! 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.
//!
Expand Down Expand Up @@ -679,7 +792,8 @@ impl LevelFilter {
/// `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.
/// created by the various logging macros and so are not typically seen
/// directly by `log` users.
///
/// Note that the [`level()`] and [`target()`] accessors are equivalent to
/// `self.metadata().level()` and `self.metadata().target()` respectively.
Expand Down Expand Up @@ -1073,16 +1187,10 @@ pub fn set_max_level(level: LevelFilter) {

/// 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.
/// The logging 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 {
Expand Down
Loading