Electron-开发实践:crash上报及解析
【前言】
electron开发实践中,crash的上报不可避免,
electron中可以通过crashReporter来上报crash,
https://www.electronjs.org/docs/latest/api/crash-reporter ,
而处理crash使用的是crashpad,有兴趣的可以继续研究下,
https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md
【crashReporter】
通过start方法启动上报,
start需要尽早的调用,
例如在app.on(‘ready’)前
// crash reporter
const { crashReporter } = require('electron');
/**
* start方法
*/
crashReporter.start({
// 要上报的服务器地址
submitURL: 'https://your-domain.com/url-to-submit',
// 产品名称
productName: 'x',
// 是否压缩,默认true,如果开启会上传gzip,服务器要处理一下
compress: false,
// 是否限制频次,默认为false,如果开启每小时上传1次
rateLimit: false,
// 是否上传到服务器,默认为true,如果关闭只在本地生成crash文件
uploadToServer: true,
// 是否禁止系统crash处理,默认为false
ignoreSystemCrashHandler: false,
// 携带的参数,extra中的参数只有主进程崩溃会携带
extra: {
userId: 'xxx',
},
// 携带的参数,globalExtra中的参数所有进程崩溃都会携带
globalExtra: {
userId: 'xxx',
},
});
通过addExtraParameter来添加携带的参数
crashReporter.addExtraParameter(key, value);
通过crash方法来产生crash,进行测试
process.crash();
如果需要子进程单独上报,可以使用如下方法
process.crashReporter.start(options);
【服务端处理上报】
这里服务端使用qiao-z这个框架来演示,
文档: https://qiao-z.vincentqiao.com/#/
服务端:安装依赖
npm i qiao-z qiao-z-upload
服务端:app.js
// qz
const qz = require('qiao-z');
// app
const app = qz({
upload: require('qiao-z-upload'),
});
// listen
app.listen(9001);
服务端:CrashController.js,qiao-z会自动扫描Controller.js结尾的文件,并注册路由
// fs
const { renameSync } = require('fs');
// path
const { resolve } = require('path');
/**
* crash controller
*/
module.exports = (app) => {
// crash
app.post('/crash', async (req, res) => {
try {
// fields
const fields = req.body.fields;
console.log('fields: ', fields);
// file info
const fileInfo = req.body.files.upload_file_minidump;
const tmpPath = fileInfo.filepath;
const destPath = resolve(__dirname, fileInfo.originalFilename);
renameSync(tmpPath, destPath);
// return
res.send('crash success');
} catch (e) {
console.log(e);
res.send('crash failed');
}
});
};
服务端:启动服务
node app.js
electron:设置crashReporter的submitURL
submitURL: 'http://localhost:9001/crash',
electron:crashReporter启动后设置4s后的crash
// report
crashReporter.start(options);
// crash
setTimeout(() => {
process.crash();
}, 4000);
服务端:查看效果
1.dmp文件

2.获取到的上报信息
这里可以看到,处理一些基础信息,已经上报了globalExtra中的userId信息

【解析dmp文件】
如上,已经获取到electron应用crash的dmp文件了,
那么,如何解析dmp文件呢,稍微比较复杂
安装depot_tools
breakpad依赖于depot_tools
|— 首先clone项目
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
|— 然后设置path
export PATH=/path/to/depot_tools:$PATH
安装breakpad
|— 创建文件夹
mkdir breakpad && cd breakpad
|— 下载breakpad
fetch breakpad
cd src
|— 构建breakpad
./configure && make
|— 安装命令
make install
下载electron symbols文件
|— 下载地址: https://github.com/electron/electron/releases
|— 找到对应操作系统和electron版本的symbols.zip文件并下载,例如我本地是22.0.0版本

使用breakpad解析dmp文件
|— 使用breakpad的minidump_stackwalk命令解析dmp文件
minidump_stackwalk -s PATH_TO_DUMP PATH_TO_electron.breakpad.sym
上面两个路径,
第一个是dmp路径,例如:
dmp/e66fdb11-043e-4f4f-ac24-8a473d54e0b3.dmp
第二个是sym路径,例如:
electron-v22.0.0-darwin-arm64-symbols/breakpad_symbols/chrome_crashpad_handler/chrome_crashpad_handler.sym
执行命令后解析效果如下

【electron-minidump】
上面解析完后的文件基本没有可读性,
是因为只使用的chrome对应的符号文件进行解析,
如果把一个dmp文件比喻为一个构建后的js文件,
如果想解析js文件所有的源码,
需要知道这个js引用的所有npm包的源码。
依次类推,解析一个dmp文件需要用到很多符号表,
比如electron的,electron渲染进程的,chrome的等等,
这里推荐一个工具进行解析: https://www.npmjs.com/package/electron-minidump
简单总结这个工具的解析方法
1.下载dmp文件对应的所有需要的sym文件
2.使用这些sym文件解析dmp文件
使用方式如下:
npx electron-minidump -f /path/to/your/dmp/file
效果如下
下载sym文件:

可以看到解析一个dmp文件,
需要下载对应的607个sym文件,
解析后内容如下:

可以看到这次解析后已经可以看到具体的异常堆栈了
【第三方方案】
上述本地解析dmp文件比较麻烦,
是否有比较方便的方案,
确实有,但是大部分收费,
例如: https://sentry.io/welcome/
【总结】
1. electron crashReporter如何使用
2. 服务端如何接收crash上报
3. 本地如何解析接收到的dmp文件
4. 其他解析方案