• rust - 捕获全局panic并记录进程退出日志


    本文提供了捕获全局panic并记录进程退出日志的方法。

    1. 使用 panic::set_hook 注册异常处理

    use human_panic::setup_panic;
    use log::error;
    use std::{boxed::Box, panic};
    
    fn hook(panic_info: &panic::PanicInfo) {
        if cfg!(debug_assertions) {
            let err_message = format!("panic occurred {:?}", panic_info);
            error!("{}", err_message);
        } else {
            let err_message = match panic_info.payload().downcast_ref::<&str>() {
                Option::Some(&str) => {
                    let err_message = format!(
                        "panic info: {:?}, occurred in {:?}",
                        str,
                        panic_info.location()
                    );
                    err_message
                }
                Option::None => {
                    let err_message =
                        format!("panic occurred in {:?}", panic_info.location());
                    err_message
                }
            };
            error!("{}", err_message);
        }
    }
    
    /// 注册异常处理函数
    /// 在panic发出后,在panic运行时之前,触发钩子函数去处理这个panic信息。
    /// panic信息被保存在PanicInfo结构体中。
    pub fn register_panic_hook() {
        panic::set_hook(Box::new(|panic_info| {
            hook(panic_info);
        }));
        // setup_panic!();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2. panic 触发异常

    use core_utils::panic::register_panic_hook;
    use core_utils::panic::register_panic_hook;
    use env_logger;
    use log::LevelFilter;
    use std::thread;
    use std::time::Duration;
    
    #[test]
    fn test_panic_set_hook() {
        let _ = env_logger::builder()
            .is_test(true)
            .filter(None, LevelFilter::Debug)
            .try_init();
    
        register_panic_hook();
    
        thread::spawn(|| {
            panic!("child thread panic");
        });
    
        thread::sleep(Duration::from_millis(100));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    日志如下

    debug模式

    [2024-04-20T05:32:30Z ERROR core_utils::panic] panic occurred PanicInfo { payload: Any { .. }, message: Some(child thread panic), location: Location { file: "core_utils/tests/test_panic.rs", line: 16, col: 9 }, can_unwind: true, force_no_backtrace: false }
    
    • 1

    release模式

    [2024-04-20T05:41:06Z ERROR core_utils::panic] panic info: "child thread panic", occurred in Some(Location { file: "core_utils/tests/test_panic.rs", line: 17, col: 9 })
    
    • 1

    3. unwrap 触发异常

    #[test]
    fn test_panic_unwrap() {
        let _ = env_logger::builder()
            .is_test(true)
            .filter(None, LevelFilter::Debug)
            .try_init();
    
        register_panic_hook();
    
        thread::spawn(|| {
            let _ = "abc".parse::<i32>().unwrap();
        });
    
        thread::sleep(Duration::from_millis(100));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    日志如下

    debug模式

    [2024-04-20T05:38:22Z ERROR core_utils::panic] panic occurred PanicInfo { payload: Any { .. }, message: Some(called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }), location: Location { file: "core_utils/tests/test_panic.rs", line: 33, col: 38 }, can_unwind: true, force_no_backtrace: false }
    
    • 1

    release模式

    注意:unwrap触发的异常会导致 panic_info.payload().downcast_ref::<&str>()返回结果为 None

    [2024-04-20T05:42:34Z ERROR core_utils::panic] panic occurred in Some(Location { file: "core_utils/tests/test_panic.rs", line: 33, col: 38 })
    
    • 1

    4. 使用 human_panic

    human_panic只能在非debug模式且环境变量RUST_BACKTRACE未设置的情况下才会生效。

    注册 hook

    use human_panic::setup_panic;
    
    pub fn register_panic_hook() {
        setup_panic!();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    模拟release环境异常

    use core_utils::panic::register_panic_hook;
    use env_logger;
    use human_panic::setup_panic;
    use log::error;
    use std::thread;
    use std::time::Duration;
    
    fn main() {
        env_logger::init();
    
        register_panic_hook();
    
        thread::spawn(|| {
            panic!("error");
            // let _ = "abc".parse::().unwrap();
        });
        thread::sleep(Duration::from_secs(1));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    cargo run --bin human_panic --release
    
    • 1

    panic发生时会在在临时文件夹下面创建一个报告文件

    Well, this is embarrassing.
    
    core_utils had a problem and crashed. To help us diagnose the problem you can send us a crash report.
    
    We have generated a report file at "/var/folders/gx/hn6l2rd56cx0lcwnkblxqvmr0000gn/T/report-93547ab5-9341-4212-a9af-6d2f17d6311d.toml". Submit an issue or email with the subject of "core_utils Crash Report" and include the report as an attachment.
    
    
    We take privacy seriously, and do not perform any automated error collection. In order to improve the software, we rely on people to submit reports.
    
    Thank you kindly!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    报告内容如下

    "name" = "core_utils"
    "operating_system" = "Mac OS 14.1.1 [64-bit]"
    "crate_version" = "0.1.0"
    "explanation" = """
    Panic occurred in file 'core_utils/src/bin/human_panic.rs' at line 14
    """
    "cause" = "error"
    "method" = "Panic"
    "backtrace" = """
    
       0: 0x105b840a5 - core::panicking::panic_fmt::h2aac8cf45f7ae617
       1: 0x1059fd7c6 - std::sys_common::backtrace::__rust_begin_short_backtrace::h4bae865db206eae3
       2: 0x1059fe2fd - core::ops::function::FnOnce::call_once{{vtable.shim}}::ha8d441119e8b7a5a
       3: 0x105b5a819 - std::sys::pal::unix::thread::Thread::new::thread_start::h679ffa03f8a73496
       4: 0x7ff801993202 - __pthread_start"""
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    leetcode234 回文链表
    java计算机毕业设计基于安卓Android的助农商城APP-农业信息app
    HAproxy反向代理与负载均衡
    用核心AI资产打造稀缺电竞体验,顺网灵悉背后有一盘大棋
    MySQL如何对SQL做prepare预处理(解决IN查询SQL预处理仅能查询出一条记录的问题)
    html静态商城网页制作 基于HTML+CSS+JavaScript在线服装商城店铺商城设计毕业论文源码
    Grok AI 是什么?
    【JVM】java内存区域
    读懂NFT地板价
    IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Maven核心概念
  • 原文地址:https://blog.csdn.net/liuyuan_jq/article/details/137998743