异步日志崩溃防丢日志方案及测试框架兼容问题咨询
崩溃时异步日志自动刷盘的解决方案及测试框架兼容处理
一、系统级崩溃拦截方案
Windows平台(Visual Studio)
- 未处理异常拦截:使用
SetUnhandledExceptionFilter注册全局过滤器,在过滤器函数中优先调用日志库的刷盘接口(如LOG_FLUSH_ALL()),完成后再调用原过滤器(注册前先保存原过滤器指针)。 - C库参数错误处理:通过
_set_invalid_parameter_handler自定义处理器,同样先执行日志刷盘,再移交默认处理逻辑。
msys2(clang/gcc)平台
- 信号捕获:用
sigaction注册SIGSEGV、SIGABRT、SIGILL等崩溃信号的处理函数,在函数中触发日志刷盘。注意:刷盘逻辑必须是异步信号安全的(比如使用无锁队列、避免调用malloc等非安全函数)。 - abort钩子:通过
__cxa_atexit注册退出回调,或在链接时替换abort函数,确保程序调用abort()崩溃前刷出日志。
二、与测试框架(gtest/boost.test)的兼容技巧
- 链式调用原有处理器:注册自定义拦截器前,先保存测试框架已注册的原处理器(比如
SetUnhandledExceptionFilter的返回值、sigaction的原有配置),在自定义逻辑执行完后,调用原处理器,保证测试框架的崩溃处理流程不受影响。 - 环境分支配置:通过预编译宏判断是否处于测试环境,比如检测
GTEST_VERSION或BOOST_TEST_MODULE,如果是测试环境则禁用自定义崩溃拦截,直接使用测试框架的日志处理机制。 - 测试框架参数调整:以gtest为例,可通过
--gtest_catch_exceptions=0关闭框架自身的异常捕获,让全局过滤器生效;也可在测试用例的SetUp/TearDown中临时切换拦截器。
三、主流异步日志库的实现方式
spdlog
- 提供
flush_on()配置,可指定特定日志级别自动刷盘,但崩溃场景下仍需配合崩溃拦截器调用flush_all()接口。 - 异步模式基于无锁队列实现,刷盘逻辑线程安全,可安全在信号/异常处理函数中调用。
- 兼容测试框架:官方推荐通过预编译宏控制崩溃拦截逻辑的启用,避免与测试框架的处理器冲突。
glog
- 初始化时自动注册崩溃信号/异常处理器,崩溃前自动刷出所有待处理日志。
- 内置兼容逻辑:检测到测试框架的处理器时,会链式调用而非覆盖,保证测试框架的崩溃报告流程正常执行。
自定义日志库注意事项
- 异步队列需保证线程安全/无锁,避免崩溃时主线程与刷盘线程的竞争导致死锁。
- 刷盘逻辑尽量轻量,避免在崩溃处理中执行复杂IO或内存操作,防止二次崩溃。
- 减少对全局状态的依赖,防止崩溃时全局变量损坏导致刷盘失败。
内容的提问来源于stack exchange,提问作者Pavel P
相关产品推荐
相关产品推荐

