relay_log/
utils.rs

1use std::error::Error;
2use std::fmt;
3
4use tracing::Level;
5
6/// Returns `true` if backtrace printing is enabled.
7///
8/// # Example
9///
10/// ```
11/// std::env::set_var("RUST_BACKTRACE", "full");
12/// assert!(relay_log::backtrace_enabled());
13/// ```
14pub fn backtrace_enabled() -> bool {
15    matches!(
16        std::env::var("RUST_BACKTRACE").as_ref().map(String::as_str),
17        Ok("1") | Ok("full")
18    )
19}
20
21/// Logs an error to the configured logger or `stderr` if not yet configured.
22///
23/// Prefer to use [`relay_log::error`](crate::error) over this function whenever possible. This
24/// function is intended to be used during startup, where initializing the logger may fail or when
25/// errors need to be logged before the logger has been initialized.
26#[allow(clippy::print_stderr, reason = "necessary for early logging")]
27pub fn ensure_error<E: AsRef<dyn Error>>(error: E) {
28    if tracing::event_enabled!(Level::ERROR) {
29        crate::error!(error = error.as_ref());
30    } else {
31        eprintln!("error: {}", LogError(error.as_ref()));
32    }
33}
34
35/// A wrapper around an error that prints its causes.
36struct LogError<'a, E: Error + ?Sized>(pub &'a E);
37
38impl<E: Error + ?Sized> fmt::Display for LogError<'_, E> {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "{}", self.0)?;
41
42        let mut source = self.0.source();
43        while let Some(s) = source {
44            write!(f, "\n  caused by: {s}")?;
45            source = s.source();
46        }
47
48        // NOTE: This is where we would print a backtrace, once stabilized.
49
50        Ok(())
51    }
52}