Skip to content

Commit

Permalink
start filling in docs and remove capture/downcast value support
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Jan 26, 2024
1 parent 7cb6a01 commit dbc0a3f
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 176 deletions.
2 changes: 1 addition & 1 deletion src/kv/key.rs
Expand Up @@ -30,7 +30,7 @@ impl ToKey for str {
}
}

/// A key in a structured key-value pair.
/// A key in a user-defined attribute.
// These impls must only be based on the as_str() representation of the key
// If a new field (such as an optional index) is added to the key they must not affect comparison
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down
56 changes: 56 additions & 0 deletions src/kv/mod.rs
Expand Up @@ -11,6 +11,62 @@
//! [dependencies.log]
//! features = ["kv_unstable"]
//! ```
//!
//! # Structured logging in `log`
//!
//! Structured logging enhances traditional text-based log records with user-defined
//! attributes. Structured logs can be analyzed using a variety of tranditional
//! data processing techniques, without needing to find and parse attributes from
//! unstructured text first.
//!
//! In `log`, user-defined attributes are part of a [`Source`] on the [`LogRecord`].
//! Each attribute is 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.
//!
//! ## Adding attributes to log records
//!
//! Attributes appear after the message format in the `log!` macros:
//!
//! ```
//! ..
//! ```
//!
//! ## Working with attributes on log records
//!
//! Use the [`LogRecord::source`] method to access user-defined attributes.
//! Individual attributes can be pulled from the source:
//!
//! ```
//! ..
//! ```
//!
//! This is convenient when an attribute of interest is known in advance.
//! All attributes can also be enumerated using a [`Visitor`]:
//!
//! ```
//! ..
//! ```
//!
//! [`Value`]s in attributes have methods for conversions to common types:
//!
//! ```
//! ..
//! ```
//!
//! Values also have their own [`value::Visitor`] type:
//!
//! ```
//! ..
//! ```
//!
//! Visitors on values are lightweight and suitable for detecting primitive types.
//! To serialize a value, you can also use either `serde` or `sval`. If you're
//! in a no-std environment, you can use `sval`. In other cases, you can use `serde`.
//!
//! Values can also always be formatted using the standard `Debug` and `Display`
//! traits.

mod error;
mod key;
Expand Down
26 changes: 17 additions & 9 deletions src/kv/source.rs
@@ -1,23 +1,31 @@
//! Sources for key-value pairs.
//! Sources for user-defined attributes.

use crate::kv::{Error, Key, ToKey, ToValue, Value};
use std::fmt;

/// A source of key-value pairs.
/// A source of user-defined attributes.
///
/// 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.
///
/// # Examples
///
/// Enumerating the attributes in a source:
///
/// ```
/// ..
/// ```
pub trait Source {
/// Visit key-value pairs.
/// Visit attributes.
///
/// A source doesn't have to guarantee any ordering or uniqueness of key-value pairs.
/// A source doesn't have to guarantee any ordering or uniqueness of attributes.
/// If the given visitor returns an error then the source may early-return with it,
/// even if there are more key-value pairs.
/// even if there are more attributes.
///
/// # Implementation notes
///
/// A source should yield the same key-value pairs to a subsequent visitor unless
/// A source should yield the same attributes to a subsequent visitor unless
/// that visitor itself fails.
fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error>;

Expand All @@ -34,14 +42,14 @@ pub trait Source {
get_default(self, key)
}

/// Count the number of key-value pairs that can be visited.
/// Count the number of attributes that can be visited.
///
/// # Implementation notes
///
/// A source that knows the number of key-value pairs upfront may provide a more
/// A source that knows the number of attributes upfront may provide a more
/// efficient implementation.
///
/// A subsequent call to `visit` should yield the same number of key-value pairs
/// A subsequent call to `visit` should yield the same number of attributes
/// to the visitor, unless that visitor fails part way through.
fn count(&self) -> usize {
count_default(self)
Expand Down
172 changes: 6 additions & 166 deletions src/kv/value.rs
Expand Up @@ -29,73 +29,18 @@ 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`.
#[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.
/// A value in a user-defined attribute.
///
/// Values are an anonymous bag containing some structured datum.
///
/// # Capturing values
///
/// There are a few ways to capture a value:
///
/// - Using the `Value::capture_*` methods.
/// - Using the `Value::from_*` methods.
/// - Using the `ToValue` trait.
/// - Using the standard `From` trait.
///
/// ## Using the `Value::capture_*` methods
///
/// `Value` offers a few constructor methods that capture values of different kinds.
/// These methods require a `T: 'static` to support downcasting.
///
/// ```
/// use log::kv::Value;
///
/// let value = Value::capture_debug(&42i32);
///
/// assert_eq!(Some(42), value.to_i64());
/// ```
///
/// ## Using the `Value::from_*` methods
///
/// `Value` offers a few constructor methods that capture values of different kinds.
Expand Down Expand Up @@ -157,59 +102,6 @@ impl<'v> Value<'v> {
value.to_value()
}

/// Get a value from a type implementing `std::fmt::Debug`.
pub fn capture_debug<T>(value: &'v T) -> Self
where
T: fmt::Debug + 'static,
{
Value {
inner: ValueBag::capture_debug(value),
}
}

/// Get a value from a type implementing `std::fmt::Display`.
pub fn capture_display<T>(value: &'v T) -> Self
where
T: fmt::Display + 'static,
{
Value {
inner: ValueBag::capture_display(value),
}
}

/// Get a value from an error.
#[cfg(feature = "kv_unstable_std")]
pub fn capture_error<T>(err: &'v T) -> Self
where
T: std::error::Error + 'static,
{
Value {
inner: ValueBag::capture_error(err),
}
}

#[cfg(feature = "kv_unstable_serde")]
/// Get a value from a type implementing `serde::Serialize`.
pub fn capture_serde<T>(value: &'v T) -> Self
where
T: serde::Serialize + 'static,
{
Value {
inner: ValueBag::capture_serde1(value),
}
}

/// Get a value from a type implementing `sval::Value`.
#[cfg(feature = "kv_unstable_sval")]
pub fn capture_sval<T>(value: &'v T) -> Self
where
T: sval::Value + 'static,
{
Value {
inner: ValueBag::capture_sval2(value),
}
}

/// Get a value from a type implementing `std::fmt::Debug`.
pub fn from_debug<T>(value: &'v T) -> Self
where
Expand Down Expand Up @@ -284,17 +176,10 @@ impl<'v> Value<'v> {
}
}

/// Check whether this value can be downcast to `T`.
pub fn is<T: 'static>(&self) -> bool {
self.inner.is::<T>()
}

/// Try downcast this value to `T`.
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
self.inner.downcast_ref::<T>()
}

/// Inspect this value using a simple visitor.
///
/// When the `kv_unstable_serde` or `kv_unstable_sval` features are enabled, you can also
/// serialize a value using its `Serialize` or `Value` implementation.
pub fn visit(&self, visitor: impl Visit<'v>) -> Result<(), Error> {
struct Visitor<V>(V);

Expand Down Expand Up @@ -824,40 +709,6 @@ pub(crate) mod tests {
vec![Value::from('a'), Value::from('⛰')].into_iter()
}

#[test]
fn test_capture_fmt() {
assert_eq!(Some(42u64), Value::capture_display(&42).to_u64());
assert_eq!(Some(42u64), Value::capture_debug(&42).to_u64());

assert!(Value::from_display(&42).to_u64().is_none());
assert!(Value::from_debug(&42).to_u64().is_none());
}

#[cfg(feature = "kv_unstable_std")]
#[test]
fn test_capture_error() {
let err = std::io::Error::from(std::io::ErrorKind::Other);

assert!(Value::capture_error(&err).to_borrowed_error().is_some());
assert!(Value::from_dyn_error(&err).to_borrowed_error().is_some());
}

#[cfg(feature = "kv_unstable_serde")]
#[test]
fn test_capture_serde() {
assert_eq!(Some(42u64), Value::capture_serde(&42).to_u64());

assert_eq!(Some(42u64), Value::from_serde(&42).to_u64());
}

#[cfg(feature = "kv_unstable_sval")]
#[test]
fn test_capture_sval() {
assert_eq!(Some(42u64), Value::capture_sval(&42).to_u64());

assert_eq!(Some(42u64), Value::from_sval(&42).to_u64());
}

#[test]
fn test_to_value_display() {
assert_eq!(42u64.to_value().to_string(), "42");
Expand Down Expand Up @@ -966,17 +817,6 @@ pub(crate) mod tests {
}
}

#[test]
fn test_downcast_ref() {
#[derive(Debug)]
struct Foo(u64);

let v = Value::capture_debug(&Foo(42));

assert!(v.is::<Foo>());
assert_eq!(42u64, v.downcast_ref::<Foo>().expect("invalid downcast").0);
}

#[test]
fn test_visit_integer() {
struct Extract(Option<u64>);
Expand Down

0 comments on commit dbc0a3f

Please sign in to comment.