mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-12-05 15:22:29 -05:00
overhaul error messages
Inspired by the poor error message here: https://github.com/scottlamb/moonfire-nvr/issues/107#issuecomment-777587727 * print the friendlier Display version of the error rather than Debug. Eg, "EROFS: Read-only filesystem" rather than "Sys(EROFS)". Do this everywhere: on command exit, on syncer retries, and on stream retries. * print the most immediate problem and additional lines for each cause. * print the backtrace or an advertisement for RUST_BACKTRACE=1 if it's unavailable. * also mention RUST_BACKTRACE=1 in the troubleshooting guide. * add context in various places, including pathnames. There are surely many places more it'd be helpful, but this is a start. * allow subcommands to return failure without an Error. In particular, "moonfire-nvr check" does its own error printing because it wants to print all the errors it finds. Printing "see earlier errors" with a meaningless stack trace seems like it'd just confuse. But I also want to get rid of the misleading "Success" at the end and 0 return to the OS.
This commit is contained in:
@@ -47,13 +47,16 @@ pub struct Options {
|
||||
pub compare_lens: bool,
|
||||
}
|
||||
|
||||
pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<(), Error> {
|
||||
pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<i32, Error> {
|
||||
let mut printed_error = false;
|
||||
|
||||
// Compare schemas.
|
||||
{
|
||||
let mut expected = rusqlite::Connection::open_in_memory()?;
|
||||
db::init(&mut expected)?;
|
||||
if let Some(diffs) = compare::get_diffs("actual", conn, "expected", &expected)? {
|
||||
println!("{}", &diffs);
|
||||
error!("Schema is not as expected:\n{}", &diffs);
|
||||
printed_error = true;
|
||||
} else {
|
||||
println!("Schema is as expected.");
|
||||
}
|
||||
@@ -88,7 +91,8 @@ pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
// Open the directory (checking its metadata) and hold it open (for the lock).
|
||||
let dir = dir::SampleFileDir::open(&dir_path, &meta)?;
|
||||
let dir = dir::SampleFileDir::open(&dir_path, &meta)
|
||||
.map_err(|e| e.context(format!("unable to open dir {}", dir_path)))?;
|
||||
let mut streams = read_dir(&dir, opts)?;
|
||||
let mut rows = garbage_stmt.query(params![dir_id])?;
|
||||
while let Some(row) = rows.next()? {
|
||||
@@ -113,7 +117,7 @@ pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<(), Error> {
|
||||
None => Stream::default(),
|
||||
Some(d) => d.remove(&stream_id).unwrap_or_else(Stream::default),
|
||||
};
|
||||
compare_stream(conn, stream_id, opts, stream)?;
|
||||
printed_error |= compare_stream(conn, stream_id, opts, stream)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,12 +129,13 @@ pub fn run(conn: &rusqlite::Connection, opts: &Options) -> Result<(), Error> {
|
||||
if r.recording_row.is_some() || r.playback_row.is_some() ||
|
||||
r.integrity_row || !r.garbage_row {
|
||||
error!("dir {} recording {} for unknown stream: {:#?}", dir_id, id, r);
|
||||
printed_error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(if printed_error { 1 } else { 0 })
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
@@ -217,9 +222,10 @@ fn read_dir(d: &dir::SampleFileDir, opts: &Options) -> Result<Dir, Error> {
|
||||
|
||||
/// Looks through a known stream for errors.
|
||||
fn compare_stream(conn: &rusqlite::Connection, stream_id: i32, opts: &Options,
|
||||
mut stream: Stream) -> Result<(), Error> {
|
||||
mut stream: Stream) -> Result<bool, Error> {
|
||||
let start = CompositeId::new(stream_id, 0);
|
||||
let end = CompositeId::new(stream_id, i32::max_value());
|
||||
let mut printed_error = false;
|
||||
|
||||
// recording row.
|
||||
{
|
||||
@@ -271,6 +277,7 @@ fn compare_stream(conn: &rusqlite::Connection, stream_id: i32, opts: &Options,
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
error!("id {} has bad video_index: {}", id, e);
|
||||
printed_error = true;
|
||||
continue;
|
||||
},
|
||||
};
|
||||
@@ -307,6 +314,7 @@ fn compare_stream(conn: &rusqlite::Connection, stream_id: i32, opts: &Options,
|
||||
if !recording.garbage_row || recording.playback_row.is_some() ||
|
||||
recording.integrity_row {
|
||||
error!("Missing recording row for {}: {:#?}", id, recording);
|
||||
printed_error = true;
|
||||
}
|
||||
continue;
|
||||
},
|
||||
@@ -315,17 +323,25 @@ fn compare_stream(conn: &rusqlite::Connection, stream_id: i32, opts: &Options,
|
||||
Some(ref p) => {
|
||||
if r != p {
|
||||
error!("Recording {} summary doesn't match video_index: {:#?}", id, recording);
|
||||
printed_error = true;
|
||||
}
|
||||
},
|
||||
None => error!("Recording {} missing playback row: {:#?}", id, recording),
|
||||
None => {
|
||||
error!("Recording {} missing playback row: {:#?}", id, recording);
|
||||
printed_error = true;
|
||||
},
|
||||
}
|
||||
match recording.file {
|
||||
Some(len) => if opts.compare_lens && r.bytes != len {
|
||||
error!("Recording {} length mismatch: {:#?}", id, recording);
|
||||
printed_error = true;
|
||||
},
|
||||
None => {
|
||||
error!("Recording {} missing file: {:#?}", id, recording);
|
||||
printed_error = true;
|
||||
},
|
||||
None => error!("Recording {} missing file: {:#?}", id, recording),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(printed_error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user