Skip to content

Commit 43b70ff

Browse files
committed
feat: add a panic handler to netpulse and netpulsed #13
no human-panic because that has a shitton of deps
1 parent 7d4db02 commit 43b70ff

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

src/bins/netpulse.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313
1414
use getopts::Options;
1515
use netpulse::analyze;
16-
use netpulse::common::{init_logging, print_usage};
16+
use netpulse::common::{init_logging, print_usage, setup_panic_handler};
1717
use netpulse::errors::RunError;
1818
use netpulse::records::{display_group, Check};
1919
use netpulse::store::Store;
2020
use tracing::error;
2121

2222
fn main() {
23+
setup_panic_handler();
2324
init_logging(tracing::Level::INFO);
2425
let args: Vec<String> = std::env::args().collect();
2526
let program = &args[0];

src/bins/netpulsed.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use daemonize::Daemonize;
3131
use getopts::Options;
3232
use netpulse::common::{
3333
confirm, exec_cmd_for_user, getpid, getpid_running, init_logging, print_usage, root_guard,
34+
setup_panic_handler,
3435
};
3536
use netpulse::errors::RunError;
3637
use netpulse::store::Store;
@@ -53,6 +54,7 @@ const SYSTEMD_SERVICE_PATH: &str = "/etc/systemd/system/netpulsed.service";
5354
static USES_DAEMON_SYSTEM: AtomicBool = AtomicBool::new(false);
5455

5556
fn main() -> Result<(), RunError> {
57+
setup_panic_handler();
5658
init_logging(tracing::Level::DEBUG);
5759
let args: Vec<String> = std::env::args().collect();
5860
let program = &args[0];

src/common.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,82 @@ pub fn fmt_timestamp(timestamp: impl Into<DateTime<Local>>) -> String {
293293
let a: chrono::DateTime<chrono::Local> = timestamp.into();
294294
format!("{}", a.format(TIME_FORMAT_HUMANS))
295295
}
296+
297+
/// Sets up a custom panic handler for user-friendly error reporting.
298+
///
299+
/// Should be called early in the program startup, ideally before any other operations.
300+
/// In debug builds, uses the default panic handler for detailed debugging output.
301+
/// In release builds, provides a user-friendly error message with reporting instructions.
302+
///
303+
/// # Example Output
304+
///
305+
/// ```text
306+
/// Well, this is embarrassing.
307+
///
308+
/// netpulse had a problem and crashed. This is a bug and should be reported!
309+
///
310+
/// Technical details:
311+
/// Version: 0.1.0
312+
/// OS: linux x86_64
313+
/// Command: netpulse --check
314+
/// Error: called `Option::unwrap()` on a `None` value
315+
/// Location: src/store.rs:142
316+
///
317+
/// Please create a new issue at https://github.com/PlexSheep/netpulse/issues
318+
/// with the above technical details and what you were doing when this happened.
319+
/// ```
320+
pub fn setup_panic_handler() {
321+
if !cfg!(debug_assertions) {
322+
// Only override in release builds
323+
std::panic::set_hook(Box::new(|panic_info| {
324+
let mut message = String::new();
325+
message.push_str("\nWell, this is embarrassing.\n\n");
326+
message.push_str(&format!(
327+
"{} had a problem and crashed. This is a bug and should be reported!\n\n",
328+
env!("CARGO_PKG_NAME")
329+
));
330+
331+
message.push_str("Technical details:\n");
332+
message.push_str(&format!("Version: {}\n", env!("CARGO_PKG_VERSION")));
333+
334+
// Get OS info
335+
#[cfg(target_os = "linux")]
336+
let os = "linux";
337+
#[cfg(target_os = "macos")]
338+
let os = "macos";
339+
#[cfg(target_os = "windows")]
340+
let os = "windows";
341+
342+
message.push_str(&format!("OS: {} {}\n", os, std::env::consts::ARCH));
343+
344+
// Get command line
345+
let args: Vec<_> = std::env::args().collect();
346+
message.push_str(&format!("Command: {}\n", args.join(" ")));
347+
348+
// Extract error message and location
349+
if let Some(msg) = panic_info.payload().downcast_ref::<&str>() {
350+
message.push_str(&format!("Error: {}\n", msg));
351+
} else if let Some(msg) = panic_info.payload().downcast_ref::<String>() {
352+
message.push_str(&format!("Error: {}\n", msg));
353+
}
354+
355+
if let Some(location) = panic_info.location() {
356+
message.push_str(&format!(
357+
"Location: {}:{}\n",
358+
location.file(),
359+
location.line()
360+
));
361+
}
362+
363+
message.push_str(
364+
"\nPlease create a new issue at https://github.com/PlexSheep/netpulse/issues\n",
365+
);
366+
message.push_str(
367+
"with the above technical details and what you were doing when this happened.\n",
368+
);
369+
370+
eprintln!("{}", message);
371+
std::process::exit(1);
372+
}));
373+
}
374+
}

0 commit comments

Comments
 (0)