From ddfe940f9a0864c574ec9461edd1d59920057258 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 29 Oct 2019 16:32:50 +0100 Subject: [PATCH 1/2] Initial anyhow integration --- Cargo.toml | 2 + Makefile | 7 ++- src/integrations/anyhow.rs | 97 ++++++++++++++++++++++++++++++++++++++ src/integrations/mod.rs | 3 ++ src/lib.rs | 1 + 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/integrations/anyhow.rs diff --git a/Cargo.toml b/Cargo.toml index 1e0d96ac..458d9453 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ with_client_implementation = ["im", "url", "with_backtrace"] with_backtrace = ["backtrace", "regex"] with_panic = ["with_backtrace"] with_failure = ["failure", "with_backtrace"] +with_anyhow = ["anyhow", "with_backtrace"] with_log = ["log", "with_backtrace"] with_debug_to_log = ["log"] with_env_logger = ["with_log", "env_logger"] @@ -41,6 +42,7 @@ with_native_tls = ["reqwest/default-tls"] backtrace = { version = "0.3.15", optional = true } url = { version = "1.7.2", optional = true } failure = { version = "0.1.5", optional = true } +anyhow = { version = "1.0.17", optional = true } log = { version = "0.4.6", optional = true, features = ["std"] } sentry-types = "0.11.0" env_logger = { version = "0.6.1", optional = true } diff --git a/Makefile b/Makefile index 598e3adc..d45e4ef5 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ testall: checkfast: check-no-default-features check-default-features .PHONY: checkfast -checkall: check-all-features check-no-default-features check-default-features check-failure check-log check-panic check-error-chain check-all-impls check-curl-transport check-actix +checkall: check-all-features check-no-default-features check-default-features check-failure check-log check-panic check-error-chain check-anyhow check-all-impls check-curl-transport check-actix .PHONY: checkall check-all-features: @@ -91,6 +91,11 @@ check-error-chain: @RUSTFLAGS=-Dwarnings cargo check --no-default-features --features 'with_error_chain' .PHONY: check-error-chain +check-anyhow: + @echo 'NO CLIENT + ANYHOW' + @RUSTFLAGS=-Dwarnings cargo check --no-default-features --features 'with_anyhow' +.PHONY: check-anyhow + check-all-impls: @echo 'NO CLIENT + ALL IMPLS' @RUSTFLAGS=-Dwarnings cargo check --no-default-features --features 'with_failure,with_log,with_panic,with_error_chain' diff --git a/src/integrations/anyhow.rs b/src/integrations/anyhow.rs new file mode 100644 index 00000000..ae30e517 --- /dev/null +++ b/src/integrations/anyhow.rs @@ -0,0 +1,97 @@ +//! Adds support for the anyhow crate. +//! +//! **Feature:** `with_anyhow` (disabled by default) +//! +//! This does not support capturing backtraces on nightly. +//! +//! # Example +//! +//! ```no_run +//! # extern crate sentry; +//! # extern crate anyhow; +//! # fn function_that_might_fail() -> Result<(), anyhow::Error> { Ok(()) } +//! use sentry::integrations::anyhow::capture_error; +//! # fn test() -> Result<(), anyhow::Error> { +//! let result = match function_that_might_fail() { +//! Ok(result) => result, +//! Err(err) => { +//! capture_error(&err); +//! return Err(err); +//! } +//! }; +//! # Ok(()) } +//! # fn main() { test().unwrap() } +//! ``` +//! +use anyhow::Error; + +use crate::hub::Hub; +use crate::internals::Uuid; +use crate::protocol::{Event, Exception, Level}; + +/// Helper function to create an event from a `anyhow::Error`. +pub fn event_from_error(err: &anyhow::Error) -> Event<'static> { + let mut exceptions = vec![]; + + for cause in err.chain() { + exceptions.push(Exception { + ty: "Error".to_owned(), + module: None, + value: Some(cause.to_string()), + stacktrace: None, + ..Default::default() + }); + } + + exceptions.reverse(); + Event { + exception: exceptions.into(), + level: Level::Error, + ..Default::default() + } +} + +/// Captures a boxed failure (`anyhow::Error`). +/// +/// This dispatches to the current hub. +pub fn capture_error(err: &Error) -> Uuid { + Hub::with_active(|hub| hub.capture_error(err)) +} + +/// Hub extension methods for working with failure. +pub trait AnyhowHubExt { + /// Captures a boxed failure (`anyhow::Error`). + fn capture_error(&self, err: &Error) -> Uuid; +} + +impl AnyhowHubExt for Hub { + fn capture_error(&self, err: &Error) -> Uuid { + self.capture_event(event_from_error(err)) + } +} + +/// Extension trait providing methods to unwrap a result, preserving backtraces from the +/// underlying error in the event of a panic. +pub trait AnyhowResultExt { + /// Type of the success case + type Value; + /// Unwraps the result, panicking if it contains an error. Any backtrace attached to the + /// error will be preserved with the panic. + fn fallible_unwrap(self) -> Self::Value; +} + +impl AnyhowResultExt for Result +where + E: Into, +{ + type Value = T; + fn fallible_unwrap(self) -> Self::Value { + match self { + Ok(v) => v, + Err(e) => { + let e: Error = e.into(); + panic!(e) + } + } + } +} diff --git a/src/integrations/mod.rs b/src/integrations/mod.rs index 0ba2709c..221b7232 100644 --- a/src/integrations/mod.rs +++ b/src/integrations/mod.rs @@ -15,3 +15,6 @@ pub mod env_logger; #[cfg(feature = "with_panic")] pub mod panic; + +#[cfg(feature = "with_anyhow")] +pub mod anyhow; diff --git a/src/lib.rs b/src/lib.rs index 7bef8010..01a05338 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,6 +104,7 @@ //! additional features: //! //! * `with_error_chain`: enables the error-chain integration +//! * `with_anyhow`: enables the anyhow integration //! * `with_test_support`: enables the test support module //! * `with_reqwest_transport`: enables the reqwest transport explicitly. This //! is currently the default transport. From f2c1d3c522a6bbfee3e8cf12755dad21a1699f22 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Tue, 29 Oct 2019 16:55:27 +0100 Subject: [PATCH 2/2] Minor tweaks --- Cargo.toml | 2 +- src/integrations/anyhow.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 458d9453..cf236c32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ with_client_implementation = ["im", "url", "with_backtrace"] with_backtrace = ["backtrace", "regex"] with_panic = ["with_backtrace"] with_failure = ["failure", "with_backtrace"] -with_anyhow = ["anyhow", "with_backtrace"] +with_anyhow = ["anyhow"] with_log = ["log", "with_backtrace"] with_debug_to_log = ["log"] with_env_logger = ["with_log", "env_logger"] diff --git a/src/integrations/anyhow.rs b/src/integrations/anyhow.rs index ae30e517..0500a58e 100644 --- a/src/integrations/anyhow.rs +++ b/src/integrations/anyhow.rs @@ -2,7 +2,7 @@ //! //! **Feature:** `with_anyhow` (disabled by default) //! -//! This does not support capturing backtraces on nightly. +//! This does not support capturing backtraces (which is a nightly-only feature in anyhow). //! //! # Example //!