From 2d3526001061bacbf4a4c47767a318986c2c61b0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Jan 2024 11:48:20 -0600 Subject: [PATCH] feat(filter): Add a Logger decorator --- crates/env_filter/src/filtered_log.rs | 45 +++++++++++++++++++++++++++ crates/env_filter/src/lib.rs | 39 +++++++++-------------- 2 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 crates/env_filter/src/filtered_log.rs diff --git a/crates/env_filter/src/filtered_log.rs b/crates/env_filter/src/filtered_log.rs new file mode 100644 index 0000000..f707bcc --- /dev/null +++ b/crates/env_filter/src/filtered_log.rs @@ -0,0 +1,45 @@ +use log::Log; + +use crate::Filter; + +/// Decorate a [`log::Log`] with record [`Filter`]ing. +/// +/// Records that match the filter will be forwarded to the wrapped log. +/// Other records will be ignored. +#[derive(Debug)] +pub struct FilteredLog { + log: T, + filter: Filter, +} + +impl FilteredLog { + /// Create a new filtered log. + pub fn new(log: T, filter: Filter) -> Self { + Self { log, filter } + } +} + +impl Log for FilteredLog { + /// Determines if a log message with the specified metadata would be logged. + /// + /// For the wrapped log, this returns `true` only if both the filter and the wrapped log return `true`. + fn enabled(&self, metadata: &log::Metadata) -> bool { + self.filter.enabled(metadata) && self.log.enabled(metadata) + } + + /// Logs the record. + /// + /// Forwards the record to the wrapped log, but only if the record matches the filter. + fn log(&self, record: &log::Record) { + if self.filter.matches(record) { + self.log.log(record) + } + } + + /// Flushes any buffered records. + /// + /// Forwards directly to the wrapped log. + fn flush(&self) { + self.log.flush() + } +} diff --git a/crates/env_filter/src/lib.rs b/crates/env_filter/src/lib.rs index 494b82d..dad0681 100644 --- a/crates/env_filter/src/lib.rs +++ b/crates/env_filter/src/lib.rs @@ -14,44 +14,32 @@ //! use env_filter::Filter; //! use log::{Log, Metadata, Record}; //! -//! struct MyLogger { -//! filter: Filter -//! } -//! -//! impl MyLogger { -//! fn new() -> MyLogger { -//! use env_filter::Builder; -//! let mut builder = Builder::new(); -//! -//! // Parse a directives string from an environment variable -//! if let Ok(ref filter) = std::env::var("MY_LOG_LEVEL") { -//! builder.parse(filter); -//! } +//! struct PrintLogger; //! -//! MyLogger { -//! filter: builder.build() -//! } -//! } -//! } -//! -//! impl Log for MyLogger { +//! impl Log for PrintLogger { //! fn enabled(&self, metadata: &Metadata) -> bool { -//! self.filter.enabled(metadata) +//! true //! } //! //! fn log(&self, record: &Record) { -//! // Check if the record is matched by the filter -//! if self.filter.matches(record) { -//! println!("{:?}", record); -//! } +//! println!("{:?}", record); //! } //! //! fn flush(&self) {} //! } +//! +//! let mut builder = env_filter::Builder::new(); +//! // Parse a directives string from an environment variable +//! if let Ok(ref filter) = std::env::var("MY_LOG_LEVEL") { +//! builder.parse(filter); +//! } +//! +//! let logger = env_filter::FilteredLog::new(PrintLogger, builder.build()); //! ``` mod directive; mod filter; +mod filtered_log; mod op; mod parser; @@ -62,3 +50,4 @@ use parser::parse_spec; pub use filter::Builder; pub use filter::Filter; +pub use filtered_log::FilteredLog;