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