前端错误监控与收集探究

编写代码只是做好项目的一小部分,写代码难免会碰到错误。因此,在项目上线后,我们还需要主动对项目的错误进行收集,不能等用户发现错误,再联系我们,我们再去处理。这样很容易造成大的损失,提前做好错误收集和处理,可以减少损失。

本人并没有做过相关的工作,下面的文章只是我在学习中的一点思考和总结,可能有比较多不足和错误的地方,希望大家指正和指导。

本文章为前端进阶系列的一部分,
欢迎关注和star本博客或是关注我的github

收集哪些错误信息

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

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

错误发生在什么环节

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

  1. 用户没打开网络
  2. DNS域名劫持
  3. http劫持
  4. cdn或是其他资源文件访问出错
  5. 服务器错误
  6. 接口出错
  7. 前端代码错误
  8. 浏览器兼容性问题(css或是js)
  9. 设备屏幕尺寸兼容问题
  10. 用户操作出错
收集哪些信息

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

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

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

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

如何收集错误的信息

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

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

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

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

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

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

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

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

各阶段访问耗时记录

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

首先我们可以关注一下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
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等无能为力

上报错误的方式

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

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

使用创建图片的好处是简单方便可跨域,可以防止重复请求,但要注意到地址栏可以携带的信息有限。

1
2
3
4
function report(error) {
var reportUrl = 'http://xxxx/report';
new Image().src = reportUrl + 'error=' + error;
}

最后

本文章为前端进阶系列的一部分,
欢迎关注和star本博客或是关注我的github

参考

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

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

  3. Google Analytics数据统计的原理

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

hpoenixf wechat
扫码获取最新博客推送
支持作者