Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Commit

Permalink
Only generate backtraces with RUST_BACKTRACE set (closes #7)
Browse files Browse the repository at this point in the history
  • Loading branch information
birkenfeld committed Aug 9, 2016
1 parent 64fb018 commit df58ffe
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ provides a few unique features:
"chain" errors with the `chain_err` method.
* Introducing new errors is trivial. Simple errors can be introduced
at the error site with just a string.
* Errors create and propagate backtraces.
* Errors can create and propagate backtraces.

[Documentation](http://brson.github.io/error-chain/index.html).

Expand Down
50 changes: 31 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//! consistent way - `From` conversion behavior is never specified
//! explicitly.
//! * Errors implement Send.
//! * Errors carry backtraces.
//! * Errors can carry backtraces.
//!
//! Similar to other libraries like [error-type] and [quick-error], this
//! library defines a macro, `error_chain!` that declares the types
Expand Down Expand Up @@ -40,9 +40,9 @@
//! errors.
//! * It provides automatic `From` conversions between any other error
//! type that hides the type of the other error in the `cause` box.
//! * It collects a single backtrace at the earliest opportunity and
//! propagates it down the stack through `From` and `ChainErr`
//! conversions.
//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
//! the earliest opportunity and propagates it down the stack through
//! `From` and `ChainErr` conversions.
//!
//! To accomplish its goals it makes some tradeoffs:
//!
Expand Down Expand Up @@ -175,13 +175,13 @@
//! #[derive(Debug)]
//! pub struct Error(pub ErrorKind,
//! pub Option<Box<StdError + Send>>,
//! pub Arc<error_chain::Backtrace>);
//! pub Option<Arc<error_chain::Backtrace>>);
//!
//! impl Error {
//! pub fn kind(&self) -> &ErrorKind { ... }
//! pub fn into_kind(self) -> ErrorKind { ... }
//! pub fn iter(&self) -> error_chain::ErrorChainIter { ... }
//! pub fn backtrace(&self) -> &error_chain::Backtrace { ... }
//! pub fn backtrace(&self) -> Option<&error_chain::Backtrace> { ... }
//! }
//!
//! impl StdError for Error { ... }
Expand Down Expand Up @@ -293,10 +293,11 @@
//!
//! ## Backtraces
//!
//! The earliest non-foreign error to be generated creates a single
//! backtrace, which is passed through all `From` conversions and
//! `chain_err` invocations of compatible types. To read the backtrace
//! just call the `backtrace()` method.
//! If the `RUST_BACKTRACE` environment variable is set to anything
//! but ``0``, the earliest non-foreign error to be generated creates
//! a single backtrace, which is passed through all `From` conversions
//! and `chain_err` invocations of compatible types. To read the
//! backtrace just call the `backtrace()` method.
//!
//! ## Iteration
//!
Expand Down Expand Up @@ -343,7 +344,7 @@ macro_rules! error_chain {
#[derive(Debug)]
pub struct $error_name(pub $error_kind_name,
pub (Option<Box<::std::error::Error + Send>>,
::std::sync::Arc<$crate::Backtrace>));
Option<::std::sync::Arc<$crate::Backtrace>>));

#[allow(unused)]
impl $error_name {
Expand All @@ -359,8 +360,8 @@ macro_rules! error_chain {
$crate::ErrorChainIter(Some(self))
}

pub fn backtrace(&self) -> &$crate::Backtrace {
&(self.1).1
pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
(self.1).1.as_ref().map(|v| &**v)
}
}

Expand Down Expand Up @@ -402,29 +403,29 @@ macro_rules! error_chain {
fn from(e: $foreign_link_error_path) -> Self {
$error_name(
$error_kind_name::$foreign_link_variant(e),
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
(None, $crate::make_backtrace()))
}
}
) *

impl From<$error_kind_name> for $error_name {
fn from(e: $error_kind_name) -> Self {
$error_name(e,
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
(None, $crate::make_backtrace()))
}
}

impl<'a> From<&'a str> for $error_name {
fn from(s: &'a str) -> Self {
$error_name(s.into(),
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
(None, $crate::make_backtrace()))
}
}

impl From<String> for $error_name {
fn from(s: String) -> Self {
$error_name(s.into(),
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
(None, $crate::make_backtrace()))
}
}

Expand Down Expand Up @@ -500,7 +501,7 @@ macro_rules! error_chain {
let e = Box::new(e) as Box<::std::error::Error + Send + 'static>;
let (e, backtrace) = backtrace_from_box(e);
let backtrace = backtrace.unwrap_or_else(
|| ::std::sync::Arc::new($crate::Backtrace::new()));
|| $crate::make_backtrace());

$error_name(callback().into(), (Some(e), backtrace))
})
Expand All @@ -513,7 +514,7 @@ macro_rules! error_chain {
// machinery to make it work.
fn backtrace_from_box(mut e: Box<::std::error::Error + Send + 'static>)
-> (Box<::std::error::Error + Send + 'static>,
Option<::std::sync::Arc<$crate::Backtrace>>) {
Option<Option<::std::sync::Arc<$crate::Backtrace>>>) {
let mut backtrace = None;

e = match e.downcast::<$error_name>() {
Expand Down Expand Up @@ -657,6 +658,7 @@ macro_rules! error_chain {

use std::error::Error as StdError;
use std::iter::Iterator;
use std::sync::Arc;

pub struct ErrorChainIter<'a>(pub Option<&'a StdError>);

Expand All @@ -673,3 +675,13 @@ impl<'a> Iterator for ErrorChainIter<'a> {
}
}
}

/// Returns a backtrace of the current call stack if `RUST_BACKTRACE`
/// is set to anything but ``0``, and `None` otherwise. This is used
/// in the generated error implementations.
pub fn make_backtrace() -> Option<Arc<Backtrace>> {
match std::env::var_os("RUST_BACKTRACE") {
Some(ref val) if val != "0" => Some(Arc::new(Backtrace::new())),
_ => None
}
}
27 changes: 27 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,33 @@ fn empty() {
error_chain! { };
}

#[test]
fn has_backtrace_depending_on_env() {
use std::env;

error_chain! {
types {}
links {}
foreign_links {}
errors {
MyError
}
}

// missing RUST_BACKTRACE and RUST_BACKTRACE=0
env::remove_var("RUST_BACKTRACE");
let err = Error::from(ErrorKind::MyError);
assert!(err.backtrace().is_none());
env::set_var("RUST_BACKTRACE", "0");
let err = Error::from(ErrorKind::MyError);
assert!(err.backtrace().is_none());

// RUST_BACKTRACE set to anything but 0
env::set_var("RUST_BACKTRACE", "yes");
let err = Error::from(ErrorKind::MyError);
assert!(err.backtrace().is_some());
}

#[cfg(test)]
mod foreign_link_test {

Expand Down

0 comments on commit df58ffe

Please sign in to comment.