前端埋点 - 报错监控
说起埋点又到了谈起前端项目中数据收集与监控,那么今天来简单的聊下前端报错监控的埋点。
首先先安利下自己做的报错监控的项目 FE-Monitor 欢迎 issue 和 star 。
首先我们可以看下前端做报错监控的意义在哪里:
- 帮助灰度测试发现问题
- 收集线上错误日志
- 帮助优化产品稳定性
- 收集错误数据用于分析
- 监控第三方资源/CDN 稳定性
总体来说前端监控的主要目的都是为了获取用户行为以及跟踪产品在用户端的使用情况,并以监控数据为基础,指明产品优化方向。
常见监控方式
try { test code // throw error } catch(e){ console.log(e); }
上面的代码在项目中很常见,一般用来捕获某一段可能代码抛出的错误信息。并且在try catch 中的错误并不会阻塞整个页面,即使发生错误,页面也可以继续执行。
当然,我们不太可能对这个项目中的每一段代码都添加 try catch,这样不仅不利于线上定位问题产生的原因,也会让代码难以维护,目前主流的就是在项目中独立引入一个报错监控的 JS 来单独的完成对整个项目的监控。
比如 FE-Monitor 就提供开源的项目报错监控的能力,只需要将 SDK 引入自己的项目中,即可监控整个项目的js执行报错,资源加载异常,ajax错误等信息了。
ajax 错误监控
ajax 的错误监控主要是为了发现服务接口返回值的问题。
看了一些产品的实现都是对 window 下的 XMLHttpRequest
重写,但是这样直接重写不仅会造成调用链的修改也会让宿主页面上的多个 ajax 库产生冲突,如使用了 jquery 的话 jquery 中是直接使用 XMLHttpRequest
对象的。如果修改了全局的对象中的属性可能会造成以外的影响。
用了一种特殊的方式去实现对 XMLHttpRequest
对象的监听。
_initListenAjax: function () { let self = this; function ajaxEventTrigger(event) { var ajaxEvent = new CustomEvent(event, { detail: this }); window.dispatchEvent(ajaxEvent); } var oldXHR = window.XMLHttpRequest; function newXHR() { var realXHR = new oldXHR(); realXHR.addEventListener('load', function ($event) { ajaxEventTrigger.call(this, 'ajaxLoad'); }, false); realXHR.addEventListener('timeout', function () { ajaxEventTrigger.call(this, 'ajaxTimeout'); }, false); realXHR.addEventListener('readystatechange', function() { ajaxEventTrigger.call(this, 'ajaxReadyStateChange'); }, false); return realXHR; } window.XMLHttpRequest = newXHR; self._startLintenAjax(); }
这样做不仅可以一经调用就监控到页面的错误,不会出现重写 window.onerror
的时候第一次错误监控不到的情况还需要重写 console.error
函数才可以监听到。
error错误监控
错误监控中对 error
事件的监控是最重要的,监听 error 的事件主要是为了发现 js 执行中抛错。
window.addEventListener("error", function(err) { getError(err, self._config); }, true);
监控 error 报错的情况中,最 error 的处理中要判断是否是我们设置的埋点接口的 URL 所抛错的。主要是为了避免在埋点服务宕机的情况下出现重复请求上报,造成页面卡死的情况。
监控资源加载异常
页面上有很多的外部的资源,一般来说对资源的加载的监控是在资源标签添加 onerror
的方法来监听加载错误信息。
支持onload的标签:<body>, <frame>, <frameset>, <iframe>, <img>, <input type="image">, <link>, <script>, <style>支持onerror的标签:<img>, <input type="image">, <object>, <script>, <style> , <audio>, <video>
这种做法和对js 代码添加 try catch一样,需要对每个资源都不断的添加监控。
对比之后 使用 addEventListener
监控整体的项目资源加载更方便快捷。
window.addEventListener("error", function(err) { getError(err, self._config); }, true);
其中 addEventListener
方法中的第三个参数是 useCapture,如果将 useCapture 设置为 true,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段处理事件。 如果useCapture 为 false,则侦听器只在目标或冒泡阶段处理事件。
其中回调函数中接受的 err 中有 cancelable
属性的是js执行错误,所以可以通过 err 上时候有 cancelable
属性来判断不同类型的错误。