当前位置: 首页 > news >正文

【Qt】为程序增加闪退crash报告日志

背景

随着软件代码量的增加,软件崩溃闪退的肯能行越来越大,其中一些是难以复现的,比如访问了访问了非法地址、被操作系统杀死等。

为此,在软件出现闪退情况时,尽可能多的记录闪退发生时信息,对排查闪退原因是非常有帮助的。

实现

因为闪退发生时软件已经不在运行了,因此需要在闪退前就告诉操作系统闪退后需要执行的操作,在Qt中就是在QApplicationexec()前调用操作系统提供的接口,注册闪退后的处理函数。

我们以Windows平台为例,在Windows平台,时利用SetUnhandledExceptionFilter函数实现异常(闪退)处理函数的注册的。

简单代码如下:

#include <QApplication>

#ifdef Q_OS_WIN
#include <windows.h>
#include <psapi.h>
#include <DbgHelp.h>
#include <fstream>
#include <sstream>

#pragma comment(lib, "DbgHelp.lib")
LONG WINAPI windowsCrashHandler(EXCEPTION_POINTERS* ex) {
    SYSTEMTIME time;
    GetLocalTime(&time);
    char logName[256];
    // 文件名格式crash_yyyymmdd_hhmmss.log
    sprintf(logName, "crash_%04d%02d%02d_%02d%02d%02d.log",
            time.wYear, time.wMonth, time.wDay,
            time.wHour, time.wMinute, time.wSecond);

    // 打开日志文件
    std::ofstream logFile(logName);
    if (!logFile.is_open()) return EXCEPTION_EXECUTE_HANDLER;

    // 记录异常信息
    logFile << "=== Exception: "
            << ex->ExceptionRecord->ExceptionCode
            <<" ==="
            << std::endl;

    // 记录内存占用(Windows)
    MEMORYSTATUSEX statex;
    statex.dwLength = sizeof(statex);
    if (GlobalMemoryStatusEx(&statex)) {
        logFile << "总内存:" << statex.ullTotalPhys / (1024 * 1024) << " MB" << std::endl;
    }

    PROCESS_MEMORY_COUNTERS pmc;
    GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
    logFile << "内存占用: "
            << pmc.WorkingSetSize / (1024 * 1024)
            << " MB" << std::endl;

    logFile << "Error Code: 0x" << std::hex << ex->ExceptionRecord->ExceptionCode << std::endl;

    // 获取调用堆栈
    HANDLE process = GetCurrentProcess();
    HANDLE thread = GetCurrentThread();
    SymInitialize(process, NULL, TRUE);  // 初始化符号表

    // 遍历堆栈帧
    STACKFRAME64 stackFrame = {{0}};
    stackFrame.AddrPC.Offset = ex->ContextRecord->Rip;  // x86 用 Eip, x64 用 Rip
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = ex->ContextRecord->Rsp;  // x86 用 Esp, x64 用 Rsp
    stackFrame.AddrStack.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = ex->ContextRecord->Rbp;  // x86 用 Ebp, x64 用 Rbp
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    DWORD imageType;
#ifdef _M_IX86
    imageType = IMAGE_FILE_MACHINE_I386;
#elif _M_X64
    imageType = IMAGE_FILE_MACHINE_AMD64;
#endif

    logFile << "调用堆栈:" << std::endl;
    int frameNum = 0;
    while (StackWalk64(imageType, process, thread, &stackFrame, ex->ContextRecord,
                       NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
        // 获取符号信息
        BYTE symbolBuffer[sizeof(SYMBOL_INFO) + 256] = {0};
        SYMBOL_INFO* symbol = (SYMBOL_INFO*)symbolBuffer;
        symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
        symbol->MaxNameLen = 255;

        DWORD64 displacement = 0;
        if (SymFromAddr(process, stackFrame.AddrPC.Offset, &displacement, symbol)) {
            logFile << "[" << frameNum << "] " << symbol->Name << std::endl;
        } else {
            logFile << "[" << frameNum << "] Unknown Address" << std::endl;
        }
        frameNum++;
    }

    // 清理符号表
    SymCleanup(process);

    logFile.close();
    // 退出程序
    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

int main(int argc, char *argv[])
{

#ifdef Q_OS_WIN
    // Windows 注册异常(闪退)处理函数
    SetUnhandledExceptionFilter(windowsCrashHandler);
#endif
    QApplication a(argc, argv);
    return a.exec();
}

这样在程序出现闪退后,就可以看到闪退时计算机内存的占用情况以及引起闪退的调用堆栈。

相关文章:

  • Nginx面试宝典【刷题系列】
  • 广州无人机考试培训收费标准(附报名流程)
  • 【开源免费】基于SpringBoot+Vue.JS美食烹饪互动平台(JAVA毕业设计)
  • python 剪切音频
  • [特殊字符]️ ‌Selenium元素存在性判断的5种方法‌
  • 归纳总结一下Tensorflow、PaddlePaddle、Pytorch构建神经网络基本流程,以及使用NCNN推理的流程
  • 快速上手 Uniapp:从入门到精通的捷径
  • css 设置svg文字的对齐方式。右对齐
  • 五、Redis哨兵监控
  • Halcon 颜色分割算子、RGB和HSV之间的转换
  • 基于STM32的智能垃圾分类与回收系统
  • Go红队开发—并发编程
  • 数据结构:二叉树的数组结构以及堆的实现详解
  • C++之继承详解
  • pikachu
  • MySQL 时区参数 time_zone 详解
  • 边缘计算收益低的三大指标
  • 使用Modbus协议西门子 S7-200 SMART PLC 通信
  • 组件传递props校验
  • leetcode59------螺旋矩阵II
  • 祝贺!苏翊鸣成功解锁“2160”
  • 越怕出错越会出错,“墨菲定律”的魔咒该怎么破?
  • 罗氏制药全新生物制药生产基地投资项目在沪启动:预计投资20.4亿元,2031年投产
  • 习近平《在庆祝中华全国总工会成立100周年暨全国劳动模范和先进工作者表彰大会上的讲话》单行本出版
  • 中国证监会印发《推动公募基金高质量发展行动方案》
  • 中国人民银行:5月8日起降息,15日起降准