1use std::cell::Cell;
37use std::env::{self, VarError};
38use std::fmt::{self, Display};
39use std::fs::File;
40use std::io::{self, IsTerminal};
41use std::sync::Mutex;
42
43use tracing::dispatcher::SetGlobalDefaultError;
44use tracing::{Event, Subscriber, span};
45use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
46use tracing_subscriber::fmt::FmtContext;
47use tracing_subscriber::fmt::format::{self, FmtSpan, FormatEvent, FormatFields};
48use tracing_subscriber::fmt::writer::BoxMakeWriter;
49use tracing_subscriber::layer::{Context, SubscriberExt};
50use tracing_subscriber::{Layer, Registry};
51pub use {tracing, tracing_core, tracing_subscriber};
53
54pub struct LoggerConfig {
57 pub filter: Result<String, VarError>,
58 pub color_logs: Result<String, VarError>,
59 pub verbose_entry_exit: Result<String, VarError>,
60 pub verbose_thread_ids: Result<String, VarError>,
61 pub backtrace: Result<String, VarError>,
62 pub json: Result<String, VarError>,
63 pub output_target: Result<String, VarError>,
64 pub wraptree: Result<String, VarError>,
65 pub lines: Result<String, VarError>,
66}
67
68impl LoggerConfig {
69 pub fn from_env(env: &str) -> Self {
70 LoggerConfig {
72 filter: env::var(env),
73 color_logs: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_COLOR", env))
})format!("{env}_COLOR")),
74 verbose_entry_exit: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_ENTRY_EXIT", env))
})format!("{env}_ENTRY_EXIT")),
75 verbose_thread_ids: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_THREAD_IDS", env))
})format!("{env}_THREAD_IDS")),
76 backtrace: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_BACKTRACE", env))
})format!("{env}_BACKTRACE")),
77 wraptree: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_WRAPTREE", env))
})format!("{env}_WRAPTREE")),
78 lines: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_LINES", env))
})format!("{env}_LINES")),
79 json: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_FORMAT_JSON", env))
})format!("{env}_FORMAT_JSON")),
80 output_target: env::var(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_OUTPUT_TARGET", env))
})format!("{env}_OUTPUT_TARGET")),
81 }
82 }
83}
84
85pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
87 init_logger_with_additional_layer(cfg, Registry::default)
88}
89
90pub trait BuildSubscriberRet:
96 tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync
97{
98}
99
100impl<
101 T: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync,
102> BuildSubscriberRet for T
103{
104}
105
106pub fn init_logger_with_additional_layer<F, T>(
110 cfg: LoggerConfig,
111 build_subscriber: F,
112) -> Result<(), Error>
113where
114 F: FnOnce() -> T,
115 T: BuildSubscriberRet,
116{
117 let filter = match cfg.filter {
118 Ok(env) => EnvFilter::new(env),
119 _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
120 };
121
122 let color_logs = match cfg.color_logs {
123 Ok(value) => match value.as_ref() {
124 "always" => true,
125 "never" => false,
126 "auto" => stderr_isatty(),
127 _ => return Err(Error::InvalidColorValue(value)),
128 },
129 Err(VarError::NotPresent) => stderr_isatty(),
130 Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue),
131 };
132
133 let verbose_entry_exit = match cfg.verbose_entry_exit {
134 Ok(v) => &v != "0",
135 Err(_) => false,
136 };
137
138 let verbose_thread_ids = match cfg.verbose_thread_ids {
139 Ok(v) => &v == "1",
140 Err(_) => false,
141 };
142
143 let lines = match cfg.lines {
144 Ok(v) => &v == "1",
145 Err(_) => false,
146 };
147
148 let json = match cfg.json {
149 Ok(v) => &v == "1",
150 Err(_) => false,
151 };
152
153 let output_target: BoxMakeWriter = match cfg.output_target {
154 Ok(v) => match File::options().create(true).write(true).truncate(true).open(&v) {
155 Ok(i) => BoxMakeWriter::new(Mutex::new(i)),
156 Err(e) => {
157 {
::std::io::_eprint(format_args!("couldn\'t open {0} as a log target: {1:?}\n",
v, e));
};eprintln!("couldn't open {v} as a log target: {e:?}");
158 BoxMakeWriter::new(io::stderr)
159 }
160 },
161 Err(_) => BoxMakeWriter::new(io::stderr),
162 };
163
164 let layer = if json {
165 let format = tracing_subscriber::fmt::format()
166 .json()
167 .with_span_list(true)
168 .with_source_location(true);
169
170 let fmt_layer = tracing_subscriber::fmt::layer()
171 .json()
172 .event_format(format)
173 .with_writer(output_target)
174 .with_target(true)
175 .with_ansi(false)
176 .with_thread_ids(verbose_thread_ids)
177 .with_thread_names(verbose_thread_ids)
178 .with_span_events(FmtSpan::ACTIVE);
179 let fmt_layer = NonrecursiveLayer { inner: fmt_layer };
180 Layer::boxed(fmt_layer)
181 } else {
182 let mut layer = tracing_tree::HierarchicalLayer::default()
183 .with_writer(output_target)
184 .with_ansi(color_logs)
185 .with_targets(true)
186 .with_verbose_exit(verbose_entry_exit)
187 .with_verbose_entry(verbose_entry_exit)
188 .with_indent_amount(2)
189 .with_indent_lines(lines)
190 .with_thread_ids(verbose_thread_ids)
191 .with_thread_names(verbose_thread_ids);
192
193 if let Ok(v) = cfg.wraptree {
194 match v.parse::<usize>() {
195 Ok(v) => layer = layer.with_wraparound(v),
196 Err(_) => return Err(Error::InvalidWraptree(v)),
197 }
198 }
199
200 Layer::boxed(layer)
201 };
202
203 let subscriber = build_subscriber();
204 match cfg.backtrace {
206 Ok(backtrace_target) => {
207 let fmt_layer = tracing_subscriber::fmt::layer()
208 .with_writer(io::stderr)
209 .without_time()
210 .event_format(BacktraceFormatter { backtrace_target });
211 let subscriber = subscriber.with(layer).with(fmt_layer).with(filter);
212 tracing::subscriber::set_global_default(subscriber)?;
213 }
214 Err(_) => {
215 tracing::subscriber::set_global_default(subscriber.with(layer).with(filter))?;
216 }
217 };
218
219 Ok(())
220}
221
222struct BacktraceFormatter {
223 backtrace_target: String,
224}
225
226impl<S, N> FormatEvent<S, N> for BacktraceFormatter
227where
228 S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
229 N: for<'a> FormatFields<'a> + 'static,
230{
231 fn format_event(
232 &self,
233 _ctx: &FmtContext<'_, S, N>,
234 mut writer: format::Writer<'_>,
235 event: &Event<'_>,
236 ) -> fmt::Result {
237 let target = event.metadata().target();
238 if !target.contains(&self.backtrace_target) {
239 return Ok(());
240 }
241 let backtrace = std::backtrace::Backtrace::force_capture();
244 writer.write_fmt(format_args!("stack backtrace: \n{0:?}\n", backtrace))writeln!(writer, "stack backtrace: \n{backtrace:?}")
245 }
246}
247
248pub fn stdout_isatty() -> bool {
249 io::stdout().is_terminal()
250}
251
252pub fn stderr_isatty() -> bool {
253 io::stderr().is_terminal()
254}
255
256#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Error {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Error::InvalidColorValue(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidColorValue", &__self_0),
Error::NonUnicodeColorValue =>
::core::fmt::Formatter::write_str(f, "NonUnicodeColorValue"),
Error::InvalidWraptree(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidWraptree", &__self_0),
Error::AlreadyInit(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AlreadyInit", &__self_0),
}
}
}Debug)]
257pub enum Error {
258 InvalidColorValue(String),
259 NonUnicodeColorValue,
260 InvalidWraptree(String),
261 AlreadyInit(SetGlobalDefaultError),
262}
263
264impl std::error::Error for Error {}
265
266impl Display for Error {
267 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
268 match self {
269 Error::InvalidColorValue(value) => formatter.write_fmt(format_args!("invalid log color value \'{0}\': expected one of always, never, or auto",
value))write!(
270 formatter,
271 "invalid log color value '{value}': expected one of always, never, or auto",
272 ),
273 Error::NonUnicodeColorValue => formatter.write_fmt(format_args!("non-Unicode log color value: expected one of always, never, or auto"))write!(
274 formatter,
275 "non-Unicode log color value: expected one of always, never, or auto",
276 ),
277 Error::InvalidWraptree(value) => formatter.write_fmt(format_args!("invalid log WRAPTREE value \'{0}\': expected a non-negative integer",
value))write!(
278 formatter,
279 "invalid log WRAPTREE value '{value}': expected a non-negative integer",
280 ),
281 Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter),
282 }
283 }
284}
285
286impl From<SetGlobalDefaultError> for Error {
287 fn from(tracing_error: SetGlobalDefaultError) -> Self {
288 Error::AlreadyInit(tracing_error)
289 }
290}
291
292const NONRECURSIVE_GUARD_LOCK: ::std::thread::LocalKey<Cell<bool>> =
{
const __RUST_STD_INTERNAL_INIT: Cell<bool> = { Cell::new(false) };
unsafe {
::std::thread::LocalKey::new(const {
if ::std::mem::needs_drop::<Cell<bool>>() {
|_|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL:
::std::thread::local_impl::EagerStorage<Cell<bool>> =
::std::thread::local_impl::EagerStorage::new(__RUST_STD_INTERNAL_INIT);
__RUST_STD_INTERNAL_VAL.get()
}
} else {
|_|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL: Cell<bool> =
__RUST_STD_INTERNAL_INIT;
&__RUST_STD_INTERNAL_VAL
}
}
})
}
};thread_local! {
293 static NONRECURSIVE_GUARD_LOCK: Cell<bool> = const { Cell::new(false) };
294}
295
296struct NonrecursiveGuard;
297
298impl NonrecursiveGuard {
299 fn lock() -> Option<NonrecursiveGuard> {
300 if !NONRECURSIVE_GUARD_LOCK.replace(true) { Some(NonrecursiveGuard) } else { None }
301 }
302}
303
304impl Drop for NonrecursiveGuard {
305 fn drop(&mut self) {
306 NONRECURSIVE_GUARD_LOCK.set(false);
307 }
308}
309
310struct NonrecursiveLayer<S> {
316 inner: S,
317}
318
319impl<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}