mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-11-29 05:19:03 -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,7 +47,7 @@ pub struct Args {
|
||||
compare_lens: bool,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
// TODO: ReadOnly should be sufficient but seems to fail.
|
||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
check::run(&conn, &check::Options {
|
||||
|
||||
@@ -54,7 +54,7 @@ pub struct Args {
|
||||
db_dir: PathBuf,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
let clocks = clock::RealClocks {};
|
||||
let db = Arc::new(db::Database::new(clocks, conn, true)?);
|
||||
@@ -77,5 +77,5 @@ pub fn run(args: &Args) -> Result<(), Error> {
|
||||
|
||||
siv.run();
|
||||
|
||||
Ok(())
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
@@ -41,14 +41,14 @@ pub struct Args {
|
||||
db_dir: PathBuf,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::Create)?;
|
||||
|
||||
// Check if the database has already been initialized.
|
||||
let cur_ver = db::get_schema_version(&conn)?;
|
||||
if let Some(v) = cur_ver {
|
||||
info!("Database is already initialized with schema version {}.", v);
|
||||
return Ok(());
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// Use WAL mode (which is the most efficient way to preserve database integrity) with a large
|
||||
@@ -63,5 +63,5 @@ pub fn run(args: &Args) -> Result<(), Error> {
|
||||
"#)?;
|
||||
db::init(&mut conn)?;
|
||||
info!("Database initialized.");
|
||||
Ok(())
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ pub struct Args {
|
||||
username: String,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
let clocks = clock::RealClocks {};
|
||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
let db = std::sync::Arc::new(db::Database::new(clocks.clone(), conn, true).unwrap());
|
||||
@@ -116,7 +116,7 @@ pub fn run(args: &Args) -> Result<(), Error> {
|
||||
} else {
|
||||
println!("s={}", encoded);
|
||||
}
|
||||
Ok(())
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn curl_cookie(cookie: &str, flags: i32, domain: &str) -> String {
|
||||
|
||||
@@ -59,12 +59,12 @@ fn open_dir(db_dir: &Path, mode: OpenMode) -> Result<dir::Fd, Error> {
|
||||
format!("db dir {} not found; try running moonfire-nvr init",
|
||||
db_dir.display())
|
||||
} else {
|
||||
format!("unable to open db dir {}: {}", db_dir.display(), &e)
|
||||
format!("unable to open db dir {}", db_dir.display())
|
||||
}))?;
|
||||
let ro = mode == OpenMode::ReadOnly;
|
||||
dir.lock(if ro { FlockArg::LockSharedNonblock } else { FlockArg::LockExclusiveNonblock })
|
||||
.map_err(|e| e.context(format!("db dir {} already in use; can't get {} lock",
|
||||
db_dir.display(), if ro { "shared" } else { "exclusive" })))?;
|
||||
.map_err(|e| e.context(format!("unable to get {} lock on db dir {} ",
|
||||
if ro { "shared" } else { "exclusive" }, db_dir.display())))?;
|
||||
Ok(dir)
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ struct Syncer {
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn run(args: &Args) -> Result<(), Error> {
|
||||
pub async fn run(args: &Args) -> Result<i32, Error> {
|
||||
let clocks = clock::RealClocks {};
|
||||
let (_db_dir, conn) = super::open_conn(
|
||||
&args.db_dir,
|
||||
@@ -323,5 +323,5 @@ pub async fn run(args: &Args) -> Result<(), Error> {
|
||||
info!("Waiting for HTTP requests to finish.");
|
||||
server_handle.await??;
|
||||
info!("Exiting.");
|
||||
Ok(())
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
use failure::Error;
|
||||
use std::ffi::OsString;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use super::OpenMode;
|
||||
@@ -58,7 +59,7 @@ pub struct Args {
|
||||
arg: Vec<OsString>,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
let mode = if args.read_only { OpenMode::ReadOnly } else { OpenMode::ReadWrite };
|
||||
let _db_dir = super::open_dir(&args.db_dir, mode)?;
|
||||
let mut db = OsString::new();
|
||||
@@ -68,6 +69,5 @@ pub fn run(args: &Args) -> Result<(), Error> {
|
||||
if args.read_only {
|
||||
db.push("?mode=ro");
|
||||
}
|
||||
Command::new("sqlite3").arg(&db).args(&args.arg).status()?;
|
||||
Ok(())
|
||||
Err(Command::new("sqlite3").arg(&db).args(&args.arg).exec().into())
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ pub struct Args {
|
||||
timestamps: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
for timestamp in &args.timestamps {
|
||||
let t = db::recording::Time::parse(timestamp)?;
|
||||
println!("{} == {}", t, t.0);
|
||||
}
|
||||
Ok(())
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
@@ -59,12 +59,13 @@ pub struct Args {
|
||||
no_vacuum: bool,
|
||||
}
|
||||
|
||||
pub fn run(args: &Args) -> Result<(), Error> {
|
||||
pub fn run(args: &Args) -> Result<i32, Error> {
|
||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
|
||||
db::upgrade::run(&db::upgrade::Args {
|
||||
sample_file_dir: args.sample_file_dir.as_ref().map(std::path::PathBuf::as_path),
|
||||
preset_journal: &args.preset_journal,
|
||||
no_vacuum: args.no_vacuum,
|
||||
}, &mut conn)
|
||||
}, &mut conn)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user