1 //! This crate allows tools to enable rust logging without having to magically
2 //! match rustc's tracing crate version.
4 //! For example if someone is working on rustc_ast and wants to write some
5 //! minimal code against it to run in a debugger, with access to the `debug!`
6 //! logs emitted by rustc_ast, that can be done by writing:
10 //! rustc_ast = { path = "../rust/compiler/rustc_ast" }
11 //! rustc_log = { path = "../rust/compiler/rustc_log" }
12 //! rustc_span = { path = "../rust/compiler/rustc_span" }
17 //! rustc_log::init_rustc_env_logger().unwrap();
19 //! let edition = rustc_span::edition::Edition::Edition2021;
20 //! rustc_span::create_session_globals_then(edition, || {
26 //! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
27 //! rustc's debug logging. In a workflow like this, one might also add
28 //! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
29 //! run` by itself is sufficient to get logs.
31 //! The reason rustc_log is a tiny separate crate, as opposed to exposing the
32 //! same things in rustc_driver only, is to enable the above workflow. If you
33 //! had to depend on rustc_driver in order to turn on rustc's debug logs, that's
34 //! an enormously bigger dependency tree; every change you make to rustc_ast (or
35 //! whichever piece of the compiler you are interested in) would involve
36 //! rebuilding all the rest of rustc up to rustc_driver in order to run your
37 //! main.rs. Whereas by depending only on rustc_log and the few crates you are
38 //! debugging, you can make changes inside those crates and quickly run main.rs
39 //! to read the debug logs.
41 use std
::env
::{self, VarError}
;
42 use std
::fmt
::{self, Display}
;
44 use tracing_subscriber
::filter
::{Directive, EnvFilter, LevelFilter}
;
45 use tracing_subscriber
::layer
::SubscriberExt
;
47 pub fn init_rustc_env_logger() -> Result
<(), Error
> {
48 init_env_logger("RUSTC_LOG")
51 /// In contrast to `init_rustc_env_logger` this allows you to choose an env var
52 /// other than `RUSTC_LOG`.
53 pub fn init_env_logger(env
: &str) -> Result
<(), Error
> {
54 let filter
= match env
::var(env
) {
55 Ok(env
) => EnvFilter
::new(env
),
56 _
=> EnvFilter
::default().add_directive(Directive
::from(LevelFilter
::WARN
)),
59 let color_logs
= match env
::var(String
::from(env
) + "_COLOR") {
60 Ok(value
) => match value
.as_ref() {
63 "auto" => stderr_isatty(),
64 _
=> return Err(Error
::InvalidColorValue(value
)),
66 Err(VarError
::NotPresent
) => stderr_isatty(),
67 Err(VarError
::NotUnicode(_value
)) => return Err(Error
::NonUnicodeColorValue
),
70 let verbose_entry_exit
= match env
::var_os(String
::from(env
) + "_ENTRY_EXIT") {
75 let layer
= tracing_tree
::HierarchicalLayer
::default()
76 .with_writer(io
::stderr
)
77 .with_indent_lines(true)
78 .with_ansi(color_logs
)
80 .with_verbose_exit(verbose_entry_exit
)
81 .with_verbose_entry(verbose_entry_exit
)
82 .with_indent_amount(2);
83 #[cfg(parallel_compiler)]
84 let layer
= layer
.with_thread_ids(true).with_thread_names(true);
86 let subscriber
= tracing_subscriber
::Registry
::default().with(filter
).with(layer
);
87 tracing
::subscriber
::set_global_default(subscriber
).unwrap();
92 pub fn stdout_isatty() -> bool
{
93 atty
::is(atty
::Stream
::Stdout
)
96 pub fn stderr_isatty() -> bool
{
97 atty
::is(atty
::Stream
::Stderr
)
102 InvalidColorValue(String
),
103 NonUnicodeColorValue
,
106 impl std
::error
::Error
for Error {}
108 impl Display
for Error
{
109 fn fmt(&self, formatter
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
111 Error
::InvalidColorValue(value
) => write
!(
113 "invalid log color value '{}': expected one of always, never, or auto",
116 Error
::NonUnicodeColorValue
=> write
!(
118 "non-Unicode log color value: expected one of always, never, or auto",