Skip to content

Commit

Permalink
work on macro support for capturing
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Feb 13, 2024
1 parent 05119e1 commit 0374a25
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 69 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ The executable itself may use the `log` crate to log as well.
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};
use log::{info, trace, warn};

pub fn shave_the_yak(yak: &mut Yak) {
trace!(target = "yak_events", yak = as_serde!(yak); "Commencing yak shaving");
trace!(target = "yak_events", yak:serde = yak; "Commencing yak shaving");

loop {
match find_a_razor() {
Expand All @@ -116,7 +116,7 @@ pub fn shave_the_yak(yak: &mut Yak) {
break;
}
Err(err) => {
warn!(err = as_error!(err); "Unable to locate a razor, retrying");
warn!(err:error = err; "Unable to locate a razor, retrying");
}
}
}
Expand Down
54 changes: 45 additions & 9 deletions src/__private_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,28 @@ use crate::{Level, Metadata, Record};
use std::fmt::Arguments;
pub use std::{file, format_args, line, module_path, stringify};

#[cfg(feature = "kv_unstable")]
pub type Value<'a> = dyn crate::kv::value::ToValue + 'a;

#[cfg(not(feature = "kv_unstable"))]
pub type Value<'a> = str;
pub type Value<'a> = &'a str;

mod sealed {
/// Types for the `kv` argument.
pub trait KVs<'a> {
fn into_kvs(self) -> Option<&'a [(&'a str, &'a super::Value<'a>)]>;
fn into_kvs(self) -> Option<&'a [(&'a str, super::Value<'a>)]>;
}
}

// Types for the `kv` argument.

impl<'a> KVs<'a> for &'a [(&'a str, &'a Value<'a>)] {
impl<'a> KVs<'a> for &'a [(&'a str, Value<'a>)] {
#[inline]
fn into_kvs(self) -> Option<&'a [(&'a str, &'a Value<'a>)]> {
fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> {
Some(self)
}
}

impl<'a> KVs<'a> for () {
#[inline]
fn into_kvs(self) -> Option<&'a [(&'a str, &'a Value<'a>)]> {
fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> {
None
}
}
Expand All @@ -41,7 +38,7 @@ fn log_impl(
level: Level,
&(target, module_path, file): &(&str, &'static str, &'static str),
line: u32,
kvs: Option<&[(&str, &Value)]>,
kvs: Option<&[(&str, Value)]>,
) {
#[cfg(not(feature = "kv_unstable"))]
if kvs.is_some() {
Expand Down Expand Up @@ -87,3 +84,42 @@ pub fn log<'a, K>(
pub fn enabled(level: Level, target: &str) -> bool {
crate::logger().enabled(&Metadata::builder().level(level).target(target).build())
}

#[cfg(feature = "kv_unstable")]
mod kv_support {
use super::*;

use crate::kv;

pub type Value<'a> = kv::Value<'a>;

pub fn capture_to_value<'a, V: kv::value::ToValue + ?Sized>(v: &'a &'a V) -> Value<'a> {
v.to_value()
}

pub fn capture_debug<'a, V: core::fmt::Debug + ?Sized>(v: &'a &'a V) -> Value<'a> {
Value::from_debug(v)
}

pub fn capture_display<'a, V: core::fmt::Display + ?Sized>(v: &'a &'a V) -> Value<'a> {
Value::from_display(v)
}

#[cfg(feature = "kv_unstable_std")]
pub fn capture_error<'a>(v: &'a (dyn std::error::Error + 'static)) -> Value<'a> {
Value::from_dyn_error(v)
}

#[cfg(feature = "kv_unstable_sval")]
pub fn capture_sval<'a, V: sval::Value + ?Sized>(v: &'a &'a V) -> Value<'a> {
Value::from_sval(v)
}

#[cfg(feature = "kv_unstable_serde")]
pub fn capture_serde<'a, V: serde::Serialize + ?Sized>(v: &'a &'a V) -> Value<'a> {
Value::from_serde(v)
}
}

#[cfg(feature = "kv_unstable")]
pub use self::kv_support::*;
58 changes: 29 additions & 29 deletions src/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
//! unstructured text first.
//!
//! In `log`, user-defined attributes are part of a [`Source`] on the log record.
//! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings
//! and values are a datum of any type that can be formatted or serialized. Simple types
//! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings
//! and values are a datum of any type that can be formatted or serialized. Simple types
//! like strings, booleans, and numbers are supported, as well as arbitrarily complex
//! structures involving nested objects and sequences.
//!
Expand All @@ -36,14 +36,14 @@
//! ## Working with key-values on log records
//!
//! Use the [`LogRecord::key_values`] method to access key-values.
//!
//!
//! Individual values can be pulled from the source by their key:
//!
//! ```
//! # fn main() -> Result<(), log::kv::Error> {
//! use log::kv::{Source, Key, Value};
//! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
//!
//!
//! // info!("Something of interest"; a = 1);
//! let a: Value = record.key_values().get(Key::from("a")).unwrap();
//! # Ok(())
Expand All @@ -56,28 +56,28 @@
//! # fn main() -> Result<(), log::kv::Error> {
//! # let record = log::Record::builder().key_values(&[("a", 1), ("b", 2), ("c", 3)]).build();
//! use std::collections::BTreeMap;
//!
//!
//! use log::kv::{self, Source, Key, Value, source::Visitor};
//!
//!
//! struct Collect<'kvs>(BTreeMap<Key<'kvs>, Value<'kvs>>);
//!
//!
//! impl<'kvs> Visitor<'kvs> for Collect<'kvs> {
//! fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> {
//! self.0.insert(key, value);
//!
//!
//! Ok(())
//! }
//! }
//!
//!
//! let mut visitor = Collect(BTreeMap::new());
//!
//!
//! // info!("Something of interest"; a = 1, b = 2, c = 3);
//! record.key_values().visit(&mut visitor)?;
//!
//!
//! let collected = visitor.0;
//!
//!
//! assert_eq!(
//! vec!["a", "b", "c"],
//! vec!["a", "b", "c"],
//! collected
//! .keys()
//! .map(|k| k.as_str())
Expand All @@ -93,10 +93,10 @@
//! # fn main() -> Result<(), log::kv::Error> {
//! use log::kv::{Source, Key};
//! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
//!
//!
//! // info!("Something of interest"; a = 1);
//! let a = record.key_values().get(Key::from("a")).unwrap();
//!
//!
//! assert_eq!(1, a.to_i64().unwrap());
//! # Ok(())
//! # }
Expand All @@ -109,9 +109,9 @@
//! # fn main() -> Result<(), log::kv::Error> {
//! use log::kv::{self, Source, Key, value::Visitor};
//! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
//!
//!
//! struct IsNumeric(bool);
//!
//!
//! impl<'kvs> Visitor<'kvs> for IsNumeric {
//! fn visit_any(&mut self, _value: kv::Value) -> Result<(), kv::Error> {
//! self.0 = false;
Expand Down Expand Up @@ -143,23 +143,23 @@
//! Ok(())
//! }
//! }
//!
//!
//! // info!("Something of interest"; a = 1);
//! let a = record.key_values().get(Key::from("a")).unwrap();
//!
//!
//! let mut visitor = IsNumeric(false);
//!
//!
//! a.visit(&mut visitor)?;
//!
//!
//! let is_numeric = visitor.0;
//!
//!
//! assert!(is_numeric);
//! # Ok(())
//! # }
//! ```
//!
//! To serialize a value to a format like JSON, you can also use either `serde` or `sval`:
//!
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[cfg(feature = "serde")]
Expand All @@ -169,16 +169,16 @@
//! let data = Data { a: 1, b: true, c: "Some data" };
//! # let source = [("a", log::kv::Value::from_serde(&data))];
//! # let record = log::Record::builder().key_values(&source).build();
//!
//!
//! // info!("Something of interest"; a = data);
//! let a = record.key_values().get(Key::from("a")).unwrap();
//!
//!
//! assert_eq!("{\"a\":1,\"b\":true,\"c\":\"Some data\"}", serde_json::to_string(&a)?);
//! # }
//! # Ok(())
//! # }
//! ```
//!
//!
//! The choice of serialization framework depends on the needs of the consumer.
//! If you're in a no-std environment, you can use `sval`. In other cases, you can use `serde`.
//! Log producers and log consumers don't need to agree on the serialization framework.
Expand All @@ -187,17 +187,17 @@
//!
//! Values can also always be formatted using the standard `Debug` and `Display`
//! traits:
//!
//!
//! ```
//! # use log::kv::Key;
//! # #[derive(Debug)] struct Data { a: i32, b: bool, c: &'static str }
//! let data = Data { a: 1, b: true, c: "Some data" };
//! # let source = [("a", log::kv::Value::from_debug(&data))];
//! # let record = log::Record::builder().key_values(&source).build();
//!
//!
//! // info!("Something of interest"; a = data);
//! let a = record.key_values().get(Key::from("a")).unwrap();
//!
//!
//! assert_eq!("Data { a: 1, b: true, c: \"Some data\" }", format!("{a:?}"));
//! ```

Expand Down
14 changes: 7 additions & 7 deletions src/kv/source.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Sources for key-values.
//!
//!
//! This module defines the [`Source`] type and supporting APIs for
//! working with collections of key-values.

Expand All @@ -11,7 +11,7 @@ use std::fmt;
/// The source may be a single pair, a set of pairs, or a filter over a set of pairs.
/// Use the [`Visitor`](trait.Visitor.html) trait to inspect the structured data
/// in a source.
///
///
/// A source is like an iterator over its key-values, except with a push-based API
/// instead of a pull-based one.
///
Expand All @@ -22,27 +22,27 @@ use std::fmt;
/// ```
/// # fn main() -> Result<(), log::kv::Error> {
/// use log::kv::{self, Source, Key, Value, source::Visitor};
///
///
/// // A `Visitor` that prints all key-values
/// // Visitors are fed the key-value pairs of each key-values
/// struct Printer;
///
///
/// impl<'kvs> Visitor<'kvs> for Printer {
/// fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> {
/// println!("{key}: {value}");
///
///
/// Ok(())
/// }
/// }
///
///
/// // A source with 3 key-values
/// // Common collection types implement the `Source` trait
/// let source = &[
/// ("a", 1),
/// ("b", 2),
/// ("c", 3),
/// ];
///
///
/// // Pass an instance of the `Visitor` to a `Source` to visit it
/// source.visit(&mut Printer)?;
/// # Ok(())
Expand Down
Loading

0 comments on commit 0374a25

Please sign in to comment.