Allow linking rustc and rustdoc against the same single tracing crate
By consecutively initializing `tracing` and `rustc_log`, Rustdoc assumes
that these involve 2 different tracing crates.
I would like to be able to build rustdoc against the same tracing crate
that rustc_log is also built against. Previously this arrangement would
crash rustdoc:
thread 'main' panicked at rust/compiler/rustc_log/src/lib.rs:142:65:
called `Result::unwrap()` on an `Err` value: SetGlobalDefaultError("a global default trace dispatcher has already been set")
stack backtrace:
0: rust_begin_unwind
1: core::panicking::panic_fmt
2: core::result::unwrap_failed
3: rustc_log::init_logger
4: rustc_driver_impl::init_logger
5: rustdoc::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
note: please make sure that you have updated to the latest nightly
query stack during panic:
end of query stack
This commit is contained in:
@@ -37,6 +37,7 @@ use std::env::{self, VarError};
|
|||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::io::{self, IsTerminal};
|
use std::io::{self, IsTerminal};
|
||||||
|
|
||||||
|
use tracing::dispatcher::SetGlobalDefaultError;
|
||||||
use tracing_core::{Event, Subscriber};
|
use tracing_core::{Event, Subscriber};
|
||||||
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
|
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
|
||||||
use tracing_subscriber::fmt::FmtContext;
|
use tracing_subscriber::fmt::FmtContext;
|
||||||
@@ -131,10 +132,10 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
|
|||||||
.without_time()
|
.without_time()
|
||||||
.event_format(BacktraceFormatter { backtrace_target });
|
.event_format(BacktraceFormatter { backtrace_target });
|
||||||
let subscriber = subscriber.with(fmt_layer);
|
let subscriber = subscriber.with(fmt_layer);
|
||||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@ pub enum Error {
|
|||||||
InvalidColorValue(String),
|
InvalidColorValue(String),
|
||||||
NonUnicodeColorValue,
|
NonUnicodeColorValue,
|
||||||
InvalidWraptree(String),
|
InvalidWraptree(String),
|
||||||
|
AlreadyInit(SetGlobalDefaultError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {}
|
impl std::error::Error for Error {}
|
||||||
@@ -199,6 +201,13 @@ impl Display for Error {
|
|||||||
formatter,
|
formatter,
|
||||||
"invalid log WRAPTREE value '{value}': expected a non-negative integer",
|
"invalid log WRAPTREE value '{value}': expected a non-negative integer",
|
||||||
),
|
),
|
||||||
|
Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SetGlobalDefaultError> for Error {
|
||||||
|
fn from(tracing_error: SetGlobalDefaultError) -> Self {
|
||||||
|
Error::AlreadyInit(tracing_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -170,12 +170,28 @@ pub fn main() {
|
|||||||
// NOTE: this compiles both versions of tracing unconditionally, because
|
// NOTE: this compiles both versions of tracing unconditionally, because
|
||||||
// - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
|
// - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
|
||||||
// - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
|
// - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
|
||||||
// NOTE: The reason this doesn't show double logging when `download-rustc = false` and
|
|
||||||
// `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
|
|
||||||
// in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
|
|
||||||
|
|
||||||
init_logging(&early_dcx);
|
crate::init_logging(&early_dcx);
|
||||||
rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
|
match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
|
||||||
|
Ok(()) => {}
|
||||||
|
// With `download-rustc = true` there are definitely 2 distinct tracing crates in the
|
||||||
|
// dependency graph: one in the downloaded sysroot and one built just now as a dependency of
|
||||||
|
// rustdoc. So the sysroot's tracing is definitely not yet initialized here.
|
||||||
|
//
|
||||||
|
// But otherwise, depending on link style, there may or may not be 2 tracing crates in play.
|
||||||
|
// The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency
|
||||||
|
// on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's
|
||||||
|
// tracing dependency is distinct from this one and also needs to be initialized (using the
|
||||||
|
// same RUSTDOC_LOG environment variable for both). Other build systems may use just a
|
||||||
|
// single tracing crate throughout the rustc and rustdoc build.
|
||||||
|
//
|
||||||
|
// The reason initializing 2 tracings does not show double logging when `download-rustc =
|
||||||
|
// false` and `debug_logging = true` is because all rustc logging goes only to its version
|
||||||
|
// of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version
|
||||||
|
// (the one in Cargo.toml).
|
||||||
|
Err(rustc_log::Error::AlreadyInit(_)) => {}
|
||||||
|
Err(error) => early_dcx.early_fatal(error.to_string()),
|
||||||
|
}
|
||||||
|
|
||||||
let exit_code = rustc_driver::catch_with_exit_code(|| {
|
let exit_code = rustc_driver::catch_with_exit_code(|| {
|
||||||
let at_args = rustc_driver::args::raw_args(&early_dcx);
|
let at_args = rustc_driver::args::raw_args(&early_dcx);
|
||||||
|
|||||||
Reference in New Issue
Block a user