Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FilteredLog utility to combine a Filter with a Log. #295

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 5 additions & 66 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,67 +1,6 @@
[package]
name = "env_logger"
version = "0.10.1"
description = """
A logging implementation for `log` which is configured via an environment
variable.
"""
repository = "https://github.com/rust-cli/env_logger"
categories = ["development-tools::debugging"]
keywords = ["logging", "log", "logger"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.60.0" # MSRV
include = [
"build.rs",
"src/**/*",
"Cargo.toml",
"Cargo.lock",
"LICENSE*",
"README.md",
"benches/**/*",
"examples/**/*",
"tests/**/*",
[workspace]
resolver = "2"
members = [
"env_filter",
"env_logger",
]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[package.metadata.release]
pre-release-replacements = [
{file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1},
{file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1},
{file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1},
{file="CHANGELOG.md", search="<!-- next-header -->", replace="<!-- next-header -->\n## [Unreleased] - ReleaseDate\n", exactly=1},
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/rust-cli/env_logger/compare/{{tag_name}}...HEAD", exactly=1},
]

[features]
default = ["auto-color", "humantime", "regex"]
color = ["dep:termcolor"]
auto-color = ["dep:is-terminal", "color"]
humantime = ["dep:humantime"]
regex = ["dep:regex"]

[dependencies]
log = { version = "0.4.8", features = ["std"] }
regex = { version = "1.0.3", optional = true, default-features=false, features=["std", "perf"] }
termcolor = { version = "1.1.1", optional = true }
humantime = { version = "2.0.0", optional = true }
is-terminal = { version = "0.4.0", optional = true }

[[test]]
name = "regexp_filter"
harness = false

[[test]]
name = "log-in-log"
harness = false

[[test]]
name = "log_tls_dtors"
harness = false

[[test]]
name = "init-twice-retains-filter"
harness = false
45 changes: 45 additions & 0 deletions env_filter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
name = "env_filter"
version = "0.10.1"
description = """
A log filtering implementation for `log` which is configured via an environment
variable.
"""
repository = "https://github.com/rust-cli/env_logger"
categories = ["development-tools::debugging"]
keywords = ["logging", "log", "logger"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.60.0" # MSRV
include = [
"build.rs",
"src/**/*",
"Cargo.toml",
"Cargo.lock",
"LICENSE*",
"README.md",
"benches/**/*",
"examples/**/*",
"tests/**/*",
]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[package.metadata.release]
pre-release-replacements = [
{file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1},
{file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1},
{file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1},
{file="CHANGELOG.md", search="<!-- next-header -->", replace="<!-- next-header -->\n## [Unreleased] - ReleaseDate\n", exactly=1},
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/rust-cli/env_logger/compare/{{tag_name}}...HEAD", exactly=1},
]

[features]
default = ["regex"]
regex = ["dep:regex"]

[dependencies]
log = { version = "0.4.8", features = ["std"] }
regex = { version = "1.0.3", optional = true, default-features=false, features=["std", "perf"] }
1 change: 1 addition & 0 deletions env_filter/LICENSE-APACHE
1 change: 1 addition & 0 deletions env_filter/LICENSE-MIT
69 changes: 69 additions & 0 deletions env_filter/src/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()
}
}
37 changes: 18 additions & 19 deletions src/filter/mod.rs → env_filter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
//! Filtering for log records.
//!
//! This module contains the log filtering used by `env_logger` to match records.
//! This crate contains the log filtering used by `env_logger` to match records.
//! You can use the `Filter` type in your own logger implementation to use the same
//! filter parsing and matching as `env_logger`. For more details about the format
//! for directive strings see [Enabling Logging].
//!
//! ## Using `env_logger` in your own logger
//! ## Using `env_filter` in your own logger
//!
//! You can use `env_logger`'s filtering functionality with your own logger.
//! You can use `env_filter`'s filtering functionality with your own logger.
//! Call [`Builder::parse`] to parse directives from a string when constructing
//! your logger. Call [`Filter::matches`] to check whether a record should be
//! logged based on the parsed filters when log records are received.
//!
//! ```
//! extern crate log;
//! extern crate env_logger;
//! use env_logger::filter::Filter;
//! use log::{Log, Metadata, Record};
//!
//! struct MyLogger {
//! filter: Filter
//! filter: env_filter::Filter
//! }
//!
//! impl MyLogger {
//! fn new() -> MyLogger {
//! use env_logger::filter::Builder;
//! let mut builder = Builder::new();
//! 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") {
Expand Down Expand Up @@ -55,8 +51,6 @@
//! ```
//!
//! [Enabling Logging]: ../index.html#enabling-logging
//! [`Builder::parse`]: struct.Builder.html#method.parse
//! [`Filter::matches`]: struct.Filter.html#method.matches

use log::{Level, LevelFilter, Metadata, Record};
use std::env;
Expand All @@ -71,6 +65,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 All @@ -79,14 +76,10 @@ mod inner;
/// ## Example
///
/// ```
/// # #[macro_use] extern crate log;
/// # use std::env;
/// use env_logger::filter::Builder;
///
/// let mut builder = Builder::new();
/// let mut builder = env_filter::Builder::new();
///
/// // Parse a logging filter from an environment variable.
/// if let Ok(rust_log) = env::var("RUST_LOG") {
/// if let Ok(rust_log) = std::env::var("RUST_LOG") {
/// builder.parse(&rust_log);
/// }
///
Expand Down Expand Up @@ -248,9 +241,8 @@ impl Filter {
///
/// ```rust
/// use log::LevelFilter;
/// use env_logger::filter::Builder;
///
/// let mut builder = Builder::new();
/// let mut builder = env_filter::Builder::new();
/// builder.filter(Some("module1"), LevelFilter::Info);
/// builder.filter(Some("module2"), LevelFilter::Error);
///
Expand Down Expand Up @@ -287,6 +279,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
5 changes: 1 addition & 4 deletions src/filter/regex.rs → env_filter/src/regex.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
extern crate regex;

use regex::Regex;
use std::fmt;

use self::regex::Regex;

#[derive(Debug)]
pub struct Filter {
inner: Regex,
Expand Down
File renamed without changes.
File renamed without changes.
67 changes: 67 additions & 0 deletions env_logger/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[package]
name = "env_logger"
version = "0.10.1"
description = """
A logging implementation for `log` which is configured via an environment
variable.
"""
repository = "https://github.com/rust-cli/env_logger"
categories = ["development-tools::debugging"]
keywords = ["logging", "log", "logger"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.60.0" # MSRV
include = [
"build.rs",
"src/**/*",
"Cargo.toml",
"Cargo.lock",
"LICENSE*",
"README.md",
"benches/**/*",
"examples/**/*",
"tests/**/*",
]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[package.metadata.release]
pre-release-replacements = [
{file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1},
{file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1},
{file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1},
{file="CHANGELOG.md", search="<!-- next-header -->", replace="<!-- next-header -->\n## [Unreleased] - ReleaseDate\n", exactly=1},
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/rust-cli/env_logger/compare/{{tag_name}}...HEAD", exactly=1},
]

[features]
default = ["auto-color", "humantime", "regex"]
color = ["dep:termcolor"]
auto-color = ["dep:is-terminal", "color"]
humantime = ["dep:humantime"]
regex = ["env_filter/regex"]

[dependencies]
env_filter = { version = "0.10.1", path = "../env_filter", default-features=false }
log = { version = "0.4.8", features = ["std"] }
termcolor = { version = "1.1.1", optional = true }
humantime = { version = "2.0.0", optional = true }
is-terminal = { version = "0.4.0", optional = true }

[[test]]
name = "regexp_filter"
harness = false

[[test]]
name = "log-in-log"
harness = false

[[test]]
name = "log_tls_dtors"
harness = false

[[test]]
name = "init-twice-retains-filter"
harness = false
1 change: 1 addition & 0 deletions env_logger/LICENSE-APACHE
Loading