-
Notifications
You must be signed in to change notification settings - Fork 721
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core: change
Interest
-combining to play nicer with multiple subscri…
…bers (#927) ## Motivation Currently, when multiple subscribers are in use, the way that `Interest` values are combined results in surprising behavior. If _any_ subscriber returns `Interest::always` for a callsite, that interest currently takes priority over any other `Interest`s. This means that if two threads have separate subscribers, one of which enables a callsite `always`, and the other `never`, _both_ subscribers will always record that callsite, without the option to disable it. This is not quite right. Instead, we should check whether the current subscriber will enable that callsite in this case. This issue is described in #902. ## Solution This branch changes the rules for combining `Interest`s so that `always` is only returned if _both_ `Interest`s are `always`. If only _one_ is `always`, the combined interest is now `sometimes`, instead. This means that when multiple subscribers exist, `enabled` will always be called on the _current_ subscriber, except when _all_ subscribers have indicated that they are `always` or `never` interested in a callsite. I've added tests that reproduce the issues with leaky filters. Fixing this revealed an additional issue where `tracing-subscriber`'s `EnvFilter` assumes that `enabled` is only called for events, and never for spans, because it always returns either `always` or `never` from `register_callsite` for spans. Therefore, the dynamic span matching directives that might enable a span were never checked in `enabled`. However, under the new interest-combining rules, `enabled` *may* still be called even if a subscriber returns an `always` or `never` interest, if *another* subscriber exists that returned an incompatible interest. This PR fixes that, as well. Depends on #919 This was previously approved by @yaahc as PR #920, but I accidentally merged it into #919 _after_ that branch merged, rather than into master (my bad!). Signed-off-by: Eliza Weisman <eliza@buoyant.io>
- Loading branch information
Showing
4 changed files
with
116 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#![cfg(feature = "std")] | ||
|
||
mod support; | ||
use self::support::*; | ||
|
||
#[test] | ||
fn spans_dont_leak() { | ||
fn do_span() { | ||
let span = tracing::debug_span!("alice"); | ||
let _e = span.enter(); | ||
} | ||
|
||
let (subscriber, handle) = subscriber::mock() | ||
.named("spans/subscriber1") | ||
.with_filter(|_| false) | ||
.done() | ||
.run_with_handle(); | ||
|
||
let _guard = tracing::subscriber::set_default(subscriber); | ||
|
||
do_span(); | ||
|
||
let alice = span::mock().named("alice"); | ||
let (subscriber2, handle2) = subscriber::mock() | ||
.named("spans/subscriber2") | ||
.with_filter(|_| true) | ||
.new_span(alice.clone()) | ||
.enter(alice.clone()) | ||
.exit(alice.clone()) | ||
.drop_span(alice) | ||
.done() | ||
.run_with_handle(); | ||
|
||
tracing::subscriber::with_default(subscriber2, || { | ||
println!("--- subscriber 2 is default ---"); | ||
do_span() | ||
}); | ||
|
||
println!("--- subscriber 1 is default ---"); | ||
do_span(); | ||
|
||
handle.assert_finished(); | ||
handle2.assert_finished(); | ||
} | ||
|
||
#[test] | ||
fn events_dont_leak() { | ||
fn do_event() { | ||
tracing::debug!("alice"); | ||
} | ||
|
||
let (subscriber, handle) = subscriber::mock() | ||
.named("events/subscriber1") | ||
.with_filter(|_| false) | ||
.done() | ||
.run_with_handle(); | ||
|
||
let _guard = tracing::subscriber::set_default(subscriber); | ||
|
||
do_event(); | ||
|
||
let (subscriber2, handle2) = subscriber::mock() | ||
.named("events/subscriber2") | ||
.with_filter(|_| true) | ||
.event(event::mock()) | ||
.done() | ||
.run_with_handle(); | ||
|
||
tracing::subscriber::with_default(subscriber2, || { | ||
println!("--- subscriber 2 is default ---"); | ||
do_event() | ||
}); | ||
|
||
println!("--- subscriber 1 is default ---"); | ||
|
||
do_event(); | ||
|
||
handle.assert_finished(); | ||
handle2.assert_finished(); | ||
} |