diff --git a/Cargo.lock b/Cargo.lock index 78bd8f5..4b69433 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -66,6 +75,9 @@ name = "anyhow" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +dependencies = [ + "backtrace", +] [[package]] name = "arrayref" @@ -171,6 +183,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bincode" version = "1.3.3" @@ -736,6 +763,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + [[package]] name = "glob" version = "0.3.1" @@ -1128,6 +1161,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -1449,6 +1491,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc_version" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 94f9fce..058902c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ version = "1.0.0-alpha.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.32" +anyhow = {version = "1.0.32", features = ["backtrace"]} async-compression = {version = "0.3.15", features = ["all", "all-algorithms", "tokio"]} async-stream = "0.3.3" async-trait = "0.1.64" diff --git a/src/adapters/custom.rs b/src/adapters/custom.rs index d1c06c1..9e266f0 100644 --- a/src/adapters/custom.rs +++ b/src/adapters/custom.rs @@ -143,15 +143,13 @@ pub fn map_exe_error(err: std::io::Error, exe_name: &str, help: &str) -> anyhow: } } -fn proc_wait(mut child: Child) -> impl AsyncRead { +fn proc_wait(mut child: Child, context: impl FnOnce() -> String) -> impl AsyncRead { let s = stream! { let res = child.wait().await?; if res.success() { yield std::io::Result::Ok(Bytes::new()); } else { - yield std::io::Result::Err(to_io_err( - format_err!("subprocess failed: {:?}", res), - )); + Err(format_err!("{:?}", res)).with_context(context).map_err(to_io_err)?; } }; StreamReader::new(s) @@ -164,6 +162,7 @@ pub fn pipe_output( exe_name: &str, help: &str, ) -> Result { + let cmd_log = format!("{:?}", cmd); // todo: perf let mut cmd = cmd .stdin(Stdio::piped()) .stdout(Stdio::piped()) @@ -177,10 +176,9 @@ pub fn pipe_output( tokio::io::copy(&mut z, &mut stdi).await?; std::io::Result::Ok(()) }); - - Ok(Box::pin( - stdo.chain(proc_wait(cmd).chain(join_handle_to_stream(join))), - )) + Ok(Box::pin(stdo.chain( + proc_wait(cmd, move || format!("subprocess: {cmd_log}")).chain(join_handle_to_stream(join)), + ))) } pub struct CustomSpawningFileAdapter { diff --git a/src/adapters/sqlite.rs b/src/adapters/sqlite.rs index 15541c7..826d091 100644 --- a/src/adapters/sqlite.rs +++ b/src/adapters/sqlite.rs @@ -77,11 +77,13 @@ fn synchronous_dump_sqlite(ai: AdaptInfo, mut s: impl Write) -> Result<()> { return Ok(()); } let inp_fname = filepath_hint; - - let conn = Connection::open_with_flags(inp_fname, OpenFlags::SQLITE_OPEN_READ_ONLY)?; + let conn = Connection::open_with_flags(&inp_fname, OpenFlags::SQLITE_OPEN_READ_ONLY) + .with_context(|| format!("opening sqlite connection to {}", inp_fname.display()))?; let tables: Vec = conn - .prepare("select name from sqlite_master where type='table'")? - .query_map([], |r| r.get::<_, String>(0))? + .prepare("select name from sqlite_master where type='table'") + .context("while preparing query")? + .query_map([], |r| r.get::<_, String>(0)) + .context("while executing query")? .filter_map(|e| e.ok()) .collect(); debug!("db has {} tables", tables.len()); @@ -121,7 +123,9 @@ impl WritingFileAdapter for SqliteAdapter { oup: Pin>, ) -> Result<()> { let oup_sync = SyncIoBridge::new(oup); - tokio::task::spawn_blocking(|| synchronous_dump_sqlite(ai, oup_sync)).await??; + tokio::task::spawn_blocking(|| synchronous_dump_sqlite(ai, oup_sync)) + .await? + .context("in synchronous sqlite task")?; Ok(()) } } diff --git a/src/adapters/writing.rs b/src/adapters/writing.rs index 433c59b..b17152a 100644 --- a/src/adapters/writing.rs +++ b/src/adapters/writing.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use crate::{adapted_iter::one_file, join_handle_to_stream, to_io_err}; use super::{AdaptInfo, FileAdapter, GetMetadata}; -use anyhow::Result; +use anyhow::{Context, Result}; use async_trait::async_trait; use tokio::io::{AsyncReadExt, AsyncWrite}; @@ -51,6 +51,7 @@ where a: super::AdaptInfo, detection_reason: &crate::matching::FileMatcher, ) -> Result { + let name = self.metadata().name.clone(); let (w, r) = tokio::io::duplex(128 * 1024); let d2 = detection_reason.clone(); let archive_recursion_depth = a.archive_recursion_depth + 1; @@ -60,7 +61,10 @@ where let config = a.config.clone(); let joiner = tokio::spawn(async move { let x = d2; - T::adapt_write(a, &x, Box::pin(w)).await.map_err(to_io_err) + T::adapt_write(a, &x, Box::pin(w)) + .await + .with_context(|| format!("in {}.adapt_write", name)) + .map_err(to_io_err) }); Ok(one_file(AdaptInfo { diff --git a/src/bin/rga-preproc.rs b/src/bin/rga-preproc.rs index 7af2ddb..2b25cef 100644 --- a/src/bin/rga-preproc.rs +++ b/src/bin/rga-preproc.rs @@ -43,7 +43,7 @@ async fn main() -> anyhow::Result<()> { // happens if e.g. ripgrep detects binary data in the pipe so it cancels reading debug!("output cancelled (broken pipe)"); } else { - Err(e).context("copying adapter output to stdout {}")?; + Err(e).context("copying adapter output to stdout")?; } } debug!("running adapter took {} total", print_dur(start));