Skip to content

Commit

Permalink
Merge pull request #476 from KodrAus/feat/kv-macros
Browse files Browse the repository at this point in the history
Allow macros to be more consistent with kvs
  • Loading branch information
KodrAus authored Jan 17, 2022
2 parents 8a80388 + 806eb7f commit d5f3c5b
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 59 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ sval = { version = "=1.0.0-alpha.5", optional = true, default-features = false }
value-bag = { version = "=1.0.0-alpha.8", optional = true, default-features = false }

[dev-dependencies]
rustversion = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_test = "1.0"
sval = { version = "=1.0.0-alpha.5", features = ["derive"] }
Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This version is explicitly tested in CI and may be bumped in any release as need

## Usage

## In libraries
### 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:
Expand Down Expand Up @@ -55,7 +55,7 @@ pub fn shave_the_yak(yak: &mut Yak) {
}
```

## In executables
### In executables

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:
Expand Down Expand Up @@ -87,3 +87,28 @@ function to do this. Any log messages generated before the logger is
initialized will be ignored.

The executable itself may use the `log` crate to log as well.

## Structured logging

If you enable the `kv_unstable` feature, you can associate structured data with your log records:

```rust
use log::{info, trace, warn, as_serde, as_error};

pub fn shave_the_yak(yak: &mut Yak) {
trace!(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");
}
}
}
}
```
43 changes: 43 additions & 0 deletions src/kv/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,49 @@ impl<'v> ToValue for Value<'v> {
}
}

/// Get a value from a type implementing `std::fmt::Debug`.
#[macro_export]
macro_rules! as_debug {
($capture:expr) => {
$crate::kv::Value::from_debug(&$capture)
};
}

/// Get a value from a type implementing `std::fmt::Display`.
#[macro_export]
macro_rules! as_display {
($capture:expr) => {
$crate::kv::Value::from_display(&$capture)
};
}

/// Get a value from an error.
#[cfg(feature = "kv_unstable_std")]
#[macro_export]
macro_rules! as_error {
($capture:expr) => {
$crate::kv::Value::from_dyn_error(&$capture)
};
}

#[cfg(feature = "kv_unstable_serde")]
/// Get a value from a type implementing `serde::Serialize`.
#[macro_export]
macro_rules! as_serde {
($capture:expr) => {
$crate::kv::Value::from_serde(&$capture)
};
}

/// Get a value from a type implementing `sval::value::Value`.
#[cfg(feature = "kv_unstable_sval")]
#[macro_export]
macro_rules! as_sval {
($capture:expr) => {
$crate::kv::Value::from_sval(&$capture)
};
}

/// A value in a structured key-value pair.
///
/// # Capturing values
Expand Down
38 changes: 37 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
//! though that default may be overridden. Logger implementations typically use
//! the target to filter requests based on some user configuration.
//!
//! # Use
//! # Usage
//!
//! The basic use of the log crate is through the five logging macros: [`error!`],
//! [`warn!`], [`info!`], [`debug!`] and [`trace!`]
Expand Down Expand Up @@ -86,6 +86,42 @@
//!
//! 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
Expand Down
73 changes: 39 additions & 34 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,20 @@
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
(target: $target:expr, $lvl:expr, $($key:ident = $value:expr),* ; $fmt:expr, $($arg:tt)+) => ({
// log!(target: "my_target", Level::Info; key1 = 42, key2 = true; "a {} event", "log");
(target: $target:expr, $lvl:expr, $($key:ident = $value:expr),+; $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
$crate::__private_api_log(
__log_format_args!($fmt, $($arg)+),
__log_format_args!($($arg)+),
lvl,
&($target, __log_module_path!(), __log_file!(), __log_line!()),
Some(&[$((__log_stringify!($key), &$value)),*])
Some(&[$((__log_stringify!($key), &$value)),+])
);
}
});

// log!(target: "my_target", Level::Info; "a {} event", "log");
(target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
Expand All @@ -51,7 +54,9 @@ macro_rules! log {
);
}
});
($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))

// log!(Level::Info, "a log event")
($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+));
}

/// Logs a message at the error level.
Expand All @@ -70,12 +75,12 @@ macro_rules! log {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Error, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Error, $($arg)+)
)
// error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// error!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Error, $($arg)+));

// error!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Error, $($arg)+))
}

/// Logs a message at the warn level.
Expand All @@ -94,12 +99,12 @@ macro_rules! error {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Warn, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Warn, $($arg)+)
)
// warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// warn!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Warn, $($arg)+));

// warn!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Warn, $($arg)+))
}

/// Logs a message at the info level.
Expand All @@ -120,12 +125,12 @@ macro_rules! warn {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Info, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Info, $($arg)+)
)
// info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// info!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Info, $($arg)+));

// info!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Info, $($arg)+))
}

/// Logs a message at the debug level.
Expand All @@ -145,12 +150,12 @@ macro_rules! info {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Debug, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Debug, $($arg)+)
)
// debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// debug!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Debug, $($arg)+));

// debug!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Debug, $($arg)+))
}

/// Logs a message at the trace level.
Expand All @@ -172,12 +177,12 @@ macro_rules! debug {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Trace, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Trace, $($arg)+)
)
// trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// trace!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Trace, $($arg)+));

// trace!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Trace, $($arg)+))
}

/// Determines if a message logged at the specified level in that module will
Expand Down
3 changes: 3 additions & 0 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ std = ["log/std"]

[dependencies.log]
path = ".."

[dev-dependencies.rustversion]
version = "1.0"
Loading

0 comments on commit d5f3c5b

Please sign in to comment.