前端监控是个大工程,最终形态是个精密、完整、自动化的后台系统。本篇带大家认识一个完善的监控系统能做些什么事,大家再根据团队及需求打造符合自身业务场景的监控系统,丰俭由人。
为什么需要建立前端监控系统
大家应该有所体会,前端同学作为出 bug 的第一责任人(开玩笑的),被突然喊来排查 bug 的时候,容易陷入被动。慌乱、紧张、尴尬的前端同学该如何自救?自然是找个办法防范于未然,建立前端监控系统,开启全知之眼,转被动为主动。
对于以业务为重心的项目,前端同学怎样充分体现自己的价值?收集用户画像,用留存率转化率等数据,打出业绩组合拳。
收集前端性能数据,对关键环节长期监控优化。让数据暴露优化点,让数据支撑优化成果。
每次发布线上心惊胆战,不敢确认是否能正常运行、担心有平台兼容问题
前端监控系统的组成
按业务模块区分
根据上边描述的痛点,前端监控系统大致可以归为四类:
- 前端监控系统
|- 用户行为监控
|- 错误监控
|- 性能监控
|- 测试监控
-
用户行为监控
即通过采集用户行为以用于描绘用户画像、提升产品体验。例如我们可以收集页面的停留时间、不同按钮的点击次数、从浏览到下单的时间、支付方式的选择等等。通过这些数据来计算业务的转化率、构建漏斗模型,为产品下一步的功能和优化提供数据支撑
-
错误监控
收集因各类原因造成的系统错误,包括前端代码错误、接口格式错误、网络错误等等。然后对错误信息进行重复过滤、错误解决指派、优雅降级。
-
性能监控
即收集前端各项性能数据,例如页面加载时间、渲染时间、CDN主要流量、打包速度及大小。逐渐优化最拉胯的项来提升前端性能。
-
测试监控
一般单元测试和代码风格测试会在代码提交或者发布前进行,但同样有监控 E2E(end to end)测试结果的需求,即前端代码发布上线后,在各浏览器;安卓、IOS、小程序的webview中进行自动化界面测试,确保代码在各主流平台能够运行。
-
运营数据采集 严格来说采集运营数据超出了前端的范畴,但是部分数据也需要前端采集,比如日活跃用户数这类和项目价值相关的数据,这部分数据可能和用户行为有重叠。
按技术实现区分
从技术实现上,实现一个监控系统,可以分为三个部分:
- 按实现划分
|- 收集监控数据
|- 过滤、展示监控数据
|- 报警及监控事件的后续处理
这三个部分的具体实现方式如下:
如何收集监控数据
为了收集出有价值的数据,我们通常会通过代码调用接口来上报数据。如果代码具有一定的规律,则可以考虑用脚本来插入代码。
在前端项目里,收集数据的方式有很多,主要围绕在恰当的时机上报,时机包括且不限于:
- 在页面生命周期中上报
// onunload
window.onload=function(){
axios.get('/api/report', {
params: {
userId: 'xxxxxxxx',
userAgent: window.navigator.userAgent,
time: new Date().getTime(),
reportContent: `访问了${window.location.href}页面`
}
})
}
// 或者 Vue 中,还有 beforeDestroy 等
mounted() {
axios.get('/api/report')
}
- 在交互事件中
const $dom = document.querySelector('#dom')
// event:input scroll
$dom.addEventListener('click', function () {
axios.get('/api/report', {
params: {
// ...,
reportContent: `点击了`
}
})
})
- 在接口请求方法的拦截器中
axios.interceptors.response.use(function (response) {
// 出现了和后端约定的错误码
if (response.data.code === '某些需要关注的错误码') {
// 发送错误报警
axios.get('/api/report', {
params: {
userId: 'xxxxxxxx',
userAgent: window.navigator.userAgent,
time: new Date().getTime(),
reportContent: `出现了${response.data.code}错误码`
}
})
}
return response;
}, function (error) {
axios.get('/api/report', {
params: {
// ...,
reportContent: `接口错误,错误信息为:${error.message}`
}
})
return Promise.reject(error);
});
- 在异常捕获链中:
try {
// ...
} catch (error) {
axios.get('/api/report', {
params: {
// ...,
reportContent: `代码块发生了错误,错误信息为:${error.message}`
}
})
}
window.onerror = function (msg, url, lineNo, columnNo, error) {
axios.get('/api/report', {
params: {
// ...,
reportContent: `发生了全局错误:${error.message}`
}
})
}
window.addEventListener('unhandledrejection', (error) => {
axios.get('/api/report', {
params: {
// ...,
reportContent: `发生了promise未被处理的reject:${error.reason}`
}
})
})
// Vue
Vue.config.errorHandler = function(error, vm, info) {
console.log(`Vue组件发生错误:${error.message}`)
}
// React
componentDidCatch(error, info) {
console.log(`React组件发生错误:${error.message}`)
}
- 还有一些非用户端数据上报的场景,比如 jenkins 打包速度、CDN消耗流量、部署前后进行的自动化测试结果等,需要对应的服务提供钩子执行脚本上报。
如何过滤、展示监控数据
对于一些上报频繁的数据,我们需要过滤处理不然会使服务器负担太大。例如某个接口错误或者易出现的JS错误,可用的做法是给不同的场景一个 code,根据 code 和 错误信息去重,记录必要的数据、舍弃冗余的数据。
展示监控数据通常是 列表 + 图标的形式,例如以时间倒序展示的线上报错列表 + 每行报错对应的分析图表。通过不同维度的筛选,做到数据的可视化
后台管理的菜单、表格、表单可以使用 element-plus 或者 antd;可视化图表可以使用 antv 或者 echarts
在列表中我们还可以加上任务指派、快捷操作等按钮,方便对监控内容进行快速响应。
自动化监控
为了保证系统稳定运行,我们可以在一些时机中对代码质量和结果进行自动化检测。例如:
- 绑定 git 仓库 hook,检测提交的代码是否符合 eslint 规范
- 绑定 git 仓库 hook,提交时运行单元测试看看是否全部通过
- 部署代码后运行 e2e 测试,对发布后的代码做不同客户端测试
- 定时测试接口,校验接口是否符合文档的数据格式
支持优雅系统降级
当系统发生致命错误时,可以自动触发处理流程,紧急切换到降级系统,关于降级系统有几个方案:
- 通过 HTTP 缓存服务器如 varnish ,对错误的接口暂时用缓存返回
- 切换到旧版本的代码上
- 专门编写降级系统作为备用
- 静态资源报网络错误可以切换到备用 CDN 地址
实践相关文章
以上是对前端监控系统的体系和实现思路做介绍,在公司中的具体实践大家可以参考更多优秀文章: