パーフェクトcolor-eyre
color-eyre クレートは、現在Rustに存在する “スタックトレースに類するもの” (BACKTRACEとSPANTRACE) を得る手段としてはおそらく最も進んでおり無視できない存在でしょう。
というわけで、 公式サンプル に手を加えて、もう一つの “スタックトレースに類するもの” を追加してあげましょう!
新規プロジェクトを cargo new で作成し、Cargo.toml は次のようにします。 ( hooq の依存については最新バージョンに置き換えてください。 )
[features]
default = ["capture-spantrace"]
capture-spantrace = []
[dependencies]
color-eyre = "0.6.5"
hooq = { path = "../../hooq" } # Please rewrite `hooq = "*"`
tracing = "0.1.43"
tracing-error = "0.2.1"
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
次に、 ::eyre::WrapErr ではなく color_eyre::eyre::WrapErr をuseしたいので、その上書きを行うhooq.tomlをCargo.tomlと同じ階層に置きます。そのほかの設定は組み込みの eyreフレーバー から引き継がれます!
[eyre]
trait_uses = ["color_eyre::eyre::WrapErr"]
そしてmain.rsを書きます。 use hooq::hooq; し、 #[instrument] の上に #[hooq(eyre)] を付けます1。
use color_eyre::Section;
use color_eyre::eyre::{Report, WrapErr};
use hooq::hooq;
use tracing::{info, instrument};
#[hooq(eyre)]
#[instrument]
fn main() -> Result<(), Report> {
#[cfg(feature = "capture-spantrace")]
install_tracing();
color_eyre::install()?;
read_config()
}
#[cfg(feature = "capture-spantrace")]
fn install_tracing() {
use tracing_error::ErrorLayer;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};
let fmt_layer = fmt::layer().with_target(false).without_time();
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info"))
.unwrap();
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(ErrorLayer::default())
.init();
}
#[hooq(eyre)]
#[instrument]
fn read_file(path: &str) -> Result<(), Report> {
info!("Reading file");
std::fs::read_to_string(path).map(drop)
}
#[hooq(eyre)]
#[instrument]
fn read_config() -> Result<(), Report> {
read_file("fake_file")
.wrap_err("Unable to read config")
.suggestion("try using a file that exists next time")
}
BACKTRACEも見たいので、これを環境変数 RUST_LIB_BACKTRACE=1 を設定した状態で実行してみます。
公式例では .wrap_err() による付与部分で理由しか書かれていなかった部分も、hooqのおかげでスタックトレースもどきに化けています!
Error:
0: [mdbook-source-code/recipe-color-eyre/src/main.rs:14:5]
14> read_config()
|
1: [mdbook-source-code/recipe-color-eyre/src/main.rs:45:5]
45> read_file("fake_file")
46| .wrap_err("Unab..nfig")
47| .suggestion("try ..time")
|
2: Unable to read config
3: [mdbook-source-code/recipe-color-eyre/src/main.rs:39:5]
39> std::fs::read_to_string(path).map(drop)
|
4: No such file or directory (os error 2)
Location:
mdbook-source-code/recipe-color-eyre/src/main.rs:39
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
0: recipe_color_eyre::read_file with path="fake_file"
at mdbook-source-code/recipe-color-eyre/src/main.rs:36
1: recipe_color_eyre::read_config
at mdbook-source-code/recipe-color-eyre/src/main.rs:43
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⋮ 4 frames hidden ⋮
5: <E as eyre::context::ext::StdError>::ext_report::h0e9fcf40b567f05e
at /home/USER/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/eyre-0.6.12/src/context.rs:26
⋮ 1 frame hidden ⋮
7: recipe_color_eyre::read_file::h74782b4bb409e5a9
at /home/USER/workspace/hooq/mdbook-source-code/recipe-color-eyre/src/main.rs:39
8: recipe_color_eyre::read_config::h8139da57eb93337e
at /home/USER/workspace/hooq/mdbook-source-code/recipe-color-eyre/src/main.rs:45
9: recipe_color_eyre::main::h9c27f45de169a3be
at /home/USER/workspace/hooq/mdbook-source-code/recipe-color-eyre/src/main.rs:14
10: core::ops::function::FnOnce::call_once::h724113526cc98cab
at /home/USER/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250
11: std::sys::backtrace::__rust_begin_short_backtrace::h9e20a34286867e4d
at /home/USER/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:158
⋮ 14 frames hidden ⋮
Suggestion: try using a file that exists next time
Run with COLORBT_SHOW_HIDDEN=1 environment variable to disable frame filtering.
Run with RUST_BACKTRACE=full to include source snippets.
多分これが一番詳細だと思います。
-
スナップショットテストの関係で時刻を出力しない
.without_time()も付与しています。 ↩