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 = cfg.verbose_entry_exit.is_ok_and(|v| v != "0");
134 let verbose_thread_ids = cfg.verbose_thread_ids.is_ok_and(|v| v == "1");
135 let lines = cfg.lines.is_ok_and(|v| v == "1");
136 let json = cfg.json.is_ok_and(|v| v == "1");
137
138 let output_target: BoxMakeWriter = match cfg.output_target {
139 Ok(v) => match File::options().create(true).write(true).truncate(true).open(&v) {
140 Ok(i) => BoxMakeWriter::new(Mutex::new(i)),
141 Err(e) => {
142 {
::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:?}");
143 BoxMakeWriter::new(io::stderr)
144 }
145 },
146 Err(_) => BoxMakeWriter::new(io::stderr),
147 };
148
149 let layer = if json {
150 let format = tracing_subscriber::fmt::format()
151 .json()
152 .with_span_list(true)
153 .with_source_location(true);
154
155 let fmt_layer = tracing_subscriber::fmt::layer()
156 .json()
157 .event_format(format)
158 .with_writer(output_target)
159 .with_target(true)
160 .with_ansi(false)
161 .with_thread_ids(verbose_thread_ids)
162 .with_thread_names(verbose_thread_ids)
163 .with_span_events(FmtSpan::ACTIVE);
164 let fmt_layer = NonrecursiveLayer { inner: fmt_layer };
165 Layer::boxed(fmt_layer)
166 } else {
167 let mut layer = tracing_tree::HierarchicalLayer::default()
168 .with_writer(output_target)
169 .with_ansi(color_logs)
170 .with_targets(true)
171 .with_verbose_exit(verbose_entry_exit)
172 .with_verbose_entry(verbose_entry_exit)
173 .with_indent_amount(2)
174 .with_indent_lines(lines)
175 .with_thread_ids(verbose_thread_ids)
176 .with_thread_names(verbose_thread_ids);
177
178 if let Ok(v) = cfg.wraptree {
179 match v.parse::<usize>() {
180 Ok(v) => layer = layer.with_wraparound(v),
181 Err(_) => return Err(Error::InvalidWraptree(v)),
182 }
183 }
184
185 Layer::boxed(layer)
186 };
187
188 let subscriber = build_subscriber();
189 match cfg.backtrace {
191 Ok(backtrace_target) => {
192 let fmt_layer = tracing_subscriber::fmt::layer()
193 .with_writer(io::stderr)
194 .without_time()
195 .event_format(BacktraceFormatter { backtrace_target });
196 let subscriber = subscriber.with(layer).with(fmt_layer).with(filter);
197 tracing::subscriber::set_global_default(subscriber)?;
198 }
199 Err(_) => {
200 tracing::subscriber::set_global_default(subscriber.with(layer).with(filter))?;
201 }
202 };
203
204 Ok(())
205}
206
207struct BacktraceFormatter {
208 backtrace_target: String,
209}
210
211impl<S, N> FormatEvent<S, N> for BacktraceFormatter
212where
213 S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
214 N: for<'a> FormatFields<'a> + 'static,
215{
216 fn format_event(
217 &self,
218 _ctx: &FmtContext<'_, S, N>,
219 mut writer: format::Writer<'_>,
220 event: &Event<'_>,
221 ) -> fmt::Result {
222 let target = event.metadata().target();
223 if !target.contains(&self.backtrace_target) {
224 return Ok(());
225 }
226 let backtrace = std::backtrace::Backtrace::force_capture();
229 writer.write_fmt(format_args!("stack backtrace: \n{0:?}\n", backtrace))writeln!(writer, "stack backtrace: \n{backtrace:?}")
230 }
231}
232
233pub fn stdout_isatty() -> bool {
234 io::stdout().is_terminal()
235}
236
237pub fn stderr_isatty() -> bool {
238 io::stderr().is_terminal()
239}
240
241#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Error {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::InvalidColorValue(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidColorValue", &__self_0),
Self::NonUnicodeColorValue =>
::core::fmt::Formatter::write_str(f, "NonUnicodeColorValue"),
Self::InvalidWraptree(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidWraptree", &__self_0),
Self::AlreadyInit(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AlreadyInit", &__self_0),
}
}
}Debug)]
242pub enum Error {
243 InvalidColorValue(String),
244 NonUnicodeColorValue,
245 InvalidWraptree(String),
246 AlreadyInit(SetGlobalDefaultError),
247}
248
249impl std::error::Error for Error {}
250
251impl Display for Error {
252 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
253 match self {
254 Error::InvalidColorValue(value) => formatter.write_fmt(format_args!("invalid log color value \'{0}\': expected one of always, never, or auto",
value))write!(
255 formatter,
256 "invalid log color value '{value}': expected one of always, never, or auto",
257 ),
258 Error::NonUnicodeColorValue => formatter.write_fmt(format_args!("non-Unicode log color value: expected one of always, never, or auto"))write!(
259 formatter,
260 "non-Unicode log color value: expected one of always, never, or auto",
261 ),
262 Error::InvalidWraptree(value) => formatter.write_fmt(format_args!("invalid log WRAPTREE value \'{0}\': expected a non-negative integer",
value))write!(
263 formatter,
264 "invalid log WRAPTREE value '{value}': expected a non-negative integer",
265 ),
266 Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter),
267 }
268 }
269}
270
271impl From<SetGlobalDefaultError> for Error {
272 fn from(tracing_error: SetGlobalDefaultError) -> Self {
273 Error::AlreadyInit(tracing_error)
274 }
275}
276
277const 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>>() {
|__rust_std_internal_init|
{
#[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 {
|__rust_std_internal_init|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL: Cell<bool> =
__RUST_STD_INTERNAL_INIT;
&__RUST_STD_INTERNAL_VAL
}
}
})
}
};thread_local! {
278 static NONRECURSIVE_GUARD_LOCK: Cell<bool> = const { Cell::new(false) };
279}
280
281struct NonrecursiveGuard;
282
283impl NonrecursiveGuard {
284 fn lock() -> Option<NonrecursiveGuard> {
285 if !NONRECURSIVE_GUARD_LOCK.replace(true) { Some(NonrecursiveGuard) } else { None }
286 }
287}
288
289impl Drop for NonrecursiveGuard {
290 fn drop(&mut self) {
291 NONRECURSIVE_GUARD_LOCK.set(false);
292 }
293}
294
295struct NonrecursiveLayer<S> {
301 inner: S,
302}
303
304impl<S: Subscriber, L: Layer<S>> Layer<S> for NonrecursiveLayer<L> {
305 fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
306 self.inner.on_register_dispatch(subscriber)
307 }
308
309 fn on_layer(&mut self, subscriber: &mut S) {
310 self.inner.on_layer(subscriber)
311 }
312
313 fn register_callsite(
314 &self,
315 metadata: &'static tracing::Metadata<'static>,
316 ) -> tracing_core::Interest {
317 self.inner.register_callsite(metadata)
318 }
319
320 fn enabled(&self, metadata: &tracing::Metadata<'_>, ctx: Context<'_, S>) -> bool {
321 self.inner.enabled(metadata, ctx)
322 }
323
324 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
325 if let Some(_) = NonrecursiveGuard::lock() {
326 self.inner.on_new_span(attrs, id, ctx)
327 }
328 }
329
330 fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
331 if let Some(_) = NonrecursiveGuard::lock() {
332 self.inner.on_record(span, values, ctx)
333 }
334 }
335
336 fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, S>) {
337 if let Some(_) = NonrecursiveGuard::lock() {
338 self.inner.on_follows_from(span, follows, ctx)
339 }
340 }
341
342 fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool {
343 if let Some(_) = NonrecursiveGuard::lock() {
344 self.inner.event_enabled(event, ctx)
345 } else {
346 false
347 }
348 }
349
350 fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
351 if let Some(_) = NonrecursiveGuard::lock() {
352 self.inner.on_event(event, ctx)
353 }
354 }
355
356 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
357 if let Some(_) = NonrecursiveGuard::lock() {
358 self.inner.on_enter(id, ctx)
359 }
360 }
361
362 fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
363 if let Some(_) = NonrecursiveGuard::lock() {
364 self.inner.on_exit(id, ctx)
365 }
366 }
367
368 fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
369 if let Some(_) = NonrecursiveGuard::lock() {
370 self.inner.on_close(id, ctx)
371 }
372 }
373
374 fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<'_, S>) {
375 self.inner.on_id_change(old, new, ctx)
376 }
377}