为什么
线上监控可以让我们方便的了解到业务产品的真实指标,如访问量、用户交互数据、页面错误、性能等关键信息。对于应用的体验优化和用户精细化运营至关重要。
线上监控是个比较复杂的体系,包括数据采集、处理计算、可视化等方面。这里篇幅和知识所限,只说端上的数据采集方面。
做什么
我们已经了解到监控的所需要的数据指标,基于此我们要采集哪些类型的数据呢?
具体如下:
- 应用加载、卸载,这是访问量
- 路由切换,对于单页面很重要
- 性能,包括加载时,运行时
- 错误,接口错误,JS 错误
- 用户交互数据,点击、眼球曝光埋点
不做什么
我们整个线上监控体系设计的目标是稳定(不会影响正常业务,埋点不会轻易失效),高效(不会对应用产生性能负担),无侵入性(不会限制业务)。基于此我们放弃以下方案。
不做无埋点/可视化埋点
无埋点和可视化埋点的原理都是利用 DOM 属性或 css 选择器将埋点和元素一一对应。而页面结构变动反过来会影响埋点的定位。这也是它们不稳定的根本原因。抛弃这类方案的原因在于:它提供的收益(埋点开发效率)和成本(埋点失效后的排查、反馈、修复)不成正比。
数据模型
我们现在已经知道了线上监控所关心的具体指标和数据类型,那么具体到某一条数据,我们关系哪些参数、用一个什么样的数据模型来指导我们的采集和分析呢?
总的来看,我们关注这些数据:
- 用户是谁 用户的设备ID,账号
- 用户的设备信息,什么系统,什么浏览器,4G 还是 WIFI
- 时间信息,错误,用户交互产生的时间
- 用户产生了什么行为,点击,眼球曝光,页面切换
- 其他上下文信息,IP,业务自定义数据
采集原理
应用加载卸载
当然是监听 load
、beforeunload
事件
路由切换
当然可以使用 hashchange
、hack history
API,但这些很难获取到动态路由的信息。比如如果一个路由的 path 为 blog/:id
。就很难将 blog/a
和 blog/b
做数据聚合。这方面可以提供一个 sendPageView
方法给到业务,业务自己在路由钩子内调用该方法即可。
性能数据
使用 performance
API,具体不在赘述。
错误信息
可以使用 window.onerror
来监听一部分错误,但这个方法兼听不到 promise 错误和 script error 。一些前端框架的错误,如 react 的 componentDidCatch
也需要做特殊定制。
用户交互数据
用户交互数据也就是通常所说的埋点,实现起来其实非常简单。
比如我们通过声明式埋点来上报数据,埋点标识为属性中带 data-track-id
的元素。
document.addEventListener('click', (e) => {
if (e.path.some(el => el.matches('[data-track-id]'))) {
// 上报数据
}
}, true)
数据上报
之前也说到,监控方案的目标是稳定和高效。为了不影响业务应用的性能,我们会把采集的关键逻辑使用 window.requestIdleCallback
包裹起来。
为了在浏览器关闭时也能上报数据,我们会使用 Navigator.sendBeacon
来上报数据,对于不支持这个 API 的浏览器,我们使用构造 image 请求来做 fallback 和跨域。
为了减少流量和服务器压力,在采集端也会做缓存,请求协议上也会做一些优化,这里不再赘述。
总结
这里简单介绍了一些前端监控体系的方向和经验之谈。没有涉及大数据处理,也不包括数据的聚合展示,数据采集只是这个体系中很小的一环。而线上监控其实也只是整个前端工程体系中的一小部分。作为一个前端工程师,如果不懂运维,不懂后端,那么能在整个前端工程体系中发挥的作用就很有限。