@@ -293,3 +293,82 @@ pub fn fmt_timestamp(timestamp: impl Into<DateTime<Local>>) -> String {
293
293
let a: chrono:: DateTime < chrono:: Local > = timestamp. into ( ) ;
294
294
format ! ( "{}" , a. format( TIME_FORMAT_HUMANS ) )
295
295
}
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 ( "\n Well, 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
+ "\n Please 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