错误信息监控
收集哪些错误信息
先从一个面试题开始吧。腾讯第二轮电话面试的一个题目:如果用户使用网页,发现白屏,现在联系上了你们,你们会向他询问什么信息呢?
一个个去堆答案没有意思,我们换个思路,先想一下为什么会白屏?
错误发生在什么环节
跟我之前的性能优化的文章一样,我们以用户访问页面的过程为顺序,大致排查一下
- 用户没打开网络
- DNS域名劫持
- http劫持
- cdn或是其他资源文件访问出错
- 服务器错误
- 接口出错
- 前端代码错误
- 浏览器兼容性问题(css或是js)
- 设备屏幕尺寸兼容问题
- 客户端出错
- 上面被盖了了webview或是别的元素
- 用户操作出错
收集哪些信息
通过以上可能发生错误的环节,我们需要向用户手机一下以下的用户信息
- 当前的网络状态
- 运营商
- 地理位置
- 访问时间
- 客户端的版本(如果是通过客户端访问)
- 系统版本
- 浏览器信息
- 设备分辨率
- 页面的来源
- 用户账号信息
- 页面访问流程各阶段耗时
- js代码报错信息
另外,参考Google Analytics数据统计的原理,我们还可以收集下面的信息
- 用户的浏览器语言编码
- 浏览器语言设置
- flash的版本
- 网页的标题
- 网页的来源
- cookie的数据
怎么发现白屏
- N秒没触发onload
- N秒后页面仍然是白的
- N秒后DOM元素少于X个
- 前端主动触发
如何收集错误的信息
现在话题来到了如何收集错误信息了。
前端错误收集有两大流派:
一个是虚拟机监控,优点是指标齐全,并且可以进行竞品监控,缺点是反映不全,容易失真
下面简单列出一些虚拟机监控的方案
- 图片对比,每隔一段时间使用虚拟机访问页面并截图然后进行相似度对比,如果差值超出一定的数值,进行报警
- 定时抓取页面的HTML源码,分析是否出现异常
另一个是脚本监控,优点是可以收集海量真实数据,缺点是影响性能,采样少的情况下容易失真。
这里暂时只重点讲脚本监控(挖个坑,之后可能填)
在这里,我们主要利用脚本收集用户的各阶段访问消耗时间以及错误信息
各阶段访问耗时记录
之所以要收集访问耗时,是为了查出是什么阶段消耗的时间较多,从而更好的定位错误来源。
performance
首先我们可以关注一下Performance,下面就先讲一下其中的两个API
performance timing
具体可以查看w3.org/TR/navigation-timing、Navigation Timing API。
在chrome浏览器控制台输入Performance.timing,会得到记录了一个浏览器访问各阶段的时间的对象。
进行错误收集的时候,可以对比这些时间,看错误发生在什么阶段
- DNS 查询耗时 :domainLookupEnd - domainLookupStart
- TCP 链接耗时 :connectEnd - connectStart
- request 请求耗时 :responseEnd - responseStart
- 解析 dom 树耗时 : domComplete - domInteractive
- 白屏时间 :responseStart - navigationStart
- domready 时间 :domContentLoadedEventEnd - navigationStart
- onload 时间 :loadEventEnd – navigationStart
- TTFB 首包时间 responseStart - Requeststart
- tti 可交互时间: domInteractive - fetchstart
performance getEntries
具体参见W3C Resource timing,Performance.getEntries()
通过performance.getEntries(),可以得到一个数字,其中的每个元素分别代表着一个资源,元素对象包括的属性跟上面的performance timing有点接近,还有不同的属性包括name代表资源的地址,请求花费的时间duration。
其他方法
记录访问开始的时间可有以下的方法:
- 服务器将访问的时间渲染到页面上
- SPA的话,记录前一个页面卸载的时间
记录访问过程的时间
- 在head标签解析后,渲染body标签前加入script标签进行打点,一般将这个时间视为白屏时间
- 捕获DOMContentLoaded事件来记录dom元素加载完毕的时间
- 在首屏页面的所有图片加载完后进行记录,保存首屏时间
- 捕获load事件记录页面加载完成的时间
脚本错误信息收集
window.onerror
window.onerror可以捕捉运行时错误,可以拿到出错的信息,堆栈,出错的文件、行号、列号
要注意以下几点:
要把window.onerror这个代码块分离出去,并且比其他脚本先执行(注意这个前提!)即可捕捉到语法错误。
由于网络请求异常事件不会冒泡,需要在捕获阶段进行处理
不能捕获promise的错误信息
跨域资源需要专门处理,需要在script标签加上crossorigin属性,服务器设置Access-Control-Allow-Origin
window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx。
promise的错误处理
promise除了使用catch方法来捕获错误,还可以使用window的unhandledrejection事件捕获异常的
|
|
try catch
无法捕捉到语法错误,只能捕捉运行时错误;
可以拿到出错的信息,堆栈,出错的文件、行号、列号; 需要借助工具把所有的function块以及文件块加入try,catch,可以在这个阶段打入更多的静态信息。
要注意的是try catch只能捕获同步代码的异常,对回调,setTimeout,promise等无能为力
API出错上报
获取请求,如果接口出错或是异常,报错
性能信息监控
performance.timing
埋点sdk上报
监听onload,contentload事件
检测dom数量
检测最大面积的元素加载
用户行为监控
- 事件监听,滚动,点击等
- 业务主动上报
- API请求
- 用户对页面的操作
上报手段
后端提供接口,前端ajax上传
创建一个新的图片,url参数带上错误信息
推荐使用gif,原因如下:
- 简单方便可跨域
- 可以防止重复请求
- 服务器不用做响应
- navigator.sendBeacon
能保证在退出页面前发送
- 无埋点或是可视化埋点
生成页面唯一标致,监听事件,用户行为等,dom节点上埋下坑位方便定位