Skip to content

Commit

Permalink
Add FilteredLog utility to combine a Filter with a Log.
Browse files Browse the repository at this point in the history
This can be used by end-users that want to combine the filtering
capabilities of `env_logger` with a different `Log` implementation.
  • Loading branch information
de-vri-es committed Jan 16, 2024
1 parent 7bc51b0 commit ca9f903
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/filter/filtered_log.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
filter: Filter,
log: T,
}

impl<T: Log> FilteredLog<T> {
/// 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<T: Log> Log for FilteredLog<T> {
/// 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()
}
}
10 changes: 10 additions & 0 deletions src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<T: log::Log>(self, log: T) -> FilteredLog<T> {
FilteredLog::new(self, log)
}
}

impl fmt::Debug for Filter {
Expand Down

0 comments on commit ca9f903

Please sign in to comment.