Skip to main content

崩溃

简介

崩溃的捕获和收集基于Electron官方提供的crashReporter,进行解析后将崩溃线程的堆栈信息上传至后台。

danger

Electron 官方提供的 crashReporter 在 Windows 平台上无法捕获由 abort 导致的崩溃。

注意事项

为确保SDK能够正常收集崩溃信息,请检查您的应用代码中是否已调用了crashReporter.start方法。如果您的应用已经启用该方法,可能会与SDK产生冲突,导致崩溃信息收集失效。

崩溃初始化

Bugly Electron使用tencent/minidump编译的可执行文件来获得崩溃堆栈,业务在使用的过程中需要声明这些可执行文件的具体路径才能正常使用崩溃功能。

tencent/minidump 编译的可执行文件路径为 node_modules/@tencent/minidump/bin/, 该路径下存放不同操作系统需要使用的可执行文件。

bin路径下的文件展示

业务在接入SDK时,可以在主进程的控制台查看SDK的日志,确认SDK能否找到可执行文件的路径。

// 寻找可执行文件路径失败,filePath为查找可执行文件的路径。可以在SDK初始化时使用minidumpBindir来修改查找可执行文件的路径
[Bugly] [DEBUG] find minidump_stackwalk failed. filePath: /Users/lolouyang/electronTest/built/darwin-arm64/minidump_stackwalk
[Bugly] [DEBUG] find minidump_dump failed. filePath: /Users/lolouyang/electronTest/built/darwin-arm64/minidump_dump

业务在打包应用的过程中可能无法查看SDK的日志,可以在SDK初始化时设置uploadCrashLog为true,这样可以在产品的【日志】栏目的用户日志/一般日志里查看SDK的崩溃功能的日志。 产品查看崩溃日志

  // 在初始化aegis时声明minidumpBinDir与uploadCrashLog
const aegis = new Aegis({
// minidumpBinDir,uploadCrashLog 使用崩溃监控功能时可以在初始化时设置这两个字段,
minidumpBindir: __dirname + "/minidump/bin", //默认为空,该路径为绝对路径
uploadCrashLog: false, //默认为false,为true时使用自定义上报崩溃过程的具体日志
env: "debug", //uploadCrashLog为true,env为debug时才会使用自定义上报上传崩溃日志
})

上报字段

{
"aegisv2_goto":"6a262b8bc85d31f4", // string,定位或追踪ID
"timestamp":1751977565, // number,事件发生时间(毫秒级时间戳)
"crashThread":"崩溃线程堆栈信息", // string,崩溃线程堆栈
"usedModules":"翻译崩溃线程所需模块地址信息", // string,相关模块信息
"js_stack":"崩溃JS堆栈信息" // string,JS层堆栈
"crashProcess": "renderer" // string, 用于标识是渲染进程崩溃还是主进程崩溃
}
  1. 上报字段包括崩溃线程堆栈信息和js堆栈信息,其中崩溃线程堆栈信息是由crashReporter捕获到minidump文件,利用minidump包解析而来。
  2. 崩溃时,由于整个进程已经崩溃,js堆栈信息无法通过常规方式获取。用户需要使用SDK通过 wrapWithStackProxy 对关键 API 进行代理,在每次调用时记录当前 JS 调用栈,并在崩溃前通过 crashReporter.addExtraParameter 将最近一次调用的堆栈信息写入崩溃报告,从而实现在崩溃时也能获取到 JS 层堆栈。
tip

Electron 官方 minidump 包暂不支持 Windows 平台,我们对其进行了重写并发布为 @tencent/minidump,主进程 SDK 依赖该包以在 Windows 上解析 minidump 文件。

崩溃前JS调用栈捕获

由于崩溃时整个进程已终止,无法通过常规方式获取JS堆栈。Aegis 通过 wrapWithStackProxy 代理关键 API,在每次调用时记录当前 JS 调用栈,并在崩溃前通过 crashReporter.addExtraParameter 保存最近调用信息。

wrapWithStackProxy 使用说明

import Aegis from '@tencent/bugly-electron-sdk';

// 1. 创建代理对象
const proxyNativeApi = Aegis.wrapWithStackProxy(nativeApi, info => {
console.log('调用:', info.method, '\n堆栈:\n', info.stack);
});

// 2. 参数说明
// 第一个参数:需要代理的原生对象或模块
// 第二个参数:回调函数,每次方法调用时触发,接收 info 对象包含:
// - method: 被调用的方法名
// - args: 调用参数数组
// - stack: 当前调用栈字符串

// 3. 使用示例
proxyNativeApi.crash(); // 调用被代理API的方法

danger
  1. 如果原生接口过多或者调用次数过于频繁的话,不建议使用该代理获取JS堆栈。
  2. 要保证JS堆栈获取的准确性的话, 需要代理所有原生API。

崩溃上报时机

渲染进程崩溃和子进程崩溃:崩溃发生时即触发崩溃上报

setCrashMonitor(aegis: Aegis) {
app.on('render-process-gone', async () => {
await this.uploadCrash(crashDir, aegis, 'renderer');
});

app.on('child-process-gone', async () => {
await this.uploadCrash(crashDir, aegis, 'browser');
});
},

这个uploadCrash函数会将crashDir中所有的崩溃文件进行上报

tip

主进程崩溃:由于主进程崩溃时,整个程序就已经崩溃,因此,主进程崩溃上报的时机是下一次程序启动时

tip

如果崩溃上报或解析失败,会立即抛出错误,并且minidump文件不会被立即删除,而是会在下一次启动或下一次崩溃上报时进行上报。