从零开始搞监控系统(7)——监控页面奔溃

简介:   页面奔溃包含两种场景,第一种是浏览器在加载网页时遇到问题导致的奔溃,另一种是因为脚本渲染出错导致页面空白无内容的奔溃。

  页面奔溃包含两种场景,第一种是浏览器在加载网页时遇到问题导致的奔溃,另一种是因为脚本渲染出错导致页面空白无内容的奔溃。

  前段时间运营抱怨有张活动页出现了空白(第二种奔溃场景),导致用户无法访问,希望我们能主动监控到这种情况,而不是通过用户的上报。

  后面和运维沟通,他那边目前只能监控接口的访问情况,无法监控静态资源,若要监控得自己想办法实现。

  首先想到的自然是利用现有的监控系统来了解页面空白情况,例如某个项目5分钟内没有监控日志,那就认为出现了页面奔溃。

  急匆匆的写了段定时任务,放到线上运行,发现这样监控会有一个很大漏洞。因为某些项目的访问量本来就不高,5分钟内没有日志是属于正常情况,所以只得作罢。


一、页面奔溃


  首先来解决第一种奔溃场景,在网上搜了些关键字,发现了些有用的资料,例如如何监控网页崩溃前端崩溃监控优化历程等。

  这些资料提供了一个全新的思路来监控页面奔溃,基于Service Worker的崩溃统计方案。

  简单地说就是一种心跳检测机制,在页面的脚本中创建Service Worker工作线程,然后定时地向该线程发送消息,即使网页奔溃了,线程还能存活。

  在线程中接收消息并比对时间,当间隔时间大于15秒时,就认为超时没有心跳了,页面处于奔溃阶段,向监控系统上报相关信息。

  在我操刀实现的时候,Service Worker没有运行成功,后面就改成了Web Worker

  工作线程的代码保存在sw.js(如下所示),在参考一篇Web Workers的文章时,他提到在线程中可以navigator对象,该对象正好有个sendBeacon()方法,可用于跨域请求。

  但是没想到线程中用的WorkerNavigator,并没有该方法,后面无奈改成了fetch()

  但是有跨域问题,要么在响应时加上跨域头,要么就无视直接发送,因为浏览器只会拦截响应不会拦截请求。


var CHECK_CRASH_INTERVAL = 10 * 1000;     // 每 10s 检查一次
var CRASH_THRESHOLD = 15 * 1000;          // 15s 超过15s没有心跳则认为已经 crash
var pages = {}, timer;
function send(param) {
    fetch(param.src);
};
function checkCrash() {
  var now = Date.now()
  for (var id in pages) {
    var page = pages[id];
    if ((now - page.t) > CRASH_THRESHOLD) {
      // 上报 crash
      delete pages[id];
      send(page.data);
    }
  }
  if (Object.keys(pages).length == 0) {
    clearInterval(timer)
    timer = null
  }
}
self.addEventListener('message', (e) => {
  var data = e.data;
  if (data.type === 'heartbeat') {
    // console.log('heartbeat');
    pages[data.id] = {
      t: Date.now(),
      data: data.data
    }
    if (!timer) {
      timer = setInterval(function () {
        checkCrash()
      }, CHECK_CRASH_INTERVAL)
    }
  } else if (data.type === 'unload') {
    delete pages[data.id]
  }
})

  在网页中加的代码如下,由于Worker加载的脚本有同源策略的限制,所以脚本和页面需要在相同的域名中。


function monitorCrash(param) {
  var isCrash = param.isCrash;
  if (!isCrash || !window.Worker) return;
  var worker = new Worker("/sw.js");
  var HEARTBEAT_INTERVAL = 5 * 1000; // 每五秒发一次心跳
  var sessionId = getIdentity();
  var heartbeat = function () {
      worker.postMessage({
        type: "heartbeat",
        id: sessionId,
        data: {
          //在页面奔溃时,上报数据,需要将上报地址一起传递
          src: param.src
        }
      });
  };
  window.addEventListener("beforeunload", function () {
    worker.postMessage({
      type: "unload",
      id: sessionId
    });
  });
  var timer = setInterval(heartbeat, HEARTBEAT_INTERVAL);
  heartbeat();
}


  上线后先在管理后台做测试,管理后台使用的是PC浏览器,马上就发现了比较严重的误报问题。

  分析下来有可能是网页在标签栏不活动的时候,影响了定时器的执行,再次活动计算两个时间段的间隔,很有可能超出了15秒,而上报奔溃日志。

  鉴于此,在没有完美解决方案之前,暂时将此功能下架。


二、页面空白


  再来解决第二种奔溃场景,现在开发都会依托React或Vue等库或框架,而这些都是用脚本来渲染出DOM结构的。

  一旦在渲染时出现脚本错误(例如未定义的变量、浏览器不支持的语法等)就会中断渲染,从而就会出现页面无内容的情况。

  这类监控并不需要使用Web Worker,只要我的监控SDK在业务脚本之前引入,就能保证监控代码正常运行。

  监控原理就是加个定时器,查看渲染容器中是否是空白,若是空白就上报并关闭定时器,否则循环监控。

  例如后台管理系统采用的是React,在HTML中会声明一个div元素,内容都会渲染到该元素中。

<div id="root"></div>

  自定义一个判断条件,如下所示,在定时器中循环执行。

document.getElementById("root").innerHTML.length > 0

  此处还有个小坑,就是定时器的运行时机,不能太早,太早判断的话,div元素中肯定没有内容,后面就将判断时机移到了DOMContentLoaded事件中。

 

相关文章
|
24天前
|
监控 数据安全/隐私保护 iOS开发
服务器监控新利器:ServerBee带你看透服务器运行状态
服务器监控新利器:ServerBee带你看透服务器运行状态
33 0
|
11月前
|
SQL JSON Java
你居然还去服务器上捞日志,搭个日志收集系统难道不香么
ELK日志收集系统进阶使用,本文主要讲解如何打造一个线上环境真实可用的日志收集系统。有了它,你就可以和去服务器上捞日志说再见了!
|
11月前
|
存储 网络协议 数据可视化
面对成百上千台服务器产生的日志,试试这款轻量级日志搬运神器
之前我们搭建的ELK日志收集系统,主要是用来收集SpringBoot应用的日志。其原理是应用通过Logstash插件,使用TCP向Logstash传输日志,从而存储到Elasticsearch中去。但是有很多中间件的日志都是直接存储在文件中的,比如Nginx、Elasticsearch和MySQL,此时我们就需要一个搬运工来把日志搬到Elasticsearch中去,Filebeat正是这样一个日志搬运工,本文将详细介绍它的使用方法,希望对大家有所帮助。
|
11月前
|
Prometheus 监控 Kubernetes
告别低效繁琐的Prometheus告警管理,Nightingale助你快速响应故障!
Prometheus的告警规则、记录规则都是采用配置文件管理,适合奉行Infrastructure as Code的公司或团队内部使用。但如果要把监控能力开放给全公司,就要支持协同操作的 UI,让各个团队互不干扰的同时共享成果
582 0
|
消息中间件 运维 监控
线上踩坑记:项目中一次OOM的分析定位排查过程!
线上踩坑记:项目中一次OOM的分析定位排查过程!
|
SQL Java 数据库连接
线上运行的项目突然变得很卡如何排查?
线上运行的项目突然变得很卡如何排查?
|
SQL 固态存储 关系型数据库
经典案例:磁盘I/O巨高排查全过程(1)
经典案例:磁盘I/O巨高排查全过程
261 0
经典案例:磁盘I/O巨高排查全过程(1)
|
Web App开发 运维 监控
再谈前端性能监控及4个最佳工具分享
对于大多数开发人员而言,监控应用程序的性能并不是一个陌生的概念。在某些情况下,我们必须自己进行一些性能调试。通常,当出现影响用户体验或影响成本的大问题时,就需要去监控应用程序的性能。同时我们也需要话时间去查看应用在不同场景下的表现情况。
738 0
再谈前端性能监控及4个最佳工具分享
|
前端开发 数据可视化 JavaScript
《全栈导航》网站挂掉-我是如何排查问题
《全栈导航》网站挂掉-我是如何排查问题
259 0
《全栈导航》网站挂掉-我是如何排查问题
|
JSON 监控 小程序
从零开始搞监控系统(5)——小程序监控
  公司目前在线上运行着一款小程序,为了能监控小程序的运行情况,自行开发了一个参数搜集的SDK,名称为 shin.js,放置在 utils 目录中。
从零开始搞监控系统(5)——小程序监控