工作多年,发现大家总是会遇到这种特殊的场景:用户反映某个功能异常。为了找出问题所在,我们尝试在本地重现异常,但结果是什么都没有。另一方面,前端代码的运行环境,如PC浏览器、手机浏览器等,复杂且不可控。这意味着代码中可能会出现各种不可预知的错误。
在这种情况下,如果我们想要拥有一套完整的前端异常监控系统,首先,需要关心的问题就是,如何及时捕捉异常,如何准确定位异常和错误的位置,采集到异常后如何及时通知相关人员?
选择解决方案
我们先来看看常见的前端监控方案。
方案一:自我研究。
具体工作主要是:自己重写Window对象中的onerror和onunhandledrejection方法,收集错误信息,通过服务端接口上传,编写服务端文件,使用Sourcemap文件恢复源码排查问题。
此外,还可以搭建一个查看异常信息的平台。因此,自研方法存在明显的缺陷,需要大量的精力。当然,自研也有易于扩展的优势,比如在前端监控中加入性能监控功能,方便后续页面的性能优化。
方案二:借助成熟的第三方工具,例如 Sentry。
这种方法不需要大量的开发,只要访问配置足够。
对于这两种解决方案,如果自己没有那么多精力去研究,可以选择使用第三方工具。
在成熟的第三方工具中,我推荐你使用 Sentry。因为 Sentry 是一个开源的 bug 跟踪工具,可以帮助我们实时监控和修复系统 bug。
此外,Sentry 支持通过 Sourcemap 文件恢复 JS 错误调用堆栈,也可以在收集到异常后通过 Telegram 或邮件实时通知。
另一个重要的点是,Sentry 允许我们在自己的服务器上构建私有服务,这意味着我们可以免费使用 Sentry 的强大功能,避免源代码泄露的风险。
下面这张图可以直观地展示哨兵采集异常信息的效果。
如何及时捕获异常?
部署哨兵
第一步,无疑是部署 Sentry。 由于官方推荐使用 Docker 进行部署,且操作相对简单,所以我将以 Docker 为例,向大家展示如何从零开始搭建 Sentry 服务。
首先,我们安装 Docker 和 Docker-Compose。 安装完成后,启动Docker,拉取sentry-onpremise仓库代码,这是Sentry官方提供的安装程序,然后启动里面的安装脚本。
在此期间,它将指导您创建管理会员帐户并最终启动哨兵服务。 相关命令可以参考这段代码:
git clone https://github.com/getsentry/onpremise
cd onpremise
./install.sh
$ docker-compose up -d
如果启动过程没问题,在浏览器中输入http://ip:9000进入Sentry登录页面,然后使用刚刚创建的管理员用户名和密码登录系统。
前端项目访问
经过刚才的一些操作,我们的Sentry服务器就完成了,接下来,我们可以在应用中集成Sentry客户端SDK,在前端代码中实时报错。
Sentry 非常强大,支持各种前端框架,如 Vue、Angular、React 等。我们都知道 Vue 是一个流行的前端轻量级框架,具有轻量级、高性能和组件化的优势。那么我将以Vue项目为例进行详细介绍。
创建项目
首先,我们点击Sentry页面左侧导航栏中的第一项Projects,然后,点击页面右上角的Create Project按钮。
然后,在Browser下选择Vue,再次点击CreateProject就可以创建项目了。
接下来,您将看到 Sentry 给出的 Vue 项目的配置指南,它将逐步指导您完成项目配置。
然后,我们继续指南。
首先,通过npm在项目中安装Sentry依赖的两个npm包,分别是@sentry/browser和@sentry/integrations,然后,在main.js中导入。
然后,使用Sentry.init初始化和配置Sentry。配置的时候,教程里已经提供了初始化代码,我们直接复制粘贴到main.js中即可。
最后,我们点击指南底部的确认按钮,然后,自动跳转到本项目的Issue错误页面。
这里需要特别注意的是DSN地址与项目一一对应,不能随意更改。
import * as Sentry from '@sentry/browser'
import { Vue as VueIntegration } from '@sentry/integrations'
Sentry.init({
dsn: 'https://xxxxxxxxxxxxxxxxx@sentry.in.cn/2',
integrations: [new VueIntegration({
Vue,
attachProps: true
})]
})
核实
现在,在Issue错误页面上,我们看到,只有一个空白表单,并且没有任务异常信息。 让我们创建一个 JS 错误报告,看看 Sentry 的效果。
首先,我们在App.vue的created方法中添加一行代码:this.test(),调用当前组件中不存在的方法,强行产生JS错误。 通过 Chrome DevTools 中的 Network 可以看到,每次页面刷新时,都会发送一个 Sentry 相关的 Post 请求,也就是 Sentry 收集异常信息。 这时候进入Issue报错页面,我们发现Sentry已经显示了捕获到的异常:
我们知道,Sentry 将每个异常报告都视为一个 Event,每个 Event 都有一个 Fingerprint。 指纹默认由 Sentry 的分组算法生成。 相同指纹的事件将自动合并为一个问题。 具体生成逻辑可以查看官方文档:https://docs.sentry.io/product/data-management-settings/event-grouping/
通过问题列表,我们可以获得以下信息:异常类型、异常名称、触发位置、最近触发时间、首次触发时间等。
点击进入问题详情页面,在页面中间区域可以看到最新Event的具体信息,如用户IP地址、浏览器信息、系统信息、异常调用栈信息等。
如何准确定位异常报错的位置?
现在,我们看到 Sentry 已经捕获了异常调用堆栈信息。但是,因为网上的代码都是经过压缩和混淆的,要知道是哪一行代码报错,只能全局搜索关键字,然后根据压缩代码的上下文定位。
那么如何查明错误消息呢?
首先,我们在Sentry后台配置AuthToken,这是配置上传Sourcemap的必要参数。
那么如何创建这个Token呢?
我们点击页面左上角的用户名,在下拉菜单中找到User Settings,点击进入用户设置界面,然后,点击Auth Tokens菜单选项新建一个Token。
接下来,我们在构建编译代码的时候开启Sourcemap配置,然后,在根目录下新建一个.sentryclirc文件。
最后,在项目中下载安装Webpack插件@sentry/webpack-plugin,在打包配置文件中添加上传Sourcemap到Sentry的配置。
具体配置请参考这段代码:
[auth]
token=exxxxxxxxxxxx
[defaults]
project=xiaoan-web
org=sentry
url=https://sentry.xxxxx.com/
view raw
这里的 Release 属性对应的是代码版本。 Sentry在采集异常信息时,会同步采集用户的代码版本信息。 通过这些信息,我们可以知道是哪个版本引起了新的问题。
需要注意的是,UrlPrefix 属性值并不是固定的,而是与项目静态资源访问路径有关。
const SentryWebpackPlugin = require('@sentry/webpack-plugin')
const commitHash = require('child_process').execSync('git rev-parse HEAD').toString();
new SentryWebpackPlugin({
include: path.resolve(__dirname, '../dist/static/js/'),
ignoreFile: '.sentrycliignore',
ignore: ['node_modules', 'webpack.config.js'],
release: commitHash,
urlPrefix: '~/static/js' // https://ip.com/static/js/app.js
})
配置完成后,Sentry可以根据上传的Sourcemap恢复代码位置:
异常采集后如何及时通知相关人员?
当 Sentry 捕捉到异常时,我们希望它能实时通知开发者,针对这种情况,Sentry 提供了邮件通知功能,只需在 Sentry 的配置文件中添加相关配置即可。
由于检查邮件可能不够及时,如果你的团队使用 Telegram 进行协同工作,你可以尝试使用第三方 Telegram 插件,你可以在网上搜索一下如何使用。
结论
以上就是今天的全部内容,希望你会喜欢,如果你觉得有用的话,请记得点赞我,关注我,并将它分享给你的朋友,也许能够帮助到他。
最后,感谢您的阅读,祝编程愉快!