简介

Sentry 是什么?中文翻译过来是「哨兵」的意思,没错,它是程序的哨兵,它可以监控我们在生产环境中项目的运行状态,一旦某段代码运行报错、或者发生异常,会第一时间将报错的信息:页面路由、异常文件、请求方式等一些非常详细的信息以消息或者邮件的方式通知我们,告诉我们:程序出错了。而我们可以从详细的报错信息中快速分析问题所在,从而快速地修复 Bug。

为什么是 Sentry?

是的,在市场上有许多供应商提供类似的一体化解决方案,国外有 BugSnagRollBar,国内有 oneapmfundebug,那为什么我们偏偏选择 Sentry 呢?

因为 Sentry 是 100% 开源的,我们可以使用它的 SaaS 版的,除此之外我们也可以私有化部署

另外 Sentry 支持主流的编程语言,可以通过 这里 查看所有支持的语言。

通过下面这张图可以看出,Sentry 在前端的近两年发展趋势,以及与其它竞争者对比:

可以看到 Sentry 的 npm 下载量基本是稳步上升,同时引入 Sentry 包体积还很小,打包后只有 20k:

如何私有化部署?

Sentry 官方提供了基于云的 SaaS 服务,那么为什么还要私有化部署呢?这是因为如果对于数据隐私和安全有着更高的要求,或者需要更多的自定义和控制权,那么私有化部署 Sentry 是个更好的选择。

Sentry 可以使用 Docker、Docker-compose、K8s 的方式部署在自己的服务器上。

关于私有化部署的方法这里给出参考文档,如有需要可以看看:

需要注意的是最新版本的 sentry 的功能很强大,但是同时带来的是对服务器的性能要求很高,因此如果只需要 sentry 最基本的功能,推荐部署 sentry 9.1.2 的版本,

下面是两个版本需要的资源和功能对比:

23.9.1

  • Docker 19.03.6+

  • Compose 2.0.1+

  • 4 CPU Cores

  • 8 GB RAM

  • 20 GB Free Disk Space

    9.1.2

  • Docker 17.05.0+

  • Compose 1.17.0+

  • 3 GB RAM

总结一下,如果你需要更完备的错误追踪和分析功能并且恰好财力雄厚,建议使用官方的 SaaS 服务或者私有化部署最新版本,否则还是建议部署 9.1.2 版本,该有的功能都有,够你使用了。

如何接入前端 SDK?

既然私有化部署了 sentry 的 9.1.2 版本,接下来就是在前端接入上报 SDK,然而官方文档上默认针对的都是最新版本,像 9.1.2 这样的上古版本接入文档早就淹没在浩瀚的历史变更记录中,互联网上更多的也是新版本的资料。经过不断的踩坑,终于是完成了 9.1.2 版本的 sdk 接入,由于精力有限,只完成了 Electron 和 Vue 平台的接入,其他平台的就不在此记录了。

Electron

  1. 安装 sdk
1
pnpm add @sentry/electron
  1. 在主进程入口文件初始化 sentry(尽可能的提前初始化)
1
2
3
4
5
6
7
8
import * as Sentry from "@sentry/electron";
import packageJson from "../../../package.json";

Sentry.init({
dsn: SENTRY_DSN,
sampleRate: 1,
release: packageJson.version,
});

Vue

除了需要特定版本的 sdk,其他的可以参考官方文档

  1. 安装 sdk
1
2
## 最新版本的 sdk 不兼容 9.1.2 版本的 sentry,使用旧版本
pnpm add @sentry/vue@5.30.0 -D
  1. 初始化 sdk
1
2
3
4
5
6
7
8
import * as Sentry from "@sentry/vue";
import Vue from "vue";

Sentry.init({
Vue,
dsn: SENTRY_DSN,
release: packageJson.version,
});

上传 Source Map

接入 sdk 后,我们手动触发个错误,就可以看到在 sentry 上多出来一个新的 Issue,点开可以看到更详细的报错信息:

但是这个报错信息对我们的意义却不是很大,因为根据这份报错信息我们没法锁定出问题的源码位置。可能会有小机灵鬼说,我明明看到了错误堆栈,里面有错误的文件名,行数和列数,为什么还是没办法锁定?

这是因此现代前端部署的代码都是合并和压缩过的,就不是给人类读的,相信我没有超能力别指望能反推出源码。

这时就需要借助 source map 了,什么?不知道什么是 source map?建议先看外这篇文章《深入浅出之 Source Map》再往下看。而且幸好的是 sentry 集成了 source map 的解析能力(在 9.1.2 这个版本也是有的,只是藏的有点深)

上面看完了相信你也明白了 source map 的重要性,接下我们开始上传 source map 到 sentry:

  1. 安装 webpack sdk

sentry 针对不同的编译器有不同的上传 sdk,其他平台见官方文档,或者使用 cli 上传,但是为了省事和简化流程,我们采用 sdk 的上传方式

1
pnpm add @sentry/webpack-plugin@2.7.1 -D
  1. 配置 webpack 插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
const packageJson = require("./package.json");

module.exports = {
productionSourceMap: true, // 生产环境生成 source map
configureWebpack: {
plugins: [
sentryWebpackPlugin({
org: "xxxx",
project: "xxxx",
url: "xxxx",
authToken: "xxxx",
release: {
name: packageJson.version,
uploadLegacySourcemaps: {
paths: ["./dist_electron/bundled"],
},
},
}),
],
},
};

更多配置参数见官方文档:@sentry/webpack-plugin,这里着重介绍下需要注意的点:

  • webpack 需要生成 source map,没有的话,sdk 就是无米而炊
  • release.name 需要和上报 sdk 里的 release 字段保持一致,以便于将异常按照 release 进行分类
  • uploadLegacySourcemaps 配置需要上传的文件目录

以上配置完成后,运行打包命令,就可以在 sentry 中看到上传的 source map 了

有了 source map,sentry 就能根据 source map 解析出源码位置

自定用户信息

在 sentry 的默认上报中,只会上报用户 ip 地址作为用户的身份标识,这对我们针对特定用户排查日志时,不能说毫无帮助,只能说聊胜于无,因此我们需要上报一些特定的字段用作用户的身份标识,比如 username,email,id 等等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import * as Sentry from "@sentry/vue";

Sentry.init({
// 初始化参数
...
});

// 自定义用户信息,setUser 的入参类型如下:
// export interface User {
// [key: string]: any;
// id?: string;
// ip_address?: string;
// email?: string;
// username?: string;
// }
Sentry.setUser({ id: xxx, username: xxx, email: xxx });

before:

after:

总结

sentry 是前端异常监控的不二选择,由于其是开源项目,我们可以选择私有化部署,而 9.1.2 版本就是考虑功能性和部署成本的最优解。

参考