use std::fmt;
use std::sync::atomic::{AtomicU8, Ordering};
use tracing::level_filters::LevelFilter;
#[inline]
pub fn current_backtrace_mode() -> BacktraceMode {
match LevelFilter::current() {
LevelFilter::TRACE | LevelFilter::DEBUG => BacktraceMode::Full,
LevelFilter::INFO => BacktraceMode::Light,
LevelFilter::WARN | LevelFilter::ERROR | LevelFilter::OFF => BacktraceMode::None,
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BacktraceMode {
None = 0,
Light = 1,
Full = 2,
}
impl From<u8> for BacktraceMode {
fn from(level: u8) -> Self {
match level {
0 => BacktraceMode::None,
1 => BacktraceMode::Light,
_ => BacktraceMode::Full,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Location {
pub file: &'static str,
pub line: u32,
pub column: u32,
}
impl Location {
#[inline(always)]
pub const fn new(file: &'static str, line: u32, column: u32) -> Self {
Self { file, line, column }
}
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}:{}", self.file, self.line, self.column)
}
}
#[derive(Debug)]
pub enum SmartBacktrace {
None,
Location(Location),
Full(std::backtrace::Backtrace),
}
impl SmartBacktrace {
pub fn none() -> Self {
SmartBacktrace::None
}
pub fn light(file: &'static str, line: u32, column: u32) -> Self {
SmartBacktrace::Location(Location::new(file, line, column))
}
pub fn full() -> Self {
#[cfg(feature = "backtrace-symbols")]
let bt = std::backtrace::Backtrace::force_capture();
#[cfg(not(feature = "backtrace-symbols"))]
let bt = std::backtrace::Backtrace::capture();
SmartBacktrace::Full(bt)
}
pub fn to_display_string(&self) -> Option<String> {
match self {
SmartBacktrace::None => None,
SmartBacktrace::Location(loc) => Some(format!(" at {}", loc)),
SmartBacktrace::Full(bt) => Some(format!("\nBacktrace:\n{}", bt)),
}
}
pub fn from_current_level() -> Self {
match current_backtrace_mode() {
BacktraceMode::Full => Self::full(),
_ => Self::none(),
}
}
}