Skip to content

Latest commit

 

History

History
140 lines (105 loc) · 5.27 KB

前端监控系统实现.md

File metadata and controls

140 lines (105 loc) · 5.27 KB

0、前言

一个强大,好用的统计分析系统,能够非常方便的将用户访问数据,站点性能数据,各种统计信息进行汇总展示。这对于有点体量的公司都是非常重要的。

1、客户端信息收集

1.1、基本信息

要收集浏览器信息,一般是通过 navigator 对象,从这里面,可以获取到:

navigator.language // 浏览器当前语言
navigator.userAgent // 浏览器信息
navigator.platform // 操作系统平台
navigator.javaEnabled() // 是否支持Java
navigator.maxTouchPoints // 触摸点个数

其次,还会通过 screen 收集屏幕信息:

screen.width // 屏幕宽度
screen.height // 屏幕高度
screen.colorDepth // 屏幕颜色bit

通过 document 获取文档相关信息

document.referrer // 来源站点
document.charset || document.characterSet // 字符编码

1.2、性能信息

要收集性能信息,我们需要通过 performance 对象,其中大致分为:Navigation Timing, User Timing 以及 Resource Timing

首先,通过 var perfData = window.performance.timing; 获取到时间点数据,这些时间数据都是以long类型的UTC时间,数据大致结构如下:

var perfData = {
  connectEnd:                 1511431220347, // 结束连接
  connectStart:               1511431220347, // 开始连接
  domComplete:                1511431221532, // DOM渲染完毕
  domContentLoadedEventEnd:   1511431220886,
  domContentLoadedEventStart: 1511431220884,
  domInteractive:             1511431220884,
  domLoading:                 1511431220680, // 开始DOM渲染
  domainLookupEnd:            1511431220347, // 结束DNS解析
  domainLookupStart:          1511431220347, // 开始DNS解析
  fetchStart:                 1511431220347, // 开始Fetch
  loadEventEnd:               1511431221565,
  loadEventStart:             1511431221532,
  navigationStart:            1511431220272, // 开始导航
  redirectEnd:                0,             // 结束跳转
  redirectStart:              0,             // 开始跳转
  requestStart:               1511431220353, // 开始请求
  responseEnd:                1511431220680, // 结束响应
  responseStart:              1511431220678, // 开始响应
  secureConnectionStart:      0,             // 开始安全连接
  unloadEventEnd:             0,
  unloadEventStart:           0
}

以此,我们可以得出如下时间数据:

var dnsLookupTime = perfData.domainLookupEnd - perfData.domainLookupStart; // DNS解析耗时
var tcpConnectTime = perfData.connectEnd - perfData.connectEnd; // TCP连接耗时
var pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; // 页面加载时间,对应 Network 的 Load
var sendRequestTime = pertData.responseStart - perfData.requestStart; // 发送请求耗时
var serverResponseTime = pertData.responseEnd - perfData.responseStart; // 服务端响应耗时
var renderTime = perfData.domComplete - perfData.domLoading; // 页面渲染所用的时间
var domContentLoadedTime = perfData.domContentLoadedEventEnd - perfData.navigationStart;// 页面内容加载时间,对应 Network 的 DOMContentLoaded
var resolveDomTreeTime = perfData.domComplete - perfData.domInteractive; // 解析DOM树耗时
var whiteScreenTime = perfData.domLoading - perfData.navigationStart; // 白屏时间

2、异常信息收集

对于异常来说,我们一般会提供自动异常收集,也需要允许主动上报异常。

如何自动上报异常呢?

我们可以监控 window.error,然后获取到错误信息,进行上报。

window.addEventListener('error', function (evt) {
  console.log(evt);
}, false);

主动上报

对于主动上报的话,我们仅仅需要提供一个方法,来触发一次上报即可。

trackException(evt) {
  const self = this;
  const data = getExceptionData(evt);
  data.tid = self._tid;
  data.t = 'exception';
  report(self._url, data);
}

3、上报细节处理

如何给服务端发送数据

在我们的上报客户端JS中,我们应该尽量少的去使用Ajax请求这些相对复杂的东西,而且也要考虑兼容性问题以及上报成功率。这个时候,我们可以考虑如下做法:

通过 navigator.sendBeacon 来进行上报,这是现在浏览器的新特新,能保持一定上报。所以,我们会优先使用它来进行上报。

那如果该特性并不可用的时候呢?发ajax请求么?不。我们可以采用构造图片请求的做法来实现:

var img = new Image();
img.src = reportUrl;

就这么简单么?也不是这么简单,我们还需要考虑这个请求是否可能发不出去(在遇到内存回收时,该变量由于没有被引用,会被回收掉,所以可能发不出去),为了提高成功率,我们应该按照如下做法实现:

const rndKey = `report_img_${makeRndString()}`;
  const img = window.WebMoniter[rndKey] = new Image();
  img.onload = img.onerror = function () {
    window.WebMoniter[rndKey] = null; // 手动清理
  }
  img.src = reportUrl;

通过构造一个随机数key,把引用放到window上,在发送完成(包括成功和失败)后,进行清理动作。

注意:该做法会有url长度限制,要尽量保证URL不至于太长。

Other

待续...