extension_eyre/lib.rs
1//! # About this crate
2//!
3//! Re-export of [`color-eyre`] crate that introduces `Extensions`.
4//!
5//! See [extensions](extensions) module documentation to learn how to use [`Extension`](extensions::Extension) and [`ExtensionExt`](extensions::ExtensionExt), .
6//!
7//! Rest of the doc here is the same as in [`color-eyre`].
8//!
9//! # extension-eyre
10//!
11//! An error report handler for panics and the [`eyre`] crate for colorful, consistent, and well
12//! formatted error reports for all kinds of errors.
13//!
14//! ## TLDR
15//!
16//! `extension_eyre` helps you build error reports that look like this:
17//!
18//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span>
19//! <span style="color: #4E9A06"><b>❯</b></span> cargo run --example custom_section
20//! <span style="color: #4E9A06"><b> Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
21//! <span style="color: #4E9A06"><b> Running</b></span> `target/debug/examples/custom_section`
22//! Error:
23//! 0: <span style="color: #F15D22">Unable to read config</span>
24//! 1: <span style="color: #F15D22">cmd exited with non-zero status code</span>
25//!
26//! Stderr:
27//! cat: fake_file: No such file or directory
28//!
29//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
30//!
31//! 0: <span style="color: #F15D22">custom_section::output2</span> with <span style="color: #34E2E2">self="cat" "fake_file"</span>
32//! at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">14</span>
33//! 1: <span style="color: #F15D22">custom_section::read_file</span> with <span style="color: #34E2E2">path="fake_file"</span>
34//! at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">58</span>
35//! 2: <span style="color: #F15D22">custom_section::read_config</span>
36//! at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">63</span>
37//!
38//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
39//!
40//! ## Setup
41//!
42//! Add the following to your toml file:
43//!
44//! ```toml
45//! [dependencies]
46//! extension-eyre = "0.6"
47//! ```
48//!
49//! And install the panic and error report handlers:
50//!
51//! ```rust
52//! use extension_eyre::eyre::Result;
53//!
54//! fn main() -> Result<()> {
55//! extension_eyre::install()?;
56//!
57//! // ...
58//! # Ok(())
59//! }
60//! ```
61//!
62//! ### Disabling tracing support
63//!
64//! If you don't plan on using `tracing_error` and `SpanTrace` you can disable the
65//! tracing integration to cut down on unused dependencies:
66//!
67//! ```toml
68//! [dependencies]
69//! extension-eyre = { version = "0.6", default-features = false }
70//! ```
71//!
72//! ### Disabling SpanTrace capture by default
73//!
74//! extension-eyre defaults to capturing span traces. This is because `SpanTrace`
75//! capture is significantly cheaper than `Backtrace` capture. However, like
76//! backtraces, span traces are most useful for debugging applications, and it's
77//! not uncommon to want to disable span trace capture by default to keep noise out
78//! developer.
79//!
80//! To disable span trace capture you must explicitly set one of the env variables
81//! that regulate `SpanTrace` capture to `"0"`:
82//!
83//! ```rust
84//! if std::env::var("RUST_SPANTRACE").is_err() {
85//! std::env::set_var("RUST_SPANTRACE", "0");
86//! }
87//! ```
88//!
89//! ### Improving perf on debug builds
90//!
91//! In debug mode `extension-eyre` behaves noticably worse than `eyre`. This is caused
92//! by the fact that `eyre` uses `std::backtrace::Backtrace` instead of
93//! `backtrace::Backtrace`. The std version of backtrace is precompiled with
94//! optimizations, this means that whether or not you're in debug mode doesn't
95//! matter much for how expensive backtrace capture is, it will always be in the
96//! 10s of milliseconds to capture. A debug version of `backtrace::Backtrace`
97//! however isn't so lucky, and can take an order of magnitude more time to capture
98//! a backtrace compared to its std counterpart.
99//!
100//! Cargo [profile
101//! overrides](https://doc.rust-lang.org/cargo/reference/profiles.html#overrides)
102//! can be used to mitigate this problem. By configuring your project to always
103//! build `backtrace` with optimizations you should get the same performance from
104//! `extension-eyre` that you're used to with `eyre`. To do so add the following to
105//! your Cargo.toml:
106//!
107//! ```toml
108//! [profile.dev.package.backtrace]
109//! opt-level = 3
110//! ```
111//!
112//! ## Features
113//!
114//! ### Multiple report format verbosity levels
115//!
116//! `extension-eyre` provides 3 different report formats for how it formats the captured `SpanTrace`
117//! and `Backtrace`, minimal, short, and full. Take the below snippets of the output produced by [`examples/usage.rs`]:
118//!
119//! ---
120//!
121//! Running `cargo run --example usage` without `RUST_LIB_BACKTRACE` set will produce a minimal
122//! report like this:
123//!
124//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span> took <span style="color: #C4A000"><b>2s</b></span>
125//! <span style="color: #CC0000"><b>❯</b></span> cargo run --example usage
126//! <span style="color: #4E9A06"><b> Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
127//! <span style="color: #4E9A06"><b> Running</b></span> `target/debug/examples/usage`
128//! <span style="color: #A1A1A1">Jul 05 19:15:58.026 </span><span style="color: #4E9A06"> INFO</span> <b>read_config</b>:<b>read_file{</b>path="fake_file"<b>}</b>: Reading file
129//! Error:
130//! 0: <span style="color: #F15D22">Unable to read config</span>
131//! 1: <span style="color: #F15D22">No such file or directory (os error 2)</span>
132//!
133//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
134//!
135//! 0: <span style="color: #F15D22">usage::read_file</span> with <span style="color: #34E2E2">path="fake_file"</span>
136//! at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">32</span>
137//! 1: <span style="color: #F15D22">usage::read_config</span>
138//! at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">38</span>
139//!
140//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
141//!
142//! <br>
143//!
144//! Running `RUST_LIB_BACKTRACE=1 cargo run --example usage` tells `extension-eyre` to use the short
145//! format, which additionally capture a [`backtrace::Backtrace`]:
146//!
147//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span>
148//! <span style="color: #CC0000"><b>❯</b></span> RUST_LIB_BACKTRACE=1 cargo run --example usage
149//! <span style="color: #4E9A06"><b> Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
150//! <span style="color: #4E9A06"><b> Running</b></span> `target/debug/examples/usage`
151//! <span style="color: #A1A1A1">Jul 05 19:16:02.853 </span><span style="color: #4E9A06"> INFO</span> <b>read_config</b>:<b>read_file{</b>path="fake_file"<b>}</b>: Reading file
152//! Error:
153//! 0: <span style="color: #F15D22">Unable to read config</span>
154//! 1: <span style="color: #F15D22">No such file or directory (os error 2)</span>
155//!
156//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
157//!
158//! 0: <span style="color: #F15D22">usage::read_file</span> with <span style="color: #34E2E2">path="fake_file"</span>
159//! at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">32</span>
160//! 1: <span style="color: #F15D22">usage::read_config</span>
161//! at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">38</span>
162//!
163//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
164//! <span style="color: #34E2E2"> ⋮ 5 frames hidden ⋮ </span>
165//! 6: <span style="color: #F15D22">usage::read_file</span><span style="color: #88807C">::haee210cb22460af3</span>
166//! at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">35</span>
167//! 7: <span style="color: #F15D22">usage::read_config</span><span style="color: #88807C">::ha649ef4ec333524d</span>
168//! at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">40</span>
169//! 8: <span style="color: #F15D22">usage::main</span><span style="color: #88807C">::hbe443b50eac38236</span>
170//! at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">11</span>
171//! <span style="color: #34E2E2"> ⋮ 10 frames hidden ⋮ </span>
172//!
173//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
174//!
175//! <br>
176//!
177//! Finally, running `RUST_LIB_BACKTRACE=full cargo run --example usage` tells `extension-eyre` to use
178//! the full format, which in addition to the above will attempt to include source lines where the
179//! error originated from, assuming it can find them on the disk.
180//!
181//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span>
182//! <span style="color: #CC0000"><b>❯</b></span> RUST_LIB_BACKTRACE=full cargo run --example usage
183//! <span style="color: #4E9A06"><b> Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.05s
184//! <span style="color: #4E9A06"><b> Running</b></span> `target/debug/examples/usage`
185//! <span style="color: #A1A1A1">Jul 05 19:16:06.335 </span><span style="color: #4E9A06"> INFO</span> <b>read_config</b>:<b>read_file{</b>path="fake_file"<b>}</b>: Reading file
186//! Error:
187//! 0: <span style="color: #F15D22">Unable to read config</span>
188//! 1: <span style="color: #F15D22">No such file or directory (os error 2)</span>
189//!
190//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
191//!
192//! 0: <span style="color: #F15D22">usage::read_file</span> with <span style="color: #34E2E2">path="fake_file"</span>
193//! at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">32</span>
194//! 30 │ }
195//! 31 │
196//! <b> 32 > #[instrument]</b>
197//! 33 │ fn read_file(path: &str) -> Result<(), Report> {
198//! 34 │ info!("Reading file");
199//! 1: <span style="color: #F15D22">usage::read_config</span>
200//! at <span style="color: #75507B">examples/usage.rs</span>:<span style="color: #75507B">38</span>
201//! 36 │ }
202//! 37 │
203//! <b> 38 > #[instrument]</b>
204//! 39 │ fn read_config() -> Result<(), Report> {
205//! 40 │ read_file("fake_file")
206//!
207//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
208//! <span style="color: #34E2E2"> ⋮ 5 frames hidden ⋮ </span>
209//! 6: <span style="color: #F15D22">usage::read_file</span><span style="color: #88807C">::haee210cb22460af3</span>
210//! at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">35</span>
211//! 33 │ fn read_file(path: &str) -> Result<(), Report> {
212//! 34 │ info!("Reading file");
213//! <span style="color: #D3D7CF"><b> 35 > Ok(std::fs::read_to_string(path).map(drop)?)</b></span>
214//! 36 │ }
215//! 37 │
216//! 7: <span style="color: #F15D22">usage::read_config</span><span style="color: #88807C">::ha649ef4ec333524d</span>
217//! at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">40</span>
218//! 38 │ #[instrument]
219//! 39 │ fn read_config() -> Result<(), Report> {
220//! <span style="color: #D3D7CF"><b> 40 > read_file("fake_file")</b></span>
221//! 41 │ .wrap_err("Unable to read config")
222//! 42 │ .suggestion("try using a file that exists next time")
223//! 8: <span style="color: #F15D22">usage::main</span><span style="color: #88807C">::hbe443b50eac38236</span>
224//! at <span style="color: #75507B">/home/jlusby/git/yaahc/extension-eyre/examples/usage.rs</span>:<span style="color: #75507B">11</span>
225//! 9 │ extension_eyre::install()?;
226//! 10 │
227//! <span style="color: #D3D7CF"><b> 11 > Ok(read_config()?)</b></span>
228//! 12 │ }
229//! 13 │
230//! <span style="color: #34E2E2"> ⋮ 10 frames hidden ⋮ </span>
231//!
232//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
233//!
234//! ### Custom `Section`s for error reports via [`Section`] trait
235//!
236//! The `section` module provides helpers for adding extra sections to error
237//! reports. Sections are disinct from error messages and are displayed
238//! independently from the chain of errors. Take this example of adding sections
239//! to contain `stderr` and `stdout` from a failed command, taken from
240//! [`examples/custom_section.rs`]:
241//!
242//! ```rust
243//! use extension_eyre::{eyre::eyre, SectionExt, Section, eyre::Report};
244//! use std::process::Command;
245//! use tracing::instrument;
246//!
247//! trait Output {
248//! fn output2(&mut self) -> Result<String, Report>;
249//! }
250//!
251//! impl Output for Command {
252//! #[instrument]
253//! fn output2(&mut self) -> Result<String, Report> {
254//! let output = self.output()?;
255//!
256//! let stdout = String::from_utf8_lossy(&output.stdout);
257//!
258//! if !output.status.success() {
259//! let stderr = String::from_utf8_lossy(&output.stderr);
260//! Err(eyre!("cmd exited with non-zero status code"))
261//! .with_section(move || stdout.trim().to_string().header("Stdout:"))
262//! .with_section(move || stderr.trim().to_string().header("Stderr:"))
263//! } else {
264//! Ok(stdout.into())
265//! }
266//! }
267//! }
268//! ```
269//!
270//! ---
271//!
272//! Here we have an function that, if the command exits unsuccessfully, creates a
273//! report indicating the failure and attaches two sections, one for `stdout` and
274//! one for `stderr`.
275//!
276//! Running `cargo run --example custom_section` shows us how these sections are
277//! included in the output:
278//!
279//! <pre><span style="color: #06989A"><b>extension-eyre</b></span> on <span style="color: #75507B"><b> hooked</b></span> <span style="color: #CC0000"><b>[$!] </b></span>is <span style="color: #FF8700"><b>📦 v0.5.0</b></span> via <span style="color: #CC0000"><b>🦀 v1.44.0</b></span> took <span style="color: #C4A000"><b>2s</b></span>
280//! <span style="color: #CC0000"><b>❯</b></span> cargo run --example custom_section
281//! <span style="color: #4E9A06"><b> Finished</b></span> dev [unoptimized + debuginfo] target(s) in 0.04s
282//! <span style="color: #4E9A06"><b> Running</b></span> `target/debug/examples/custom_section`
283//! Error:
284//! 0: <span style="color: #F15D22">Unable to read config</span>
285//! 1: <span style="color: #F15D22">cmd exited with non-zero status code</span>
286//!
287//! Stderr:
288//! cat: fake_file: No such file or directory
289//!
290//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
291//!
292//! 0: <span style="color: #F15D22">custom_section::output2</span> with <span style="color: #34E2E2">self="cat" "fake_file"</span>
293//! at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">14</span>
294//! 1: <span style="color: #F15D22">custom_section::read_file</span> with <span style="color: #34E2E2">path="fake_file"</span>
295//! at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">58</span>
296//! 2: <span style="color: #F15D22">custom_section::read_config</span>
297//! at <span style="color: #75507B">examples/custom_section.rs</span>:<span style="color: #75507B">63</span>
298//!
299//! <span style="color: #34E2E2">Suggestion</span>: try using a file that exists next time</pre>
300//!
301//! Only the `Stderr:` section actually gets included. The `cat` command fails,
302//! so stdout ends up being empty and is skipped in the final report. This gives
303//! us a short and concise error report indicating exactly what was attempted and
304//! how it failed.
305//!
306//! ### Aggregating multiple errors into one report
307//!
308//! It's not uncommon for programs like batched task runners or parsers to want
309//! to return an error with multiple sources. The current version of the error
310//! trait does not support this use case very well, though there is [work being
311//! done](https://github.com/rust-lang/rfcs/pull/2895) to improve this.
312//!
313//! For now however one way to work around this is to compose errors outside the
314//! error trait. `extension-eyre` supports such composition in its error reports via
315//! the `Section` trait.
316//!
317//! For an example of how to aggregate errors check out [`examples/multiple_errors.rs`].
318//!
319//! ### Custom configuration for `color-backtrace` for setting custom filters and more
320//!
321//! The pretty printing for backtraces and span traces isn't actually provided by
322//! `extension-eyre`, but instead comes from its dependencies [`color-backtrace`] and
323//! [`color-spantrace`]. `color-backtrace` in particular has many more features
324//! than are exported by `extension-eyre`, such as customized color schemes, panic
325//! hooks, and custom frame filters. The custom frame filters are particularly
326//! useful when combined with `extension-eyre`, so to enable their usage we provide
327//! the `install` fn for setting up a custom `BacktracePrinter` with custom
328//! filters installed.
329//!
330//! For an example of how to setup custom filters, check out [`examples/custom_filter.rs`].
331//!
332//! [`eyre`]: https://docs.rs/eyre
333//! [`color-eyre`]: https://docs.rs/color-eyre
334//! [`tracing-error`]: https://docs.rs/tracing-error
335//! [`color-backtrace`]: https://docs.rs/color-backtrace
336//! [`eyre::EyreHandler`]: https://docs.rs/eyre/*/eyre/trait.EyreHandler.html
337//! [`backtrace::Backtrace`]: https://docs.rs/backtrace/*/backtrace/struct.Backtrace.html
338//! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html
339//! [`color-spantrace`]: https://github.com/yaahc/color-spantrace
340//! [`Section`]: https://docs.rs/color-eyre/*/extension_eyre/trait.Section.html
341//! [`eyre::Report`]: https://docs.rs/eyre/*/eyre/struct.Report.html
342//! [`eyre::Result`]: https://docs.rs/eyre/*/eyre/type.Result.html
343//! [`Handler`]: https://docs.rs/color-eyre/*/extension_eyre/struct.Handler.html
344//! [`examples/usage.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/usage.rs
345//! [`examples/custom_filter.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/custom_filter.rs
346//! [`examples/custom_section.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/custom_section.rs
347//! [`examples/multiple_errors.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/multiple_errors.rs
348#![doc(html_root_url = "https://docs.rs/color-eyre/0.6.2")]
349#![cfg_attr(docsrs, feature(doc_cfg))]
350#![warn(
351 missing_docs,
352 rustdoc::missing_doc_code_examples,
353 rust_2018_idioms,
354 unreachable_pub,
355 bad_style,
356 const_err,
357 dead_code,
358 improper_ctypes,
359 non_shorthand_field_patterns,
360 no_mangle_generic_items,
361 overflowing_literals,
362 path_statements,
363 patterns_in_fns_without_body,
364 private_in_public,
365 unconditional_recursion,
366 unused,
367 unused_allocation,
368 unused_comparisons,
369 unused_parens,
370 while_true
371)]
372#![allow(clippy::try_err)]
373
374use std::ops::Deref;
375use std::ops::DerefMut;
376
377pub use color_eyre::owo_colors;
378pub use eyre;
379#[doc(hidden)]
380pub use eyre::Report;
381#[doc(hidden)]
382pub use eyre::Result;
383#[cfg(feature = "capture-spantrace")]
384#[doc(hidden)]
385pub use Handler as Context;
386
387pub mod config;
388pub mod extensions;
389mod handler;
390pub(crate) mod private;
391
392pub use color_eyre::IndentedSection;
393pub use extensions::{Extension, ExtensionExt};
394#[doc(hidden)]
395pub use color_eyre::section::Section as Help;
396pub use color_eyre::section::{Section, SectionExt};
397
398/// A custom handler type for [`eyre::Report`] which provides colorful error
399/// reports and [`tracing-error`] support.
400///
401/// # Details
402///
403/// This type is not intended to be used directly, prefer using it via the
404/// [`extension_eyre::Report`] and [`extension_eyre::Result`] type aliases.
405///
406/// [`eyre::Report`]: https://docs.rs/eyre/*/eyre/struct.Report.html
407/// [`tracing-error`]: https://docs.rs/tracing-error
408/// [`extension_eyre::Report`]: type.Report.html
409/// [`extension_eyre::Result`]: type.Result.html
410pub struct Handler {
411 extensions: extensions::Extensions,
412 inner: Box<dyn eyre::EyreHandler>,
413}
414
415impl Deref for Handler {
416 type Target = Box<dyn eyre::EyreHandler>;
417
418 fn deref(&self) -> &Self::Target {
419 &self.inner
420 }
421}
422
423impl DerefMut for Handler {
424 fn deref_mut(&mut self) -> &mut Self::Target {
425 &mut self.inner
426 }
427}
428
429/// The kind of type erased error being reported
430#[cfg(feature = "issue-url")]
431#[cfg_attr(docsrs, doc(cfg(feature = "issue-url")))]
432pub enum ErrorKind<'a> {
433 /// A non recoverable error aka `panic!`
434 NonRecoverable(&'a dyn std::any::Any),
435 /// A recoverable error aka `impl std::error::Error`
436 Recoverable(&'a (dyn std::error::Error + 'static)),
437}
438
439/// Install the default panic and error report hooks
440///
441/// # Details
442///
443/// This function must be called to enable the customization of `eyre::Report`
444/// provided by `color-eyre`. This function should be called early, ideally
445/// before any errors could be encountered.
446///
447/// Only the first install will succeed. Calling this function after another
448/// report handler has been installed will cause an error. **Note**: This
449/// function _must_ be called before any `eyre::Report`s are constructed to
450/// prevent the default handler from being installed.
451///
452/// Installing a global theme in `color_spantrace` manually (by calling
453/// `color_spantrace::set_theme` or `color_spantrace::colorize` before
454/// `install` is called) will result in an error if this function is called.
455///
456/// # Examples
457///
458/// ```rust
459/// use extension_eyre::eyre::Result;
460///
461/// fn main() -> Result<()> {
462/// extension_eyre::install()?;
463///
464/// // ...
465/// # Ok(())
466/// }
467/// ```
468pub fn install() -> Result<(), crate::eyre::Report> {
469 config::HookBuilder::default().install()
470}