Merge branch 'err-dyn-report' into 'main'
Error logging (ErrorReport, .report()) POC See merge request tpo/core/arti!936
This commit is contained in:
commit
fa5a417fc9
|
@ -39,6 +39,7 @@
|
|||
|
||||
use tor_basic_utils::retry::RetryDelay;
|
||||
use tor_chanmgr::ChanMgr;
|
||||
use tor_error::ErrorReport;
|
||||
use tor_linkspec::ChanTarget;
|
||||
use tor_netdir::{DirEvent, NetDir, NetDirProvider, Timeliness};
|
||||
use tor_proto::circuit::{CircParameters, ClientCirc, UniqId};
|
||||
|
@ -642,7 +643,7 @@ impl<R: Runtime> CircMgr<R> {
|
|||
|
||||
match statemgr.try_lock() {
|
||||
Err(e) => {
|
||||
error!("Problem with state lock file: {}", e);
|
||||
error!("Problem with state lock file: {}", e.report());
|
||||
break;
|
||||
}
|
||||
Ok(NewlyAcquired) => {
|
||||
|
|
|
@ -291,6 +291,17 @@ mod test {
|
|||
assert!(s.contains("Couldn't wobble the wobbling device."));
|
||||
#[cfg(feature = "backtrace")]
|
||||
assert!(s.contains("internal_macro_test"));
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
enum Wrap {
|
||||
#[error("Internal error")]
|
||||
Internal(#[from] Bug),
|
||||
}
|
||||
|
||||
let w: Wrap = e.into();
|
||||
let s = format!("Got: {}", w.report());
|
||||
dbg!(&s);
|
||||
assert!(s.contains("Couldn't wobble the wobbling device."));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! The Report type which reports errors nicely
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
/// Wraps any Error, providing a nicely-reporting Display impl
|
||||
|
@ -7,15 +8,15 @@ use std::fmt::{self, Debug, Display};
|
|||
#[allow(clippy::exhaustive_structs)] // this is a transparent wrapper
|
||||
pub struct Report<E>(pub E)
|
||||
where
|
||||
E: AsRef<dyn std::error::Error>;
|
||||
E: AsRef<dyn StdError>;
|
||||
|
||||
impl<E> Display for Report<E>
|
||||
where
|
||||
E: AsRef<dyn std::error::Error>,
|
||||
E: AsRef<dyn StdError>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// Non-generic inner function avoids code bloat
|
||||
fn inner(mut e: &dyn std::error::Error, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn inner(mut e: &dyn StdError, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "error")?;
|
||||
let mut last = String::new();
|
||||
loop {
|
||||
|
@ -44,7 +45,7 @@ where
|
|||
#[allow(clippy::print_stderr)] // this is the point of this function
|
||||
pub fn report_and_exit<E, R>(e: E) -> R
|
||||
where
|
||||
E: AsRef<dyn std::error::Error>,
|
||||
E: AsRef<dyn StdError>,
|
||||
{
|
||||
/// Non-generic inner function avoids code bloat
|
||||
fn eprint_progname() {
|
||||
|
@ -58,10 +59,41 @@ where
|
|||
std::process::exit(127)
|
||||
}
|
||||
|
||||
/// Helper type for reporting errors that are concrete implementors of `StdError`
|
||||
///
|
||||
/// This is an opaque type, only constructable via the `ErrorExt` helper trait
|
||||
/// and only useable via its `AsRef` implementation.
|
||||
//
|
||||
// We need this because Rust's trait object handling rules, and provided AsRef impls,
|
||||
// are rather anaemic. We cannot simply put a &dyn Error into Report, because
|
||||
// &dyn Error doesn't impl AsRef<dyn Error> even though the implementation is trivial.
|
||||
// We can't provide that AsRef impl ourselves due to trait coherency rules.
|
||||
// So instead, we wrap up the &dyn Error in a newtype, for which we *can* provide the AsRef.
|
||||
pub struct ReportHelper<'e>(&'e (dyn StdError + 'static));
|
||||
impl<'e> AsRef<dyn StdError + 'static> for ReportHelper<'e> {
|
||||
fn as_ref(&self) -> &(dyn StdError + 'static) {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension trait providing `.report()` method on concrete errors
|
||||
///
|
||||
/// This is implemented for types that directly implement [`std::error::Error`]` + 'static`.
|
||||
/// For types like `anyhow::Error` that `impl AsRef<dyn Error>`,
|
||||
/// use `tor_error::Report(err)` directly.
|
||||
pub trait ErrorReport: StdError + Sized + 'static {
|
||||
/// Return an object that displays the error and its causes
|
||||
//
|
||||
// We would ideally have returned `Report<impl AsRef<...>>` but that's TAIT.
|
||||
fn report(&self) -> Report<ReportHelper> {
|
||||
Report(ReportHelper(self as _))
|
||||
}
|
||||
}
|
||||
impl<E: StdError + Sized + 'static> ErrorReport for E {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::error::Error as StdError;
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
@ -495,7 +495,7 @@ pub(crate) mod test {
|
|||
.build()
|
||||
.unwrap();
|
||||
let send1 = send1.sink_map_err(|e| {
|
||||
trace!("got sink error: {}", e);
|
||||
trace!("got sink error: {:?}", e);
|
||||
CodecError::DecCell(tor_cell::Error::ChanProto("dummy message".into()))
|
||||
});
|
||||
let (chan, reactor) = crate::channel::Channel::new(
|
||||
|
|
Loading…
Reference in New Issue