1 Electron 应用集成 Sentry
首先应从 Sentry
平台新建项目,并获得 dsn
地址。一般为了数据安全可控等原因,都会使用内部搭建的 Sentry 平台。下面示例为从 Sentry 官网注册账号并新建测试项目,获得 dsn 格式参考如下:
https://a3g538c5c6g7585ba69f99ea96c8888d@o8888888.ingest.sentry.io/9999999
然后需要在项目中添加 @sentry/electron
依赖:
pnpm add @sentry/electron
最后,在主进程和所有渲染进程中均引入并初始化 Sentry。如果应用最终的发布为非 bundles 打包模式,可以直接从 @sentry/electron
导出,其在入口处对当前运行环境做了识别判断。示例:
import * as Sentry from '@sentry/electron'; Sentry.init({ dsn: 'https://a3g538c5c6g7585ba69f99ea96c8888d@o8888888.ingest.sentry.io/9999999' })
一般生产环境都会使用构建工具打包为 bundles 模式。所以推荐按进程类型分别引入。示例:
// 主进程 import * as Sentry from '@sentry/electron/dist/main'; //渲染进程 import * as Sentry from '@sentry/electron/dist/renderer'; Sentry.init({ dsn: 'https://a3g538c5c6g7585ba69f99ea96c8888d@o8888888.ingest.sentry.io/9999999' });
以上为接入 Sentry 的基本流程。实际开发过程中,可能会有对捕捉到的未知异常进行主动上报以便分析,Sentry 提供了 Capture Message 等方法供自定义上报。以下为一个简单的封装示例:
import type * as Sentry from '@sentry/electron'; import type { CaptureContext } from '@sentry/types'; const isDev = process.env.NODE_ENV = 'production'; export const SentryHelper = { sentry: null as Sentry, init(dsn: string, sentry: unknown) { this.sentry = sentry; this.sentry.init({ dsn, debug: !isDev, environment: isDev ? 'dev' : 'prod', release: '0.0.1' }); }, setUser(id: string) { this.sentry.setUser({ id }); }, captureException(exception: unknown, captureContext?: CaptureContext) { this.entry.captureException(exception, captureContext); } captureMessage(message: string, captureContext?: CaptureContext | Sentry.Severity) { this.sentry.captureMessage(message, captureContext); } };
2 上传 Electron 符号表文件到 Sentry 平台
当 Electron 应用崩溃时,会生成 dump 文件,dump 文件记录了崩溃时的调用堆栈信息。
接入 @sentry/electron
后,发生崩溃时会将 dump 文件上传至 Sentry 平台。但是 dump 文件记录的堆栈信息反映的是编译优化后的信息,不能直接定位和分析。
Electron 的符号表文件类似于前端 js 编译输出的 sourcemap 文件,记录了编译前后的源码映射关系(主要是基于 C++ 编译时生成的 pdb 文件,或由 pdb 文件转换而来)。上传符号表文件至 Sentry 平台,则 Sentry 会根据版本匹配的符号表文件解析崩溃上传的 dump 文件,展示具体源码对应的堆栈信息。
Electron 在提供 exe 程序的同时,也提供了对应版本的符号表文件。基于 @sentry/cli
、@sentry/wizard
等工具,可以方便的根据当前项目中使用的 Electron 版本从 github 上下载正确的符号表文件并上传到指定的 Sentry 平台上。
以下为相关方法与步骤参考。
- 首先,在 Sentry 平台中获取
Auth Tokens
。 -
然后,在项目根目录新建
.sentryclirc
文件。内容参考如下:
[defaults] url = https://sentry.io/ org = your org project = your project [auth] token = your token
- 接着,添加相关依赖,参考如下:
pnpm add @sentry/wizard @sentry/cli electron-download
- 使用
sentry-wizard
生成符合当前项目的sentry-symbols.js
文件。执行如下命令:
sentry-wizard --integration electron
- 执行
sentry-symbols.js
文件,即可从 GitHub 上下载符合当前项目 Electron 版本的符号表文件,并上传至 Sentry 平台。示例:
node sentry-symbols.js
由于符号表文件较大,在国内的网络环境下,此过程可能会较久或执行失败。
我们也可以打开 sentry-symbols.js 文件查看具体的下载地址,到 github release 页面自行下载对应的符号表文件(以 symbols.zip 后缀结尾):https://github.com/electron/electron/releases
3 Electron 应用接入自建的低版本 Sentry 平台
由于内部生产环境的 Sentry 平台版本较低(9.x),在更新 Electron 以及 @sentry/electron
至较高版本后出现了 403 异常。参考如下:
Sentry Logger [Warn]: Dropping request: HTTPError: HTTP Error (403)
根据官方 issues 得知为版本兼容性问题。@sentry/electron
的 v3 版本要求 Sentry Server >= v20.6.0。
于是降级 @sentry/electron
至 v2
版本。但是又出现了 Electron 的 crashReporter API 兼容性问题。这是由于从 Electron 13 版本开始,废弃了 。
可行的解决办法则为在本地维护 @sentry/electron
V2 版本,并修正其中对 crashReporter API 在高版本中的调用方法。具体为:
- 将
node_modules/@sentry/electron
目录内容复制至本地仓库目录中,如lib-patchs/@sentry/electron
。 - 将
lib-patchs
目录的模块查找级别设置为最高。以webpack
为例,可作如下配置:
{ resolve: { modules: ['lib-patchs', 'node_modules'] } }
此外,由于我们的应用使用 React 开发,实际上在渲染进程中是通过 @sentry/react
接入的,其对应适配 Sentry@9.x
平台的版本为 5.x
。即 @sentry/react@^5.30.0
。
上面介绍的是利用 webpack alias 特性实现修改外部依赖的方式。其优点是简单,缺点则是需要将整个依赖包都提交至 git 仓库。
也可以使用 patch-package库实现,具体用法可参见其 Readme.md 文档。
4 相关参考
上面介绍了常规的 Electron 应用集成 Sentry 的基本方法与步骤,并记录了高版本 Electron 接入 Sentry@9.x 平台的一种兼容处理办法。
如果因为一些特别的需求,有针对 Electron 源码进行了改动并自编译,其接入 Sentry
的方法可参考如下文章: Electron 自编译应用崩溃(crash)调试分析方法
- https://docs.sentry.io/platforms/javascript/guides/electron/
- https://github.com/getsentry/sentry-electron/issues/483
- https://lzw.me/a/electron-crash-sentry.html