Skip to content

Commit 3fb3da6

Browse files
Rollup merge of rust-lang#157190 - khyperia:nonrecursive-tracing-json, r=jieyouxu
Silence recursive RUSTC_LOG_FORMAT_JSON messages We print a *lot* of debug messages while formatting the arguments of another, outer, debug message. For example, these two `debug!` lines are responsible for **75%** of all log messages when running with `RUSTC_LOG=trace RUSTC_LOG_FORMAT_JSON=1`, because we format paths to string a *lot* when debug logging: https://github.com/rust-lang/rust/blob/c315891193c35827c2d789adce686f8a5481778f/compiler/rustc_hir/src/definitions.rs#L153-L156 The default rustc log formatter, `tracing_tree::HierarchicalLayer`, blocks all "recursive" tracing messages, dropping them: https://github.com/davidbarsky/tracing-tree/blob/79627fc72ae7dcf95af16e047797e60494679678/src/lib.rs#L410-L412 However, `RUSTC_LOG_FORMAT_JSON` does not. This is mildly annoying, since once logged, it's impossible to tell that a message is "recursive", so which means that [my lil rustc log viewer](https://github.com/khyperia/khys-rustc-log-viewer), as [well as Jana's](https://git.donsz.nl/jana/logviewer), can only fully filter these messages out, rather than only showing them when they are top-level logs. This change implements a very criminal, primitive recursion check, in a very hacky way, in rustc_log - I am not proud of this code, and wish there was a better way of doing this. As far as I can tell, though, this is the easiest/most effective way of implementing this - `tracing` doesn't provide nice tools for this kind of thing. Before this change: ``` khyperia@argon /d/rust (main)> RUSTC_LOG_FORMAT_JSON=1 RUSTC_LOG=trace rustc +stage1 -Znext-solver=globally tests/ui/const-generics/gca/non-type-equality-ok.rs &| wc -l 1443792 lines khyperia@argon /d/rust (main)> RUSTC_LOG_FORMAT_JSON=1 RUSTC_LOG=trace rustc +stage1 -Znext-solver=globally tests/ui/const-generics/gca/non-type-equality-ok.rs &| wc -c 3513565523 = 3.5 gigabytes ``` After this change: ``` khyperia@argon /d/rust (main)> RUSTC_LOG_FORMAT_JSON=1 RUSTC_LOG=trace rustc +stage1 -Znext-solver=globally tests/ui/const-generics/gca/non-type-equality-ok.rs &| wc -l 84104 lines = 5.8% of the number of lines khyperia@argon /d/rust (main)> RUSTC_LOG_FORMAT_JSON=1 RUSTC_LOG=trace rustc +stage1 -Znext-solver=globally tests/ui/const-generics/gca/non-type-equality-ok.rs &| wc -c 257480205 = 257 megabytes = 7.3% the amount of data ``` FYI @jdonszelmann r? @jieyouxu
2 parents 7459f76 + 14f4690 commit 3fb3da6

1 file changed

Lines changed: 106 additions & 2 deletions

File tree

compiler/rustc_log/src/lib.rs

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,20 @@
3333
//! debugging, you can make changes inside those crates and quickly run main.rs
3434
//! to read the debug logs.
3535
36+
use std::cell::Cell;
3637
use std::env::{self, VarError};
3738
use std::fmt::{self, Display};
3839
use std::fs::File;
3940
use std::io::{self, IsTerminal};
4041
use std::sync::Mutex;
4142

4243
use tracing::dispatcher::SetGlobalDefaultError;
43-
use tracing::{Event, Subscriber};
44+
use tracing::{Event, Subscriber, span};
4445
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
4546
use tracing_subscriber::fmt::FmtContext;
4647
use tracing_subscriber::fmt::format::{self, FmtSpan, FormatEvent, FormatFields};
4748
use tracing_subscriber::fmt::writer::BoxMakeWriter;
48-
use tracing_subscriber::layer::SubscriberExt;
49+
use tracing_subscriber::layer::{Context, SubscriberExt};
4950
use tracing_subscriber::{Layer, Registry};
5051
// Re-export tracing
5152
pub use {tracing, tracing_core, tracing_subscriber};
@@ -175,6 +176,7 @@ where
175176
.with_thread_ids(verbose_thread_ids)
176177
.with_thread_names(verbose_thread_ids)
177178
.with_span_events(FmtSpan::ACTIVE);
179+
let fmt_layer = NonrecursiveLayer { inner: fmt_layer };
178180
Layer::boxed(fmt_layer)
179181
} else {
180182
let mut layer = tracing_tree::HierarchicalLayer::default()
@@ -286,3 +288,105 @@ impl From<SetGlobalDefaultError> for Error {
286288
Error::AlreadyInit(tracing_error)
287289
}
288290
}
291+
292+
thread_local! {
293+
static NONRECURSIVE_GUARD_LOCK: Cell<bool> = const { Cell::new(false) };
294+
}
295+
296+
struct NonrecursiveGuard;
297+
298+
impl NonrecursiveGuard {
299+
fn lock() -> Option<NonrecursiveGuard> {
300+
if !NONRECURSIVE_GUARD_LOCK.replace(true) { Some(NonrecursiveGuard) } else { None }
301+
}
302+
}
303+
304+
impl Drop for NonrecursiveGuard {
305+
fn drop(&mut self) {
306+
NONRECURSIVE_GUARD_LOCK.set(false);
307+
}
308+
}
309+
310+
/// Many debug messages that rustc emits produce additional debug messages when formatting the
311+
/// arguments to the original debug message. [`tracing_tree::HierarchicalLayer`] (used by the
312+
/// default output format) filters these out, but [`tracing_subscriber::fmt::format::Json`] (used by
313+
/// `RUSTC_LOG_FORMAT_JSON`) does not. So, implement a simple recursion check to filter these
314+
/// messages out.
315+
struct NonrecursiveLayer<S> {
316+
inner: S,
317+
}
318+
319+
impl<S: Subscriber, L: Layer<S>> Layer<S> for NonrecursiveLayer<L> {
320+
fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
321+
self.inner.on_register_dispatch(subscriber)
322+
}
323+
324+
fn on_layer(&mut self, subscriber: &mut S) {
325+
self.inner.on_layer(subscriber)
326+
}
327+
328+
fn register_callsite(
329+
&self,
330+
metadata: &'static tracing::Metadata<'static>,
331+
) -> tracing_core::Interest {
332+
self.inner.register_callsite(metadata)
333+
}
334+
335+
fn enabled(&self, metadata: &tracing::Metadata<'_>, ctx: Context<'_, S>) -> bool {
336+
self.inner.enabled(metadata, ctx)
337+
}
338+
339+
fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
340+
if let Some(_) = NonrecursiveGuard::lock() {
341+
self.inner.on_new_span(attrs, id, ctx)
342+
}
343+
}
344+
345+
fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
346+
if let Some(_) = NonrecursiveGuard::lock() {
347+
self.inner.on_record(span, values, ctx)
348+
}
349+
}
350+
351+
fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, S>) {
352+
if let Some(_) = NonrecursiveGuard::lock() {
353+
self.inner.on_follows_from(span, follows, ctx)
354+
}
355+
}
356+
357+
fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool {
358+
if let Some(_) = NonrecursiveGuard::lock() {
359+
self.inner.event_enabled(event, ctx)
360+
} else {
361+
false
362+
}
363+
}
364+
365+
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
366+
if let Some(_) = NonrecursiveGuard::lock() {
367+
self.inner.on_event(event, ctx)
368+
}
369+
}
370+
371+
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
372+
if let Some(_) = NonrecursiveGuard::lock() {
373+
self.inner.on_enter(id, ctx)
374+
}
375+
}
376+
377+
fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
378+
if let Some(_) = NonrecursiveGuard::lock() {
379+
self.inner.on_exit(id, ctx)
380+
}
381+
}
382+
383+
fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
384+
if let Some(_) = NonrecursiveGuard::lock() {
385+
self.inner.on_close(id, ctx)
386+
}
387+
}
388+
389+
fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<'_, S>) {
390+
self.inner.on_id_change(old, new, ctx)
391+
}
392+
}

0 commit comments

Comments
 (0)