前端监控探究

错误信息监控

收集哪些错误信息

先从一个面试题开始吧。腾讯第二轮电话面试的一个题目:如果用户使用网页,发现白屏,现在联系上了你们,你们会向他询问什么信息呢?

一个个去堆答案没有意思,我们换个思路,先想一下为什么会白屏?

错误发生在什么环节

跟我之前的性能优化的文章一样,我们以用户访问页面的过程为顺序,大致排查一下

  1. 用户没打开网络
  2. DNS域名劫持
  3. http劫持
  4. cdn或是其他资源文件访问出错
  5. 服务器错误
  6. 接口出错
  7. 前端代码错误
  8. 浏览器兼容性问题(css或是js)
  9. 设备屏幕尺寸兼容问题
  10. 客户端出错
  11. 上面被盖了了webview或是别的元素
  12. 用户操作出错

收集哪些信息

通过以上可能发生错误的环节,我们需要向用户手机一下以下的用户信息

  1. 当前的网络状态
  2. 运营商
  3. 地理位置
  4. 访问时间
  5. 客户端的版本(如果是通过客户端访问)
  6. 系统版本
  7. 浏览器信息
  8. 设备分辨率
  9. 页面的来源
  10. 用户账号信息
  11. 页面访问流程各阶段耗时
  12. js代码报错信息

另外,参考Google Analytics数据统计的原理,我们还可以收集下面的信息

  1. 用户的浏览器语言编码
  2. 浏览器语言设置
  3. flash的版本
  4. 网页的标题
  5. 网页的来源
  6. cookie的数据

怎么发现白屏

  1. N秒没触发onload
  2. N秒后页面仍然是白的
  3. N秒后DOM元素少于X个
  4. 前端主动触发

如何收集错误的信息

现在话题来到了如何收集错误信息了。

前端错误收集有两大流派:

一个是虚拟机监控,优点是指标齐全,并且可以进行竞品监控,缺点是反映不全,容易失真

下面简单列出一些虚拟机监控的方案

  1. 图片对比,每隔一段时间使用虚拟机访问页面并截图然后进行相似度对比,如果差值超出一定的数值,进行报警
  2. 定时抓取页面的HTML源码,分析是否出现异常

另一个是脚本监控,优点是可以收集海量真实数据,缺点是影响性能,采样少的情况下容易失真。

这里暂时只重点讲脚本监控(挖个坑,之后可能填)

在这里,我们主要利用脚本收集用户的各阶段访问消耗时间以及错误信息

各阶段访问耗时记录

之所以要收集访问耗时,是为了查出是什么阶段消耗的时间较多,从而更好的定位错误来源。

performance

首先我们可以关注一下Performance,下面就先讲一下其中的两个API

performance timing

具体可以查看w3.org/TR/navigation-timingNavigation Timing API

在chrome浏览器控制台输入Performance.timing,会得到记录了一个浏览器访问各阶段的时间的对象。

进行错误收集的时候,可以对比这些时间,看错误发生在什么阶段

  1. DNS 查询耗时 :domainLookupEnd - domainLookupStart
  2. TCP 链接耗时 :connectEnd - connectStart
  3. request 请求耗时 :responseEnd - responseStart
  4. 解析 dom 树耗时 : domComplete - domInteractive
  5. 白屏时间 :responseStart - navigationStart
  6. domready 时间 :domContentLoadedEventEnd - navigationStart
  7. onload 时间 :loadEventEnd – navigationStart
  8. TTFB 首包时间 responseStart - Requeststart
  9. tti 可交互时间: domInteractive - fetchstart
performance getEntries

具体参见W3C Resource timingPerformance.getEntries()

通过performance.getEntries(),可以得到一个数字,其中的每个元素分别代表着一个资源,元素对象包括的属性跟上面的performance timing有点接近,还有不同的属性包括name代表资源的地址,请求花费的时间duration。

其他方法

记录访问开始的时间可有以下的方法:

  1. 服务器将访问的时间渲染到页面上
  2. SPA的话,记录前一个页面卸载的时间

记录访问过程的时间

  1. 在head标签解析后,渲染body标签前加入script标签进行打点,一般将这个时间视为白屏时间
  2. 捕获DOMContentLoaded事件来记录dom元素加载完毕的时间
  3. 在首屏页面的所有图片加载完后进行记录,保存首屏时间
  4. 捕获load事件记录页面加载完成的时间

脚本错误信息收集

window.onerror

window.onerror可以捕捉运行时错误,可以拿到出错的信息,堆栈,出错的文件、行号、列号

要注意以下几点:

  1. 要把window.onerror这个代码块分离出去,并且比其他脚本先执行(注意这个前提!)即可捕捉到语法错误。

  2. 由于网络请求异常事件不会冒泡,需要在捕获阶段进行处理

  3. 不能捕获promise的错误信息

  4. 跨域资源需要专门处理,需要在script标签加上crossorigin属性,服务器设置Access-Control-Allow-Origin

  5. window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx。

promise的错误处理

promise除了使用catch方法来捕获错误,还可以使用window的unhandledrejection事件捕获异常的

1
2
3
4
5
6
7
8
window.addEventListener("unhandledrejection", function(e){
// Event新增属性
// @prop {Promise} promise - 状态为rejected的Promise实例
// @prop {String|Object} reason - 异常信息或rejected的内容
// 会阻止异常继续抛出,不让Uncaught(in promise) Error产生
e.preventDefault()
})

try catch

无法捕捉到语法错误,只能捕捉运行时错误;
可以拿到出错的信息,堆栈,出错的文件、行号、列号; 需要借助工具把所有的function块以及文件块加入try,catch,可以在这个阶段打入更多的静态信息。

要注意的是try catch只能捕获同步代码的异常,对回调,setTimeout,promise等无能为力

API出错上报

获取请求,如果接口出错或是异常,报错

性能信息监控

performance.timing

埋点sdk上报

监听onload,contentload事件

检测dom数量

检测最大面积的元素加载

用户行为监控

  • 事件监听,滚动,点击等
  • 业务主动上报
  • API请求
  • 用户对页面的操作

上报手段

  1. 后端提供接口,前端ajax上传

  2. 创建一个新的图片,url参数带上错误信息

推荐使用gif,原因如下:

  • 简单方便可跨域
  • 可以防止重复请求
  • 服务器不用做响应
  1. navigator.sendBeacon

能保证在退出页面前发送

  1. 无埋点或是可视化埋点

生成页面唯一标致,监听事件,用户行为等,dom节点上埋下坑位方便定位

参考

  1. 前端魔法堂——异常不仅仅是try/catch

  2. 前端优化-如何计算白屏和首屏时间

  3. Google Analytics数据统计的原理

  4. 初探 performance – 监控网页与程序性能

支持作者

如果我的文章对你有帮助,欢迎 关注和 star 本博客 或是关注我的 github,获取更新通知。欢迎发送邮件到hpoenixf@foxmail.com与作者交流