summaryrefslogtreecommitdiffstats
path: root/tokio-trace
diff options
context:
space:
mode:
authorSon <leson.phung@gmail.com>2019-03-26 09:19:20 +1100
committerEliza Weisman <eliza@buoyant.io>2019-03-25 15:19:20 -0700
commit1524ee4b60792c7046748ebc4a9db2e687b971d3 (patch)
tree3c00e3281dec77d8abab3f14bc63d2368ff9fbfc /tokio-trace
parent7793d637397a0e73096a1df31c777920545e9d1e (diff)
trace: Add static level filtering (#987)
## Motivation `tokio-trace` should have static verbosity level filtering, like the `log` crate. The static max verbosity level should be controlled at compile time with a set of features. It should be possible to set a separate max level for release and debug mode builds. ## Solution We can do this fairly similarly to how the `log` crate does it: `tokio-trace` should export a constant whose value is set based on the static max level feature flags. Then, we add an if statement to the `span!` and `event!` macros which tests if that event or span's level is enabled. Closes #959
Diffstat (limited to 'tokio-trace')
-rw-r--r--tokio-trace/Cargo.toml16
-rw-r--r--tokio-trace/src/level_filters.rs88
-rw-r--r--tokio-trace/src/lib.rs3
-rw-r--r--tokio-trace/src/macros.rs10
-rw-r--r--tokio-trace/test_static_max_level_features/Cargo.toml10
-rw-r--r--tokio-trace/test_static_max_level_features/tests/test.rs71
6 files changed, 195 insertions, 3 deletions
diff --git a/tokio-trace/Cargo.toml b/tokio-trace/Cargo.toml
index c4460b96..0d4bdcbb 100644
--- a/tokio-trace/Cargo.toml
+++ b/tokio-trace/Cargo.toml
@@ -16,6 +16,7 @@ publish = false
[dependencies]
tokio-trace-core = "0.1"
+cfg-if = "0.1.7"
[dev-dependencies]
ansi_term = "0.11"
@@ -23,6 +24,21 @@ 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.
diff --git a/tokio-trace/src/level_filters.rs b/tokio-trace/src/level_filters.rs
new file mode 100644
index 00000000..4d383112
--- /dev/null
+++ b/tokio-trace/src/level_filters.rs
@@ -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 {
+ 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;
+ }
+}
diff --git a/tokio-trace/src/lib.rs b/tokio-trace/src/lib.rs
index 23e5cce0..6182b552 100644
--- a/tokio-trace/src/lib.rs
+++ b/tokio-trace/src/lib.rs
@@ -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`
@@ -339,6 +341,7 @@ pub use self::{
mod macros;
pub mod field;
+pub mod level_filters;
pub mod span;
pub mod subscriber;
diff --git a/tokio-trace/src/macros.rs b/tokio-trace/src/macros.rs
index e2d231de..84791747 100644
--- a/tokio-trace/src/macros.rs
+++ b/tokio-trace/src/macros.rs
@@ -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! {
@@ -120,6 +120,8 @@ macro_rules! span {
} else {
$crate::Span::new_disabled()
}
+ } else {
+ $crate::Span::new_disabled()
}
};
(
@@ -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! {
@@ -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) => {
@@ -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;
diff --git a/tokio-trace/test_static_max_level_features/Cargo.toml b/tokio-trace/test_static_max_level_features/Cargo.toml
new file mode 100644
index 00000000..a40596a3
--- /dev/null
+++ b/tokio-trace/test_static_max_level_features/Cargo.toml
@@ -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"]
diff --git a/tokio-trace/test_static_max_level_features/tests/test.rs b/tokio-trace/test_static_max_level_features/tests/test.rs
new file mode 100644
index 00000000..ba3f2757
--- /dev/null
+++ b/tokio-trace/test_static_max_level_features/tests/test.rs
@@ -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;
+}