|
45 | 45 | use std::env::{self, VarError};
|
46 | 46 | use std::fmt::{self, Display};
|
47 | 47 | use std::io::{self, IsTerminal};
|
| 48 | +use tracing_core::{Event, Subscriber}; |
48 | 49 | use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
|
| 50 | +use tracing_subscriber::fmt::{ |
| 51 | + format::{self, FormatEvent, FormatFields}, |
| 52 | + FmtContext, |
| 53 | +}; |
49 | 54 | use tracing_subscriber::layer::SubscriberExt;
|
50 | 55 |
|
51 | 56 | pub fn init_rustc_env_logger() -> Result<(), Error> {
|
52 |
| - init_env_logger("RUSTC_LOG") |
| 57 | + init_rustc_env_logger_with_backtrace_option(&None) |
| 58 | +} |
| 59 | + |
| 60 | +pub fn init_rustc_env_logger_with_backtrace_option( |
| 61 | + backtrace_target: &Option<String>, |
| 62 | +) -> Result<(), Error> { |
| 63 | + init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target) |
53 | 64 | }
|
54 | 65 |
|
55 | 66 | /// In contrast to `init_rustc_env_logger` this allows you to choose an env var
|
56 | 67 | /// other than `RUSTC_LOG`.
|
57 | 68 | pub fn init_env_logger(env: &str) -> Result<(), Error> {
|
| 69 | + init_env_logger_with_backtrace_option(env, &None) |
| 70 | +} |
| 71 | + |
| 72 | +pub fn init_env_logger_with_backtrace_option( |
| 73 | + env: &str, |
| 74 | + backtrace_target: &Option<String>, |
| 75 | +) -> Result<(), Error> { |
58 | 76 | let filter = match env::var(env) {
|
59 | 77 | Ok(env) => EnvFilter::new(env),
|
60 | 78 | _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
|
@@ -88,11 +106,47 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
|
88 | 106 | let layer = layer.with_thread_ids(true).with_thread_names(true);
|
89 | 107 |
|
90 | 108 | let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
|
91 |
| - tracing::subscriber::set_global_default(subscriber).unwrap(); |
| 109 | + match backtrace_target { |
| 110 | + Some(str) => { |
| 111 | + let fmt_layer = tracing_subscriber::fmt::layer() |
| 112 | + .with_writer(io::stderr) |
| 113 | + .without_time() |
| 114 | + .event_format(BacktraceFormatter { backtrace_target: str.to_string() }); |
| 115 | + let subscriber = subscriber.with(fmt_layer); |
| 116 | + tracing::subscriber::set_global_default(subscriber).unwrap(); |
| 117 | + } |
| 118 | + None => { |
| 119 | + tracing::subscriber::set_global_default(subscriber).unwrap(); |
| 120 | + } |
| 121 | + }; |
92 | 122 |
|
93 | 123 | Ok(())
|
94 | 124 | }
|
95 | 125 |
|
| 126 | +struct BacktraceFormatter { |
| 127 | + backtrace_target: String, |
| 128 | +} |
| 129 | + |
| 130 | +impl<S, N> FormatEvent<S, N> for BacktraceFormatter |
| 131 | +where |
| 132 | + S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>, |
| 133 | + N: for<'a> FormatFields<'a> + 'static, |
| 134 | +{ |
| 135 | + fn format_event( |
| 136 | + &self, |
| 137 | + _ctx: &FmtContext<'_, S, N>, |
| 138 | + mut writer: format::Writer<'_>, |
| 139 | + event: &Event<'_>, |
| 140 | + ) -> fmt::Result { |
| 141 | + let target = event.metadata().target(); |
| 142 | + if !target.contains(&self.backtrace_target) { |
| 143 | + return Ok(()); |
| 144 | + } |
| 145 | + let backtrace = std::backtrace::Backtrace::capture(); |
| 146 | + writeln!(writer, "stack backtrace: \n{:?}", backtrace) |
| 147 | + } |
| 148 | +} |
| 149 | + |
96 | 150 | pub fn stdout_isatty() -> bool {
|
97 | 151 | io::stdout().is_terminal()
|
98 | 152 | }
|
|
0 commit comments