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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
#![feature(backtrace)] mod help; pub use eyre::*; pub use help::Help; pub type ErrReport = eyre::ErrReport<JaneContext>; pub type Result<T, E = ErrReport> = core::result::Result<T, E>; use help::HelpInfo; use indenter::Indented; use std::any::{Any, TypeId}; use std::backtrace::Backtrace; use std::backtrace::BacktraceStatus; use std::error::Error; use std::fmt::Write as _; use tracing_error::{ExtractSpanTrace, SpanTrace, SpanTraceStatus}; pub struct JaneContext { backtrace: Option<Backtrace>, span_trace: Option<SpanTrace>, help: Vec<HelpInfo>, } fn get_deepest_backtrace<'a>(error: &'a (dyn Error + 'static)) -> Option<&'a Backtrace> { Chain::new(error) .rev() .flat_map(|error| error.backtrace()) .next() } fn get_deepest_spantrace<'a>(error: &'a (dyn Error + 'static)) -> Option<&'a SpanTrace> { Chain::new(error) .rev() .flat_map(|error| error.span_trace()) .next() } impl EyreContext for JaneContext { fn default(error: &(dyn std::error::Error + 'static)) -> Self { let backtrace = if get_deepest_backtrace(error).is_none() { Some(Backtrace::capture()) } else { None }; let span_trace = if get_deepest_spantrace(error).is_none() { Some(SpanTrace::capture()) } else { None }; Self { backtrace: backtrace, span_trace: span_trace, help: Vec::new(), } } fn member_ref(&self, typeid: TypeId) -> Option<&dyn Any> { if typeid == TypeId::of::<Backtrace>() { self.backtrace.as_ref().map(|b| b as &dyn Any) } else if typeid == TypeId::of::<SpanTrace>() { self.span_trace.as_ref().map(|s| s as &dyn Any) } else { None } } fn member_mut(&mut self, typeid: TypeId) -> Option<&mut dyn Any> { if typeid == TypeId::of::<Vec<HelpInfo>>() { Some(&mut self.help) } else { None } } fn display( &self, error: &(dyn std::error::Error + 'static), f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { write!(f, "{}", error)?; if f.alternate() { for cause in Chain::new(error).skip(1) { write!(f, ": {}", cause)?; } } Ok(()) } fn debug( &self, error: &(dyn std::error::Error + 'static), f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { if f.alternate() { return core::fmt::Debug::fmt(error, f); } let errors = Chain::new(error).rev().enumerate(); for (n, error) in errors { writeln!(f)?; write!(Indented::numbered(f, n), "{}", error)?; } for help in &self.help { write!(f, "\n{}", help)?; } let span_trace = self .span_trace .as_ref() .or_else(|| get_deepest_spantrace(error)) .expect("SpanTrace capture failed"); match span_trace.status() { SpanTraceStatus::CAPTURED => write!(f, "\n\nSpan Trace:\n{}", span_trace)?, SpanTraceStatus::UNSUPPORTED => write!(f, "\n\nWarning: SpanTrace capture is Unsupported.\nEnsure that you've setup an error layer and the versions match")?, _ => (), } let backtrace = self .backtrace .as_ref() .or_else(|| get_deepest_backtrace(error)) .expect("backtrace capture failed"); if let BacktraceStatus::Captured = backtrace.status() { write!(f, "\n\nStack Backtrace:\n{}", backtrace)?; } Ok(()) } }