前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【前端监控】页面错误监控

【前端监控】页面错误监控

作者头像
神仙朱
发布2021-09-09 15:01:10
2K0
发布2021-09-09 15:01:10
举报

小东西快快学快快记,大知识按计划学,不拖延

今天!我们来总结!上报页面错误数据!

言简意赅!不废话!

本文分为4个部分

1、页面错误分类

2、错误监听具体处理

页面错误分类

页面错误这种数据上报的重要性,想必不用我多说了吧

页面通常就分为3种错误

1、js 报错

2、资源加载错误

3、请求报错

其中js执行错误,会显示在控制台上,这也是比较常见的造成bug的原因。

一个多级不判空取值就很可能导致严重的白屏bug

你以为这种错误很少吗,就我们团队就这种bug就出现好多次,被大佬骂惨了,看看我们现在线上监控到的错误

一大半都是 of undefined,of null,is not a function 这些看似非常简单的错误

人有时候存在侥幸和偷懒心理,只觉得成功就行,习惯性忽略错误情况

我大佬常说的一句话,我们要对代码抱有敬畏之心

不说废话了

下面来说下具体如何监听这3种错误分类

监听JS 报错

JS 的抛错,分为 JS 执行错误 和 未被 catch的 promise 错误,他们分别需要监听不同的事件来捕获他们的错误

1JS 执行错误

我们会劫持 window.onerror 事件,如下,重写然后加上自己的处理逻辑

代码语言:javascript
复制
const orgError = window.onerror;

window.onerror = (...args) => {

    // 上报获取错误信息处理逻辑....
    orgError?.call(window, ...args);
};

看下这个函数args都包含了什么(以下按照参数顺序列出)

按字面意思来看已经可以理解了,我们来看一下实际捕获的错误的这个五个参数

其中还有一个比较重要的信息是 第五个参数的 error 对象

里面包含了 调用栈信息,就上面你看到的这些,我给格式化一下

代码语言:javascript
复制
"ReferenceError: userinfo is not defined
    at getuserINfo (http://127.0.0.1:5500/CODE/LOGGER/PAGE_ERROR/index.js:69:3)
    at JSError (http://127.0.0.1:5500/CODE/LOGGER/PAGE_ERROR/index.js:64:3)
    at http://127.0.0.1:5500/CODE/LOGGER/PAGE_ERROR/index.js:87:1"

可以看到所有的函数调用栈,getuserInfo 和 JSError

上报什么数据

除了我们常规的上报基础数据

如你上面看到的数据,都需要上报上去

可以看一下我们监控系统最终上报的数据

我们具体是把这些数据 拼接成一个字符串 ,然后进行上报

问题一览

1、无法获取跨域 js 详细错误

如果你的js文件和引入的页面域名不一致,产生的跨域问题,就会导致无法捕获到详细错误。

只能拿到 Script error,具体参数如下

一般js文件都放在cdn,所以不可避免会跨域的,我们的解决办法也就是解决跨域问题

1.文件添加跨域头 Access-Control-Allow-Origin

2.引入js的script标签加上属性 crossorigin="anonymous"

2、向上抛错

在重写 window.onerror的时候,如果不想继续抛错(捕获之后不显示控制台)

那么就在回调后面return true

但是一般不会这样的,我们是只做拦截,保持原样,否则会对开发者不友好

3、无法捕获语法错误

并不是什么错误都能捕获到,语法错误就不可以比如你乱用关键字

代码语言:javascript
复制
const function = 1

语法错误,可能代码文件解析中断,监听代码当然没有生效

4、根据行列号利用 sourcemap 还原源码位置

这里详细讲又是一大篇了,具体会另外写篇文章总结

可以简单描述一下

我们团队用了sentry 去做这个事

1、项目打包的时候,会把sourcemap上传到 sentry 系统

2、系统根据上报的错误信息就会还原具体的报错位置

比如这样

2未被 catch的 promise 错误

我们还需要监听捕获没有被catch的promise

比如这样

控制台就会显示

具体我们会监听 unhandledrejection 事件来捕获这个错误

代码语言:javascript
复制
window.addEventListener('unhandledrejection', (e)=>{     
  // 上报获取错误信息处理逻辑....
});

看下回调内的事件对象,主要 reason 这个属性,包含了没有 catch 的 错误信息

上报什么数据

除了基础的上报数据,这里我们就只需要把 reason 错误信息字段上报上去就行了

问题一览

1、未被catch的 promise 错误,不是指 promise 内的执行 错误

比如下面 promise 中 读取了一个没有声明的变量 aaa

代码语言:javascript
复制
new Promise((res, rej) => {
  setTimeout(() => {
    console.log(aaa);
    rej('错误');
  }, 1000);
});

这个错误属于 js 执行错误,不属于 promise 错误

所以它会被前面的 window.onerror 捕获到,而不会触发 unhandledrejection 事件

资源报错

监控资源报错我们在另一篇内容有总结,具体可以看 【前端监控】静态资源测速&错误上报

这里再简单描述下

前面我们用window.onerror 来监听js执行错误,但是它并不能获取到资源加载失败的错误,因为这些错误不会向上冒泡,但是我们可以进行捕获

所以我们可以使用 addEventListener 的方式设置捕获监听错误

这里的话可以两种方式

代码语言:javascript
复制
window.addEventListener('error',handler,true)

window.document.addEventListener('error',handler, true)

什么区别呢

window.addxx 可以监听到 js执行错误 + 资源加载错误window.document.addxx 只监听到 资源加载错误

而js执行错误我们已经通过window.onerror拿到了,这里没必要又重复获取一遍。

并且需要区分出错误类型,所以我们这里只监听资源错误就好了

代码语言:javascript
复制
window.document.addEventListener('error',handler, true)

请求报错

请求报错的内容,也已经写过,具体可以参考 【前端监控】自动抓取接口请求数据

简单说,就是 劫持 XMLHttpRequest 和 fetch 方法,在原来的方法上包一层自己的处理逻辑,拿到请求的信息 等

而 判断 请求是否出错,是根据 请求的 status 来判断的

具体标准的 HTTP status code 如下

代码语言:javascript
复制
Informational responses (100–199)
Successful responses (200–299)
Redirects (300–399)
Client errors (400–499)
Server errors (500–599)

如果 status 在 400 以上,我们就认为请求是错误的

另外,在请求完成前,status的值为0。如果 XMLHttpRequest 出错,浏览器返回的 status 也为0,所以0 的情况也要兼容下

另外,请求超时也算错误,我们需要额外判断超时的情况

现在以 xhr 为一个例子说明一下

代码语言:javascript
复制
// ...... 其他劫持逻辑
const originSend = window.XMLHttpRequest.prototype.send;

window.XMLHttpRequest.prototype.send = function () {
  xhr.addEventListener('loadend', function () {
    let type = ''; // 错误类型

    // 超时错误
    if (this.isTimeout) {
      type = 'timeout'; 

    // 在请求完成前,status的值为0。如果 XMLHttpRequest 出错,浏览器返回的 status 也为0。
    } else if (this.status <= 0) { 
      type = 'failed';

    // Client errors (400–499)  Server errors (500–599)
    } else if (this.status >= 400) { 
      type = 'error';
    }

    this.report({
      type,
      url,
      method,
      body,
      duration,
    });
  });

  xhr.addEventListener('timeout', () => {
    xhr.isTimeout = true;
  });

  return originSend.apply(this, arguments);
};

// ......

最后可以看下我们对于线上页面监控的一个异常数据对比图,大概长这样(数据是假的)

可以很清楚看到线上页面的稳定性,一个字,稳

最后

鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵, 如果有任何描述不当的地方,欢迎后台联系本人,领取红包

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 神仙朱 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
前端性能监控
前端性能监控(Real User Monitoring,RUM)是一站式前端监控解决方案,专注于 Web、小程序等场景监控。前端性能监控聚焦用户页面性能(页面测速,接口测速,CDN 测速等)和质量(JS 错误,Ajax 错误等),并且联动腾讯云应用性能监控实现前后端一体化监控。用户只需要安装 SDK 到自己的项目中,通过简单配置化,即可实现对用户页面质量的全方位守护,真正做到低成本使用和无侵入监控。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档