Open rtimush opened 1 year ago
Thanks for filing this! I was on the trail of one of my spans getting swallowed, realized commenting out tracing_log::LogTracer::init()
"fixed" it, searched, and found this timely bug report with a nice minimal repro.
I'd love to get this fixed, and have been reading the code a bit, but I'm really confused about how per-layer filtering is supposed to work. E.g., starting from the basics:
<Registry as Subscriber>::enabled
returns some pre-set state from a thread local. Is there some contract that something else should have been called first? From reading tracing::Subscriber docs, it sounds like it's more common to go through register_callsite
, but this isn't actually required? So I don't understand how this enabled
implementation can work? am I missing something?
I've reproduced this without log. It seems that Dispatch::enabled()
affects the next call-site to be registered.
Cargo.toml:
[package]
name = "tracing-lost-callsite"
version = "0.1.0"
edition = "2021"
[dependencies]
tracing = "0.1.37"
tracing-core = "0.1.31"
tracing-subscriber = "0.3.17"
src/main.rs:
fn main() {
use tracing_subscriber::prelude::*;
// Change this to DEBUG and the supressed INFO event will be recorded.
let filter = tracing_core::LevelFilter::INFO;
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer().with_filter(filter))
.init();
tracing::info!("this event is unaffected");
let metadata = make_metadata_with_level(tracing_core::Level::DEBUG);
let enabled = tracing::dispatcher::get_default(|dispatch| dispatch.enabled(&metadata));
tracing::info!("this event gets suppressed");
tracing::info!("The callsite was enabled? {}", enabled);
}
fn make_metadata_with_level(level: tracing_core::Level) -> tracing::Metadata<'static> {
struct Cs;
impl tracing_core::Callsite for Cs {
fn set_interest(&self, _interest: tracing_core::Interest) {}
fn metadata(&self) -> &tracing_core::Metadata<'_> {
unimplemented!()
}
}
tracing::Metadata::new(
"",
"app",
level,
None,
None,
None,
tracing::field::FieldSet::new(&[], tracing_core::identify_callsite!(&Cs)),
tracing::metadata::Kind::EVENT,
)
}
I've reproduced this without log. It seems that
Dispatch::enabled()
affects the next call-site to be registered.Cargo.toml:
[package] name = "tracing-lost-callsite" version = "0.1.0" edition = "2021" [dependencies] tracing = "0.1.37" tracing-core = "0.1.31" tracing-subscriber = "0.3.17"
src/main.rs:
fn main() { use tracing_subscriber::prelude::*; // Change this to DEBUG and the supressed INFO event will be recorded. let filter = tracing_core::LevelFilter::INFO; tracing_subscriber::registry() .with(tracing_subscriber::fmt::layer().with_filter(filter)) .init(); tracing::info!("this event is unaffected"); let metadata = make_metadata_with_level(tracing_core::Level::DEBUG); let enabled = tracing::dispatcher::get_default(|dispatch| dispatch.enabled(&metadata)); tracing::info!("this event gets suppressed"); tracing::info!("The callsite was enabled? {}", enabled); } fn make_metadata_with_level(level: tracing_core::Level) -> tracing::Metadata<'static> { struct Cs; impl tracing_core::Callsite for Cs { fn set_interest(&self, _interest: tracing_core::Interest) {} fn metadata(&self) -> &tracing_core::Metadata<'_> { unimplemented!() } } tracing::Metadata::new( "", "app", level, None, None, None, tracing::field::FieldSet::new(&[], tracing_core::identify_callsite!(&Cs)), tracing::metadata::Kind::EVENT, ) }
Thanks for the repro, this is great. We could add this as a regression test for a fix.
Is constructing a Metadata
with None
location, filename, and module path necessary to trigger this issue?
@hawkw I don't believe so, this was just supposed to be minimal. Another repro is via tracing-log
. This is the one described in this issue, but I don't know whether the Metadata
created from tracing-log
has no location, filename, etc (I just haven't had a chance to check).
use tracing_subscriber::prelude::*;
fn main() {
let env_filter = tracing_subscriber::filter::EnvFilter::new("other_mod=debug,debug");
let fmt_layer = tracing_subscriber::fmt::layer().with_filter(env_filter);
tracing_subscriber::registry().with(fmt_layer).init();
tracing::error!("this error is unaffected");
_ = log::log_enabled!(target: "other_mod", log::Level::Debug);
tracing::error!("this error gets suppressed");
}
Cool, I think you're right, but I was just checking to make sure.
This issue appears to be with the FILTERING
thread-local used by the Filtered
layer. When enabled
is called, it updates it with the underlying filter result:
This expects a matching call to on_new_span
or on_event
, which call did_enabled
to reset the FILTERING
state:
However, when enabled
is manually called (e.g. from log::log_enabled
), there isn't a matching call, which will cause an unrelated span/event to get ignored.
Bug Report
Version
Platform
Description
Querying "enabled" from the
log
crate in some cases makestracing
swallow the next event. Example code:If executed with
RUST_LOG=<crate_name>=debug,info
, the secondinfo!
is not logged.This doesn't happen if:
debug
or<crate_name>=info,info
The Cargo.toml dependencies section: