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

Trace static level filtering #987

Merged
merged 16 commits into from
Mar 25, 2019
Merged
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
1 change: 1 addition & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ task:
test_script:
- . $HOME/.cargo/env
- cargo test --all --no-fail-fast
- (cd tokio-trace/test_static_max_level_features && cargo test)
- cargo doc --all
i686_test_script:
- . $HOME/.cargo/env
Expand Down
1 change: 1 addition & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
- tokio-timer
- tokio-trace
- tokio-trace/tokio-trace-core
- tokio-trace/test_static_max_level_features

- template: ci/azure-cargo-check.yml
parameters:
Expand Down
16 changes: 16 additions & 0 deletions tokio-trace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,29 @@ publish = false

[dependencies]
tokio-trace-core = "0.1"
cfg-if = "0.1.7"

[dev-dependencies]
ansi_term = "0.11"
humantime = "1.1.1"
futures = "0.1"
log = "0.4"

[features]
max_level_off = []
max_level_error = []
max_level_warn = []
max_level_info = []
max_level_debug = []
max_level_trace = []

release_max_level_off = []
release_max_level_error = []
release_max_level_warn = []
release_max_level_info = []
release_max_level_debug = []
release_max_level_trace = []

# These are used for the "basic" example from the tokio-trace-prototype repo,
# which is currently not included as it used the `tokio-trace-log` crate, and
# that crate is currently unstable.
Expand Down
88 changes: 88 additions & 0 deletions tokio-trace/src/level_filters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::cmp::Ordering;
use tokio_trace_core::Level;

/// `LevelFilter` is used to statistically filter the logging messages based on its `Level`.
/// Logging messages will be discarded if its `Level` is greater than `LevelFilter`.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct LevelFilter(Option<Level>);

impl LevelFilter {
/// The "off" level.
///
/// Designates that logging should be to turned off.
pub const OFF: LevelFilter = LevelFilter(None);
/// The "error" level.
///
/// Designates very serious errors.
pub const ERROR: LevelFilter = LevelFilter(Some(Level::ERROR));
/// The "warn" level.
///
/// Designates hazardous situations.
pub const WARN: LevelFilter = LevelFilter(Some(Level::WARN));
/// The "info" level.
///
/// Designates useful information.
pub const INFO: LevelFilter = LevelFilter(Some(Level::INFO));
/// The "debug" level.
///
/// Designates lower priority information.
pub const DEBUG: LevelFilter = LevelFilter(Some(Level::DEBUG));
/// The "trace" level.
///
/// Designates very low priority, often extremely verbose, information.
pub const TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
}

impl PartialEq<LevelFilter> for Level {
hawkw marked this conversation as resolved.
Show resolved Hide resolved
fn eq(&self, other: &LevelFilter) -> bool {
match other.0 {
None => false,
Some(ref level) => self.eq(level),
}
}
}

impl PartialOrd<LevelFilter> for Level {
fn partial_cmp(&self, other: &LevelFilter) -> Option<Ordering> {
match other.0 {
None => Some(Ordering::Less),
Some(ref level) => self.partial_cmp(level),
}
}
}

/// The statically resolved maximum trace level.
///
/// See the crate level documentation for information on how to configure this.
///
/// This value is checked by the `event` macro. Code that manually calls functions on that value
/// should compare the level against this value.
pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL;

cfg_if! {
if #[cfg(all(not(debug_assertions), feature = "release_max_level_off"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::OFF;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_error"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::ERROR;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_warn"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::WARN;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_info"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_debug"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
} else if #[cfg(all(not(debug_assertions), feature = "release_max_level_trace"))] {
const MAX_LEVEL: LevelFilter = LevelFilter::TRACE;
} else if #[cfg(feature = "max_level_off")] {
const MAX_LEVEL: LevelFilter = LevelFilter::OFF;
} else if #[cfg(feature = "max_level_error")] {
const MAX_LEVEL: LevelFilter = LevelFilter::ERROR;
} else if #[cfg(feature = "max_level_warn")] {
const MAX_LEVEL: LevelFilter = LevelFilter::WARN;
} else if #[cfg(feature = "max_level_info")] {
const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
} else if #[cfg(feature = "max_level_debug")] {
const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
} else {
const MAX_LEVEL: LevelFilter = LevelFilter::TRACE;
}
}
3 changes: 3 additions & 0 deletions tokio-trace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@
//! [`tokio-trace-futures`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-futures
//! [`tokio-trace-fmt`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-fmt
//! [`tokio-trace-log`]: https://github.com/tokio-rs/tokio-trace-nursery/tree/master/tokio-trace-log
#[macro_use]
extern crate cfg_if;
extern crate tokio_trace_core;

// Somehow this `use` statement is necessary for us to re-export the `core`
Expand Down Expand Up @@ -339,6 +341,7 @@ pub use self::{
mod macros;

pub mod field;
pub mod level_filters;
pub mod span;
pub mod subscriber;

Expand Down
10 changes: 7 additions & 3 deletions tokio-trace/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ macro_rules! span {
$name:expr,
$($k:ident $( = $val:expr )* ),*
) => {
{
if $lvl <= $crate::level_filters::STATIC_MAX_LEVEL {
use $crate::callsite;
use $crate::callsite::Callsite;
let callsite = callsite! {
Expand All @@ -120,6 +120,8 @@ macro_rules! span {
} else {
$crate::Span::new_disabled()
}
} else {
$crate::Span::new_disabled()
}
};
(
Expand All @@ -128,7 +130,7 @@ macro_rules! span {
$name:expr,
$($k:ident $( = $val:expr )* ),*
) => {
{
if $lvl <= $crate::level_filters::STATIC_MAX_LEVEL {
use $crate::callsite;
use $crate::callsite::Callsite;
let callsite = callsite! {
Expand All @@ -146,6 +148,8 @@ macro_rules! span {
} else {
$crate::Span::new_disabled()
}
} else {
$crate::Span::new_disabled()
}
};
(target: $target:expr, level: $lvl:expr, parent: $parent:expr, $name:expr) => {
Expand Down Expand Up @@ -334,7 +338,7 @@ macro_rules! span {
#[macro_export(local_inner_macros)]
macro_rules! event {
(target: $target:expr, $lvl:expr, { $( $k:ident = $val:expr ),* $(,)*} )=> ({
{
if $lvl <= $crate::level_filters::STATIC_MAX_LEVEL {
#[allow(unused_imports)]
use $crate::{callsite, dispatcher, Event, field::{Value, ValueSet}};
use $crate::callsite::Callsite;
Expand Down
10 changes: 10 additions & 0 deletions tokio-trace/test_static_max_level_features/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[workspace]

[package]
name = "test_cargo_max_level_features"
version = "0.1.0"
publish = false

[dependencies.tokio-trace]
path = ".."
features = ["max_level_debug", "release_max_level_info"]
71 changes: 71 additions & 0 deletions tokio-trace/test_static_max_level_features/tests/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#[macro_use]
extern crate tokio_trace;

use std::sync::{Arc, Mutex};
use tokio_trace::span::{Attributes, Record};
use tokio_trace::{span, Event, Id, Level, Metadata, Subscriber};

struct State {
last_level: Mutex<Option<Level>>,
}

struct TestSubscriber(Arc<State>);

impl Subscriber for TestSubscriber {
fn enabled(&self, _: &Metadata) -> bool {
true
}

fn new_span(&self, _span: &Attributes) -> Id {
span::Id::from_u64(42)
}

fn record(&self, _span: &Id, _values: &Record) {}

fn record_follows_from(&self, _span: &Id, _follows: &Id) {}

fn event(&self, event: &Event) {
*self.0.last_level.lock().unwrap() = Some(event.metadata().level().clone());
}

fn enter(&self, _span: &Id) {}

fn exit(&self, _span: &Id) {}
}

#[cfg(test)]
fn test_static_max_level_features() {
let me = Arc::new(State {
last_level: Mutex::new(None),
});
let a = me.clone();
tokio_trace::subscriber::with_default(TestSubscriber(me), || {
error!("");
last(&a, Some(Level::ERROR));
warn!("");
last(&a, Some(Level::WARN));
info!("");
last(&a, Some(Level::INFO));
debug!("");
last(&a, Some(Level::DEBUG));
trace!("");
last(&a, None);

span!(level: Level::ERROR, "");
last(&a, None);
span!(level: Level::WARN, "");
last(&a, None);
span!(level: Level::INFO, "");
last(&a, None);
span!(level: Level::DEBUG, "");
last(&a, None);
span!(level: Level::TRACE, "");
last(&a, None);
});
}

fn last(state: &State, expected: Option<Level>) {
let mut lvl = state.last_level.lock().unwrap();
assert_eq!(*lvl, expected);
*lvl = None;
}