Repository: eyre-rs/color-eyre (Rust)

Issue:
Customizability of output of Handler
## Turning off "Backtrace omitted" for end users

CLI tools are published with each circumstance.
In the case the tool is OSS, backtrace and span trace is very useful because the users can investigate problem by themselves (They can also read source code.) and can report to upstream.
In the case the tool is proprietary, backtrace and span trace is also useful, but I think the developer should make the error message easy to read for users (They may not know Rust.), and make it clear by using `note` and `suggestion` what the user should do next.

From this viewpoint,

```
Backtrace omitted.
Run with RUST_BACKTRACE=1 environment variable to display it.
Run with RUST_BACKTRACE=full to include source snippets.
```

may become noise.  I'd like to print this message on debug build and not to do on release build.

## General customizability

More generally, `anyhow` has capability to customize error chain output.  This is a consequence of the fact that the interface of error chain is public.
I used `anyhow` and customized output as below,

```rust
let res = do_something();

if let Err(e) = res {
    eprintln!();
    eprintln!("Error:");

    for (i, e) in e.chain().enumerate() {
        eprintln!("{:>5}: {}", i, e);
    }

    std::process::exit(1);
} else {
    std::process::exit(0);
}
```

because, I guess, as you feel this is better than original one. (Especially, in the case the root cause is `No such file or directory (os error 2)`, or other difficult-to-undestand error message that the developers of CLI tools cannot control.)

If my understanding is correct, current implementation does not allow developers either

1. to customize `eyre::Handler::debug()`, because `struct Handler` has `Vec<HelpInfo>` as a member, but visibility of `HelpInfo` is `pub(crate)`; nor
1. to replace `eyre::Handler`, because, e.g., [`note()` requeres downcasting handler to concrete struct `crate::Handler`](https://github.com/yaahc/color-eyre/blob/7316c8f/src/section/help.rs#L22)

The only available way is forking `color-eyre` and making their own little variant, I guess.  I think we should not make another crate if the developer is satisfied with collecting capability of `color-eyre` (like `note` and `suggestion`.)

What do you think?  I'm a Rust beginner and don't have nice idea to solve the general case...



Discussion:
I think features like this to disable the env info section are good ideas but I also don't think it's a bad thing to fork color-eyre. The hooks are designed to be easy to implement, so it shouldnt be seen as expensive to write your own hooks when customization is needed beyond what general hooks like color-eyre support.

In this case though I'm happy to add a feature to the hook builder to suppress this output.
Thanks.  I agree with you.

I'll think about this a little more.
Alrighty, I've added a feature to disable this section to master, I'll go ahead and make a release shortly so you can start using it.
Thanks Jnae.

I think full customizing capability requires modifying both `eyre` and `color-eyre` drastically, so I agree your change is the current best.



Patch:
diff --git a/src/config.rs b/src/config.rs
index 58ceb6f..869e593 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -246,6 +246,7 @@ impl Frame {
 pub struct HookBuilder {
     filters: Vec<Box<FilterCallback>>,
     capture_span_trace_by_default: bool,
+    display_env_section: bool,
 }
 
 impl HookBuilder {
@@ -277,6 +278,7 @@ impl HookBuilder {
         HookBuilder {
             filters: vec![],
             capture_span_trace_by_default: false,
+            display_env_section: true,
         }
     }
 
@@ -286,6 +288,12 @@ impl HookBuilder {
         self
     }
 
+    /// Configures the enviroment varible info section and whether or not it is displayed
+    pub fn display_env_section(mut self, cond: bool) -> Self {
+        self.display_env_section = cond;
+        self
+    }
+
     /// Add a custom filter to the set of frame filters
     ///
     /// # Examples
@@ -341,11 +349,13 @@ impl HookBuilder {
             filters: self.filters.into_iter().map(Into::into).collect(),
             #[cfg(feature = "capture-spantrace")]
             capture_span_trace_by_default: self.capture_span_trace_by_default,
+            display_env_section: self.display_env_section,
         };
 
         let eyre_hook = EyreHook {
             #[cfg(feature = "capture-spantrace")]
             capture_span_trace_by_default: self.capture_span_trace_by_default,
+            display_env_section: self.display_env_section,
         };
 
         (panic_hook, eyre_hook)
@@ -477,13 +487,15 @@ fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) ->
         )?;
     }
 
-    let env_section = EnvSection {
-        bt_captured: &capture_bt,
-        #[cfg(feature = "capture-spantrace")]
-        span_trace: span_trace.as_ref(),
-    };
+    if printer.display_env_section {
+        let env_section = EnvSection {
+            bt_captured: &capture_bt,
+            #[cfg(feature = "capture-spantrace")]
+            span_trace: span_trace.as_ref(),
+        };
 
-    write!(&mut separated.ready(), "{}", env_section)?;
+        write!(&mut separated.ready(), "{}", env_section)?;
+    }
 
     Ok(())
 }
@@ -492,6 +504,7 @@ pub(crate) struct PanicHook {
     filters: Vec<Arc<FilterCallback>>,
     #[cfg(feature = "capture-spantrace")]
     capture_span_trace_by_default: bool,
+    display_env_section: bool,
 }
 
 impl PanicHook {
@@ -516,6 +529,7 @@ impl PanicHook {
 pub(crate) struct EyreHook {
     #[cfg(feature = "capture-spantrace")]
     capture_span_trace_by_default: bool,
+    display_env_section: bool,
 }
 
 impl EyreHook {
@@ -541,6 +555,7 @@ impl EyreHook {
             #[cfg(feature = "capture-spantrace")]
             span_trace,
             sections: Vec::new(),
+            display_env_section: self.display_env_section,
         }
     }
 
diff --git a/src/handler.rs b/src/handler.rs
index e4b3447..7736c49 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -112,13 +112,15 @@ impl eyre::EyreHandler for Handler {
             f = h.ready();
         }
 
-        let env_section = EnvSection {
-            bt_captured: &self.backtrace.is_some(),
-            #[cfg(feature = "capture-spantrace")]
-            span_trace,
-        };
-
-        write!(&mut separated.ready(), "{}", env_section)?;
+        if self.display_env_section {
+            let env_section = EnvSection {
+                bt_captured: &self.backtrace.is_some(),
+                #[cfg(feature = "capture-spantrace")]
+                span_trace,
+            };
+
+            write!(&mut separated.ready(), "{}", env_section)?;
+        }
 
         Ok(())
     }
diff --git a/src/lib.rs b/src/lib.rs
index 261eacd..7653c5e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -399,6 +399,7 @@ pub struct Handler {
     #[cfg(feature = "capture-spantrace")]
     span_trace: Option<SpanTrace>,
     sections: Vec<HelpInfo>,
+    display_env_section: bool,
 }
 
 static CONFIG: OnceCell<config::PanicHook> = OnceCell::new();


Test patch:
diff --git a/tests/bt_disabled.rs b/tests/bt_disabled.rs
new file mode 100644
index 0000000..4e6f163
--- /dev/null
+++ b/tests/bt_disabled.rs
@@ -0,0 +1,15 @@
+use color_eyre::eyre;
+use eyre::eyre;
+
+#[test]
+fn disabled() {
+    color_eyre::config::HookBuilder::default()
+        .display_env_section(false)
+        .install()
+        .unwrap();
+
+    let report = eyre!("error occured");
+
+    let report = format!("{:?}", report);
+    assert!(!report.contains("RUST_BACKTRACE"));
+}
diff --git a/tests/bt_enabled.rs b/tests/bt_enabled.rs
new file mode 100644
index 0000000..7bc6f03
--- /dev/null
+++ b/tests/bt_enabled.rs
@@ -0,0 +1,15 @@
+use color_eyre::eyre;
+use eyre::eyre;
+
+#[test]
+fn enabled() {
+    color_eyre::config::HookBuilder::default()
+        .display_env_section(true)
+        .install()
+        .unwrap();
+
+    let report = eyre!("error occured");
+
+    let report = format!("{:?}", report);
+    assert!(report.contains("RUST_BACKTRACE"));
+}