diff --git a/Cargo.toml b/Cargo.toml index 02e6641..8a51dd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,18 +6,19 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +capture-spantrace = ["tracing-error", "color-spantrace"] + +default = ["capture-spantrace"] + [dependencies] eyre = "0.3.8" -tracing-error = "0.1.2" -color-backtrace = "0.3.0" +tracing-error = { version = "0.1.2", optional = true } +color-backtrace = "0.4.0" backtrace = "0.3" -indenter = "0.1.3" -console = "0.10.0" -color-spantrace = { git = "https://github.com/yaahc/color-spantrace.git" } - -[patch.crates-io] -color-backtrace = { git = "https://github.com/yaahc/color-backtrace.git", branch = "filter" } -indenter = { git = "https://github.com/yaahc/indenter.git" } +indenter = "0.2.0" +ansi_term = "0.12.1" +color-spantrace = { version = "0.1", optional = true } [dev-dependencies] tracing-subscriber = "0.2.5" diff --git a/README.md b/README.md index 1de56a5..4274699 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,41 @@ -color-eyre ----------- +## color-eyre A custom context for the [`eyre`] crate for colorful error reports, suggestions, and [`tracing-error`] support. -**Disclaimer**: This crate is currently pre-release while I try to upstream -changes I made to [`color-backtrace`] to support this crate. Until then I -cannot publish this to crates.io, the documentation is filled out however so -simply run `cargo doc --open` for an explanation of usage. +## Setup + +Add the following to your toml file: + +```toml +[dependencies] +eyre = "0.3.8" +color-eyre = "0.1" +``` + +And then import the type alias from color-eyre for [`eyre::Report`] or [`eyre::Result`]. + +```rust +use color_eyre::Report; + +// or + +fn example() -> color_eyre::Result<()> { + # Ok(()) + // ... +} +``` + +### Disabling tracing support + +If you don't plan on using `tracing_error` and `SpanTrace` you can disable the +tracing integration to cut down on unused dependencies: + +```toml +[dependencies] +eyre = "0.3.8" +color-eyre = { version = "0.1", default-features = false } +``` ## Explanation @@ -16,6 +44,8 @@ and a pair of type aliases for setting this context type as the parameter of [`eyre::Report`]. ```rust +use color_eyre::Context; + pub type Report = eyre::Report; pub type Result = core::result::Result; ``` @@ -26,35 +56,12 @@ pub type Result = core::result::Result; - captures a [`tracing_error::SpanTrace`] and prints using [`color-spantrace`] - Only capture SpanTrace by default for better performance. -- display source lines when `RUST_LIB_BACKTRACE=full` is set from both of - the above libraries +- display source lines when `RUST_LIB_BACKTRACE=full` is set - store help text via [`Help`] trait and display after final report -## Setup +## Example -Add the following to your toml file: - -```toml -[dependencies] -eyre = "0.3.8" -color-eyre = { git = "https://github.com/yaahc/color-eyre.git" } -``` - -And then import the type alias from color-eyre for [`eyre::Report`] or [`eyre::Result`]. - -```rust -use color_eyre::Report; - -// or - -fn example(&self) -> color_eyre::Result<()> { - // ... -} -``` - -# Example - -```rust +```rust,should_panic use color_eyre::{Help, Report}; use eyre::WrapErr; use tracing::{info, instrument}; diff --git a/examples/usage.rs b/examples/usage.rs index a402557..494ccb2 100644 --- a/examples/usage.rs +++ b/examples/usage.rs @@ -1,12 +1,21 @@ use color_eyre::{Help, Report}; use eyre::WrapErr; use tracing::{info, instrument}; -use tracing_error::ErrorLayer; -use tracing_subscriber::prelude::*; -use tracing_subscriber::{fmt, EnvFilter}; #[instrument] fn main() -> Result<(), Report> { + #[cfg(feature = "capture-spantrace")] + install_tracing(); + + Ok(read_config()?) +} + +#[cfg(feature = "capture-spantrace")] +fn install_tracing() { + use tracing_error::ErrorLayer; + use tracing_subscriber::prelude::*; + use tracing_subscriber::{fmt, EnvFilter}; + let fmt_layer = fmt::layer().with_target(false); let filter_layer = EnvFilter::try_from_default_env() .or_else(|_| EnvFilter::try_new("info")) @@ -17,8 +26,6 @@ fn main() -> Result<(), Report> { .with(fmt_layer) .with(ErrorLayer::default()) .init(); - - Ok(read_config()?) } #[instrument] diff --git a/src/help.rs b/src/help.rs index 3ac8d00..bfbc894 100644 --- a/src/help.rs +++ b/src/help.rs @@ -1,5 +1,5 @@ use crate::{Report, Result}; -use console::style; +use ansi_term::Color::*; use std::fmt::{self, Display}; /// A helper trait for attaching help text to errors to be displayed after the chain of errors @@ -184,9 +184,9 @@ pub enum HelpInfo { impl Display for HelpInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Self::Note(context) => write!(f, "Note: {}", context), - Self::Warning(context) => write!(f, "Warning: {}", context), - Self::Suggestion(context) => write!(f, "{}: {}", style("Suggestion").cyan(), context), + Self::Note(context) => write!(f, "{}: {}", Cyan.paint("Note"), context), + Self::Warning(context) => write!(f, "{}: {}", Yellow.paint("Warning"), context), + Self::Suggestion(context) => write!(f, "{}: {}", Cyan.paint("Suggestion"), context), } } } diff --git a/src/lib.rs b/src/lib.rs index 5949547..416e28b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,23 +1,65 @@ -//! This library provides a custom [`eyre::EyreContext`] type for colorful error -//! reports with custom help text for the [`eyre`] crate. +//! A custom context for the [`eyre`] crate for colorful error reports, suggestions, +//! and [`tracing-error`] support. //! -//! **Disclaimer**: This library is currently in pre-release while I work on upstreaming changes I -//! made to [`color-backtrace`], until then this depends on unreleased versions on github and so it -//! cannot be published to crates.io +//! ## Setup //! -//! # Features +//! Add the following to your toml file: +//! +//! ```toml +//! [dependencies] +//! eyre = "0.3.8" +//! color-eyre = "0.1" +//! ``` +//! +//! And then import the type alias from color-eyre for [`eyre::Report`] or [`eyre::Result`]. +//! +//! ```rust +//! use color_eyre::Report; +//! +//! // or +//! +//! fn example() -> color_eyre::Result<()> { +//! # Ok(()) +//! // ... +//! } +//! ``` +//! +//! ### Disabling tracing support +//! +//! If you don't plan on using `tracing_error` and `SpanTrace` you can disable the +//! tracing integration to cut down on unused dependencies: +//! +//! ```toml +//! [dependencies] +//! eyre = "0.3.8" +//! color-eyre = { version = "0.1", default-features = false } +//! ``` +//! +//! ## Explanation +//! +//! This crate works by defining a `Context` type which implements [`eyre::EyreContext`] +//! and a pair of type aliases for setting this context type as the parameter of +//! [`eyre::Report`]. +//! +//! ```rust +//! use color_eyre::Context; +//! +//! pub type Report = eyre::Report; +//! pub type Result = core::result::Result; +//! ``` +//! +//! ## Features //! //! - captures a [`backtrace::Backtrace`] and prints using [`color-backtrace`] //! - captures a [`tracing_error::SpanTrace`] and prints using //! [`color-spantrace`] //! - Only capture SpanTrace by default for better performance. -//! - display source lines when `RUST_LIB_BACKTRACE=full` is set from both of -//! the above libraries +//! - display source lines when `RUST_LIB_BACKTRACE=full` is set //! - store help text via [`Help`] trait and display after final report //! -//! # Example +//! ## Example //! -//! ```should_panic +//! ```rust,should_panic //! use color_eyre::{Help, Report}; //! use eyre::WrapErr; //! use tracing::{info, instrument}; @@ -54,44 +96,43 @@ //! } //! ``` //! -//! # Report Formats -//! -//! The following report formats are available via setting the `RUST_LIB_BACKTRACE` variable. -//! //! ## Minimal Report Format //! -//! ![minimal report format](https://github.com/yaahc/color-eyre/blob/master/pictures/minimal.png) +//! ![minimal report format](./pictures/minimal.png) //! //! ## Short Report Format (with `RUST_LIB_BACKTRACE=1`) //! -//! ![short report format](https://github.com/yaahc/color-eyre/blob/master/pictures/short.png) +//! ![short report format](./pictures/short.png) //! //! ## Full Report Format (with `RUST_LIB_BACKTRACE=full`) //! -//! ![full report format](https://github.com/yaahc/color-eyre/blob/master/pictures/full.png) +//! ![full report format](./pictures/full.png) //! -//! [`eyre::EyreContext`]: https://docs.rs/eyre/0.3.8/eyre/trait.EyreContext.html //! [`eyre`]: https://docs.rs/eyre +//! [`tracing-error`]: https://docs.rs/tracing-error +//! [`color-backtrace`]: https://docs.rs/color-backtrace +//! [`eyre::EyreContext`]: https://docs.rs/eyre/0.3.8/eyre/trait.EyreContext.html //! [`backtrace::Backtrace`]: https://docs.rs/backtrace/0.3.46/backtrace/struct.Backtrace.html //! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/0.1.2/tracing_error/struct.SpanTrace.html -//! [`color-backtrace`]: https://docs.rs/color-backtrace //! [`color-spantrace`]: https://github.com/yaahc/color-spantrace //! [`Help`]: trait.Help.html //! [`eyre::Report`]: https://docs.rs/eyre/0.3.8/eyre/struct.Report.html -//! [`tracing-error`]: https://docs.rs/tracing-error +//! [`eyre::Result`]: https://docs.rs/eyre/0.3.8/eyre/type.Result.html +use ansi_term::Color::*; use backtrace::Backtrace; -use console::style; use eyre::*; pub use help::Help; use help::HelpInfo; -use indenter::{indented, Format, Indented}; +use indenter::{indented, Format}; +#[cfg(feature = "capture-spantrace")] use std::error::Error; use std::fmt::Write as _; +#[cfg(feature = "capture-spantrace")] use tracing_error::{ExtractSpanTrace, SpanTrace, SpanTraceStatus}; mod help; -/// A Custom Context type for [`eyre::Report`] which provides colorful error +/// A custom context type for [`eyre::Report`] which provides colorful error /// reports and [`tracing-error`] support. /// /// This type is not intended to be used directly, prefer using it via the @@ -103,11 +144,13 @@ mod help; /// [`color_eyre::Result`]: type.Result.html pub struct Context { backtrace: Option, + #[cfg(feature = "capture-spantrace")] span_trace: Option, help: Vec, } impl EyreContext for Context { + #[allow(unused_variables)] fn default(error: &(dyn std::error::Error + 'static)) -> Self { let backtrace = if std::env::var("RUST_LIB_BACKTRACE").is_ok() { Some(Backtrace::new()) @@ -115,6 +158,7 @@ impl EyreContext for Context { None }; + #[cfg(feature = "capture-spantrace")] let span_trace = if get_deepest_spantrace(error).is_none() { Some(SpanTrace::capture()) } else { @@ -123,6 +167,7 @@ impl EyreContext for Context { Self { backtrace, + #[cfg(feature = "capture-spantrace")] span_trace, help: Vec::new(), } @@ -137,33 +182,42 @@ impl EyreContext for Context { return core::fmt::Debug::fmt(error, f); } + #[cfg(feature = "capture-spantrace")] let errors = Chain::new(error) .filter(|e| e.span_trace().is_none()) .enumerate(); + #[cfg(not(feature = "capture-spantrace"))] + let errors = Chain::new(error).enumerate(); + + let mut buf = String::new(); for (n, error) in errors { writeln!(f)?; - write!(Indented::numbered(f, n), "{}", style(error).red())?; + buf.clear(); + write!(&mut buf, "{}", error).unwrap(); + write!(indented(f).ind(n), "{}", Red.paint(&buf))?; } - let span_trace = self - .span_trace - .as_ref() - .or_else(|| get_deepest_spantrace(error)) - .expect("SpanTrace capture failed"); + #[cfg(feature = "capture-spantrace")] + { + 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\n")?; - write!(indented(f).with_format(Format::Uniform { indentation: " " }), "{}", color_spantrace::colorize(span_trace))? - }, - SpanTraceStatus::UNSUPPORTED => write!(f, "\n\nWarning: SpanTrace capture is Unsupported.\nEnsure that you've setup an error layer and the versions match")?, - _ => (), + match span_trace.status() { + SpanTraceStatus::CAPTURED => { + write!(f, "\n\n")?; + write!(indented(f).with_format(Format::Uniform { indentation: " " }), "{}", color_spantrace::colorize(span_trace))? + }, + SpanTraceStatus::UNSUPPORTED => write!(f, "\n\nWarning: SpanTrace capture is Unsupported.\nEnsure that you've setup an error layer and the versions match")?, + _ => (), + } } if let Some(backtrace) = self.backtrace.as_ref() { write!(f, "\n\n")?; - // let settings = color_backtrace::PanicPrinter::default(); let bt_str = color_backtrace::BacktracePrinter::new() .add_frame_filter(Box::new(|frames| { @@ -172,20 +226,17 @@ impl EyreContext for Context { "eyre::", ]; - frames - .into_iter() - .filter(|frame| { - !filters.iter().any(|f| { - let name = if let Some(name) = frame.name.as_ref() { - name.as_str() - } else { - return true; - }; + frames.retain(|frame| { + !filters.iter().any(|f| { + let name = if let Some(name) = frame.name.as_ref() { + name.as_str() + } else { + return true; + }; - name.starts_with(f) - }) + name.starts_with(f) }) - .collect() + }); })) .format_trace_to_string(&backtrace) .unwrap(); @@ -206,6 +257,7 @@ impl EyreContext for Context { } } +#[cfg(feature = "capture-spantrace")] fn get_deepest_spantrace<'a>(error: &'a (dyn Error + 'static)) -> Option<&'a SpanTrace> { Chain::new(error) .rev()