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

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

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

rust 复制代码
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!();
}

2. panic 触发异常

rust 复制代码
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));
}

日志如下

debug模式

rust 复制代码
[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 }

release模式

rust 复制代码
[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 })

3. unwrap 触发异常

rust 复制代码
#[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));
}

日志如下

debug模式

rust 复制代码
[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 }

release模式

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

rust 复制代码
[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 })

4. 使用 human_panic

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

注册 hook

rust 复制代码
use human_panic::setup_panic;

pub fn register_panic_hook() {
    setup_panic!();
}

模拟release环境异常

rust 复制代码
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::<i32>().unwrap();
    });
    thread::sleep(Duration::from_secs(1));
}
sh 复制代码
cargo run --bin human_panic --release

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!

报告内容如下

复制代码
"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"""
相关推荐
Rust语言中文社区2 小时前
【Rust日报】 Danube Messaging - 云原生消息平台
开发语言·后端·rust
Rust研习社5 小时前
构建可扩展 Rust 项目:从模块化到 Workspace 工程化实践
rust
好家伙VCC5 小时前
**发散创新:用 Rust实现数据编织(DataWrangling)的高效流式处理架构**在现
java·开发语言·python·架构·rust
本地化文档18 小时前
rustdoc-book-l10n
rust·github·gitcode
Tony Bai21 小时前
Rust 看了流泪,AI 看了沉默:扒开 Go 泛型最让你抓狂的“残疾”类型推断
开发语言·人工智能·后端·golang·rust
jump_jump1 天前
RTK:给 AI 编码助手瘦身的 Rust 代理
性能优化·rust·claude
小杍随笔1 天前
【Rust Exercism 练习详解:Anagram + Space Age + Sublist(附完整代码与深度解读)】
开发语言·rust·c#
Rust研习社1 天前
Rust 字符串与切片实战
rust
朝阳5811 天前
局域网聊天工具
javascript·rust
朝阳5811 天前
我做了一个局域网传文件的小工具,记录一下
javascript·rust