Electron 应用接入 Sentry 与低版本兼容的实践方案

目录
[隐藏]

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 平台上。

以下为相关方法与步骤参考。

  1. 首先,在 Sentry 平台中获取 Auth Tokens
  2. 然后,在项目根目录新建 .sentryclirc 文件。内容参考如下:

[defaults]
url = https://sentry.io/
org = your org
project = your project

[auth]
token = your token
  1. 接着,添加相关依赖,参考如下:
pnpm add @sentry/wizard @sentry/cli electron-download
  1. 使用 sentry-wizard 生成符合当前项目的 sentry-symbols.js 文件。执行如下命令:
sentry-wizard --integration electron
  1. 执行 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/electronv2 版本。但是又出现了 Electron 的 crashReporter API 兼容性问题。这是由于从 Electron 13 版本开始,废弃了 。

可行的解决办法则为在本地维护 @sentry/electron V2 版本,并修正其中对 crashReporter API 在高版本中的调用方法。具体为:

  1. node_modules/@sentry/electron 目录内容复制至本地仓库目录中,如 lib-patchs/@sentry/electron
  2. 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
点赞 (0)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Captcha Code