由于 C++ 没有标准的崩溃报告系统,而且未处理的异常都会导致程序崩溃。最后操作系统会弹出丑丑的“已停止工作”对话框,也不能存下什么有用的信息。为了解决这个问题,我们一般都会自写代码处理崩溃信息,或像我一样采取第三方库或平台。

通常在程序崩溃时,我们要保存崩溃时程序的运行信息,如导出包含运行栈的 Mini Dump、保存最后一瞬间的截图等,最后如果可以的话将收集的信息传输到自己的服务器上。如果自写代码实现这些功能,工作量会比较大;对于第三方,根据我搜索的资料,实现了类似功能的第三方平台有 BugSplat (付费服务),第三方库有 CrashRptBugTrap

这几个第三方平台各有优缺点,对我而言因为我暂时用在小项目上,因此在对比了之后暂时使用的是 BugTrap,名意为臭虫陷阱。在这里简单记录下使用方法和使用心得。

为什么是 BugTrap?

Windows 内置有一个用于未处理错误的处理程序,但这个对话框到底讲了啥?如果我们不希望把数据发送到 MicroSoft,我们基本上获取不到有用的信息。

Microsoft 默认崩溃提示框

而 BugTrap 有以下优点:

  • 简单易用,可快速添加到现有项目而不用更改太多代码。
  • 支持 C++ x86 / x64 及 .Net。
  • 友好的提示界面,元素均可自定义。
  • 崩溃时自动收集崩溃数据, 包含 Mini Dump、软件版本、屏幕截图等。
  • 在用户同意后可通过网络或邮件传输,并可附加自己的日志文件。

使用 BugTrap 后我们可以很简单的把崩溃提示换成如下图所示的样式(敏感信息已隐藏),是不是很棒!

简单模式的错误报告
包含详细信息的错误报告

在代码中增加支持

原生 C++

BugTrap 以动态链接库的形式供使用,使用这种形式是因为崩溃后需要独立句柄才能做到发送数据。链接库同时提供了 Unicode 和 ANSI 两种形式,不过现在的应用程序默认都是编译 Unicode 了吧。

以 MFC 应用举例, 下面是从 BugTrap 官方例程中提取并修改的代码:

记得把 .lib 文件放在项目目录下,原生 C++ 也是差不多的思路。

MFC 框架

如果使用的是 MFC,框架产生的错误都会被 CException 拦截,但我们也可以使用 BugTrap 代替它。而方法也很简单,几乎不用对代码进行更改,只需要从BTWindow 类派生窗口类即可。

BTWindow 类是一个模板, 以基本窗口类的名称为参数。我们只需要对窗口类使用 BTWindow 模板即可,如:

其他使用上的问题,请参阅使用手册。

测试使用

在做完上面的设置之后,已经可以正常使用 BugTrap 了。 我们可以 在设置异常处理程序后,使用断点语句 _asm int 3 来测试 BugTrap 是否正常工作。注意不要直接在 Visual Studio 中运行调试,因为 VS 的调试器会在 BugTrap 前捕捉所有错误,导致 BugTrap 根本不起作用(被坑了一小时时间的人语重心长地说道)。

在错误报告中显示符号信息需要 PDB 或 MAP 文件,在需要分发的情况下推荐生成一份 MAP 文件备用。原因是由于 MAP 文件只包含了符号的链接信息,会比 PDB 文件小很多。

增加 MAP 文件生成

自定义捕捉

在 BugTrap 可以正常使用之后,我们想要对捕捉流程做些自定义也很简单。

崩溃预处理函数

如果我们想在程序崩溃前对程序做些处理,比如说增加几条日志提示发生了严重错误,则我们可以使用 BT_SetPreErrHandler 函数设置预处理器。

其中第二个参数可以传递一个指针,以便在处理函数中使用。

自定义错误报告对话框

错误报告对话框在 BugTrap 中是高度可定制的。举例来说,默认对话框的第一句话是 “A Crash has been detected by BugTrap”。如果我们不想显示 BugTrap 的信息,可以使用以下代码来覆盖:

我在上面截图中的程序中便使用了这行代码,其中的 BTDM_INTRO1 表示设定的是介绍文本第一行,其他值需要参考头文件里的描述。

增加自定义日志文件

有时候,除了某些 BUG,部分逻辑问题也会导致程序崩溃。在这种情况下,标准错误报告可能无济于事。而自定义日志记录可能是最有效的错误预防机制。BugTrap 可以在详细模式下(设定了标志 BTF_DETAILEDMODE),将任意数量的其他文件附加到报告中。

如果要从 Windows 注册表中导出某些项并将其附加到报告中,则可以利用内置的 BugTrap 函数:

BugTrap 还另外提供了一套内置的日志系统,由于我使用的是 boost::log,没有深入对其进行了解。需要的可以自行阅读使用手册相关的内容。

查看报告

不论是服务器上传或是邮件传输,在收到错误报告后我们都可以通过 BugTrap 附带的 CrashExplorer 小程序来阅览报告。若是收到的报告中只有堆栈地址而没有符号信息,前面我们生成的 MAP 文件就派上了用场。只需要在“Map/Pdb Folder”中设定我们相应的文件就可以显示详细的数据啦,精确到哪一行代码,是不是很方便。

小结

BugTrap 正如其名,是一个方便易用的错误报告处理器。以前有挺多游戏及程序采用了这个模块来收集错误报告,如 CF、LoL 等。这次也只是做了简单的应用,使用时也请多翻阅使用手册。

基于我个人的使用需求,部分高级功能如服务器上传等都没有研究,请大家多多包含。能帮到你们更是再好不过了,若有更好的错误报告处理模块,欢迎大家告诉我,谢谢!

参考资料

Hintay

Hintay

帝王鸽

发表评论

表情 图像 粗体 删除线 居中 斜体 下划线 块引用 代码