前端监控

293 阅读6分钟

线上提供前端监控的主流服务

image.png

目的

  1. 提升用户体验
  2. 更快发现异常,定位异常,解决异常
  3. 了解业务数据,知道产品升级---数据驱动的思想

采集

采集的信息包括:环境信息,性能信息,异常信息,业务信息

环境信息

  1. url:window.location.href
  2. ua:window.navigator.userAgent,包括操作系统,浏览器类型,版本
  3. token:记录当前用户是谁

性能信息

页面的性能直接影响了用户留存率,研究表明:如果一个一个移动端页面加载时长超过了3秒,用户就会放弃而离开,BBC发现网页加载时长每增加1秒,用户就会流失10%

以下为网络层面和页面展示层面的指标

  1. 网络层面
指标解释
重定向耗时重定向所耗费的时间
DNS解析耗时浏览器输入网址后首先会进行DNS解析,其可以对服务器是否工作作出反馈
TCP连接耗时只建立连接过程的耗时
SSL连接耗时指数据安全性,完整性建立耗时
TTFB网络请求耗时表示浏览器接受第一个字节的时间
数据传输耗时浏览器接受内容所耗费的时间
资源加载耗时DOM构建完毕后到页面加载完毕这段时间
  1. 页面展示层面指标
指标解释
FP(First Paint)首次绘制,标记浏览器渲染任何在视觉上不同于导航前屏幕内容之内容的时间点.
FCP(First Contentful Paint)首次内容绘制,标记浏览器渲染来自 DOM 第一位内容的时间点,该内容可能是文本、图像、SVG 甚至 元素.
LCP(Largest Contentful Paint)最大内容渲染,表示可视区“内容”最大的可见元素开始出现在屏幕上的时间点。
FMP(First Meaningful Paint)首次有效绘制,表示页面的“主要内容”开始出现在屏幕上的时间点。它是我们测量用户加载体验的主要指标。
DCL(DomContentLoaded)当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,无需等待样式表、图像和子框架的完成加载.
L(onLoad)当依赖的资源全部加载完毕之后才会触发
TTI(Time to Interactive)可交互时间,用于标记应用已进入视觉渲染并能可靠响应用户输入的时间点
FID(First Input Delay)首次输入延迟,用户首次和页面交互(单击链接、点击按钮等)到页面响应交互的时间

上述这么多指标改怎么获取呢?浏览器给我们留了相应的接口---window.performance,通过改接口可以获取一些与性能相关的参数

异常信息

对于网站来说,异常信息最致命,最影响用户体验的问题,需要重点监控。对于异常信息可以分为两类:运行时错误,接口错误。

  1. 运行时错误

可归类为7类:语法错误,类型错误,范围错误,引用错误,eval错误,URL错误,资源加载错误。为了捕获代码错误,需要考虑两类场景:非promise场景和promise场景,因为这两种场景捕获错误的策略不同。 (1)非Promise场景可通过监听error事件来捕获错误。对于error事件捕获的错误分为两类:资源错误和代码错误。资源错误指的就是js、css、img等未加载,该错误只能在捕获阶段获取到,且为资源错误时event.target.localName存在值(用此区分资源错误与代码错误);代码错误指的就是语法错误、类型错误等这一类错误,可以获取代码错误的信息、堆栈等,用于排查错误。

export function listenerError() {
    window.addEventListener('error', (event) => {
        if (event.target.localName) {
            console.log('这是资源错误', event);
        }
        else {
            console.log('这是代码错误', event);
        }
    }, true)
}

(2)promise场景

Promise场景的处理方式有所不同,当Promise被reject且没有reject处理器的时候,会触发unhandlerejection事件,所以通过监听unhandlerejection的事件来捕获错误。

export function listenerPromiseError() { 
window.addEventListener('unhandledrejection', (event) => { console.log('这是Promise场景中错误', event); 
}) }

  1. 接口错误

对于浏览器来说,所有的接口均是基于XHR和Fetch实现的,为了捕获接口中的错误,可以通过重写该方法,然后通过接口返回的信息来判断当前接口的状况,下面以XHR为例来展示封装过程。

function newXHR() {
    const XMLHttpRequest = window.XMLHttpRequest;
    const oldXHROpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = (method, url, async) => {
        // 做一些自己的数据上报操作
        return oldXHROpen.apply(this, arguments);
    }

    const oldXHRSend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = (body) => {
        // 做一些自己的数据上报操作
        return oldXHRSend.apply(this, arguments);
    }
}

业务信息

每个产品都会有自己的业务信息,例如用户在线时长、pv、uv、用户分布等,通过获取这些业务信息才能更加清楚的了解目前产品的状况,以便产品经理更好的去规划产品的未来方向。由于每个产品业务信息多种多样,小伙伴本可以按照自己的需求进行撰写代码

上报

对于上报的方式无外乎两种:一种是Ajax的方式上报;另一种是通过Image的形式进行上报。目前很多大厂采用的上报方式均是通过一个1*1像素的的gif图片进行上报,既然人家都采用该种策略,那我们就来唠一唠下面两个问题。

一. 为什么采用image的方式上报?

  1. 没有跨域问题,因为数据服务器和后端服务器大概率是不同的域名,若采用ajax的方式进行处理还要处理跨域问题,否则数据会被浏览器拦截
  2. 不会阻塞页面加载,只需要new Image对象就可以 二. 图片类型很多,为什么采用gif这种格式上报?

其实归结为一个字——小。对于1*1px的图片,BMP结构的文件需要74字节,PNG结构的文件需要67字节,GIF结构的文件只需要43字节。同样的响应,GIF可以比BMP节约41%的流量,比PNG节约35%的流量,所以选择gif进行上报。

分析

日志上报之后需要进行清洗,获取自己所需要内容,并将分析内容进行存储。根据数据量的大小可分为两种方式:单机和集群。

  1. 单机 访问量小,日志少的网站可以采用单机的方式对数据进行分析,例如,用node读取日志文件,然后通过日志文件中获取所需要的信息,最终将处理的信息存储到数据库中
  2. 集群 很多产品的访问量很大,日志很多,此时就需要利用hadoop进行分布式处理,获取最终处理结果

报警

当异常类型超多一定阈值之后需要进行报警通知,让对应的工作人员去处理问题,及时止损。根据报警的级别不同,可以选择不同的报警方式。

报警