From ca9f903b1b2fe95c816b1ed81ac040f95ab56e9d Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Tue, 16 Jan 2024 11:08:32 +0100 Subject: [PATCH] Add FilteredLog utility to combine a Filter with a Log. This can be used by end-users that want to combine the filtering capabilities of `env_logger` with a different `Log` implementation. --- src/filter/filtered_log.rs | 69 ++++++++++++++++++++++++++++++++++++++ src/filter/mod.rs | 10 ++++++ 2 files changed, 79 insertions(+) create mode 100644 src/filter/filtered_log.rs diff --git a/src/filter/filtered_log.rs b/src/filter/filtered_log.rs new file mode 100644 index 00000000..41d1835c --- /dev/null +++ b/src/filter/filtered_log.rs @@ -0,0 +1,69 @@ +use super::Filter; +use log::Log; + +/// Wrapper that combines a [`Filter`] with an existing [`log::Log`] implementation. +/// +/// Records that match the filter will be forwarded to the wrapped log. +/// Other records will be ignored. +#[derive(Debug)] +pub struct FilteredLog { + filter: Filter, + log: T, +} + +impl FilteredLog { + /// Create a new filtered log. + pub fn new(filter: Filter, log: T) -> Self { + Self { filter, log } + } + + /// Gets a reference to the filter. + pub fn filter(&self) -> &Filter { + &self.filter + } + + /// Gets a mutable reference to the filter. + pub fn filter_mut(&mut self) -> &mut Filter { + &mut self.filter + } + + /// Gets a reference to the wrapped log. + pub fn inner(&self) -> &T { + &self.log + } + + /// Gets a mutable reference to the wrapped log. + pub fn inner_mut(&mut self) -> &mut T { + &mut self.log + } + + /// Consumes the filtered log to take back ownership of the filter and the wrapped log. + pub fn into_parts(self) -> (Filter, T) { + (self.filter, self.log) + } +} + +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/src/filter/mod.rs b/src/filter/mod.rs index d4acf632..9f3886b4 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -71,6 +71,9 @@ mod inner; #[path = "string.rs"] mod inner; +mod filtered_log; +pub use filtered_log::FilteredLog; + /// A builder for a log filter. /// /// It can be used to parse a set of directives from a string before building @@ -287,6 +290,13 @@ impl Filter { enabled(&self.directives, level, target) } + + /// Wraps an existing [`Log`] implementation with the filter. + /// + /// The returned log forwards all records that match the filter to the wrapped [`Log`] implementation. + pub fn wrap_log(self, log: T) -> FilteredLog { + FilteredLog::new(self, log) + } } impl fmt::Debug for Filter {