# 前端监控

# 1.场景和类型

# 主要场景

两个方面的需求,监察用户的使用情况,监察系统的运行状态。

# 用户使用情况

# pv、uv等运行数据

  • pv: 访问人次,一般每次刷新页面都会 + 1
  • uv: 访问人数,每人一天内只计数一次,一般小于等于pv
  • ip数:访问的ip数量
  • 跳出率:打开一个网页的概率/总的网页访问数
  • 平均访问时长:访问总时长 / 访问页数
  • 平均访问深度:在当前域名跳转的次数 / 访问次数
  • 会话数:用户发起的session的数量
  • 路由切换量(rpv):由于当前很多较复杂的网站都是采用spa结构,使用传统的pv,uv不能反映用户真实使用状况,所以这个指标就显得非常重要了,一般来说路由切换一次 rpv + 1,最终得到一个路由访问的次数

# 埋点,点击流

为了要记录用户在网站上的点击,拖动,跳转等行为,对页面上元素绑定的一些事件并上报记录,称作埋点点击流,是基于以上的埋点的记录,把一系列事件串起来,形成一个用户操作的链条。 通过点击流和埋点,可以分析用户的使用习惯,找到用户在网站使用上碰到的问题,帮助网站做的更好。比如,在点击购买链接前,如果多数都会点击对比商品的按钮,那么对比按钮的位置就需要得到凸显等等。

# 场景回放

基于埋点和点击流,我们可以做到对用户使用场景的回放和还原,比如用户点击了一些敏感操作按钮,可以帮助用户找到操作失误记录,再比如对于较难复现的bug,可以通过场景回放来重放用户的操作步骤,复现bug。

# 录屏

通过视频对用户操作进行还原,直观且强大

# 系统运行情况

# 错误感知

  • 控制台错误: runtime报出的错误,一般会打印在浏览器开发工具的控制台,这样
  • 网络错误: 一般包括 http 等与服务器交互产生的请求错误,比如 http response 返回值为4xx,5xx等错误
  • 业务系统自定义错误:一般是各系统自己定义的需要上报的业务错误,比如 http 返回 200,但其实接口返回错误码

# 耗时统计

  • 页面加载耗时:主要是收集由performace.timing对象提供计算出的各种时间实现的
  • 接口请求耗时:主要用于统计对后端接口的耗时情况

# 全链路状态感知

也称作端到端的全链路监控,基本会收集从请求从 web server 到 db 的全生命周期的状态,基本会记录整个请求在处理过程中各个环节的具体耗时等信息。

# 对应场景的监控类型

# 行为监控

  • 主要负责监控用户的使用情况,比如点击流,pv,uv等指标都属于此类。还有上面提到的场景回放和录屏也可以归到这一类上面。
  • 一般的展现形式都是图表,同时提供基于时间等维度的对比功能,能够比较直观的看出数据的变化和趋势对比。

# 异常监控

浏览器主动抛出的错误和接口错误的情况 很多异常监控也结合sourcemap来还原错误堆栈和现场,提供快速查找错误的能力。

# 链路监控

链路监控对应上面全链路感知的场景,一般的展示场景可以参考开发者工具中的timeline类似,可以直观的看出各阶段耗时情况。

# 2. 行为监控的技术实现

监控系统设计的总体思路上,最重要的是**“无痛”或者“无侵入”。 如何做到无痛**?主要方式是拦截和重写

# 用户使用场景各种实现

# 埋点,点击流

本质上就是对事件的拦截

# 场景回放,录屏

  • dom 背景 + 回放操作
  • html2canvas
  • chrome 插件方式
  • dom 上报重建

# 3. 异常监控的实现

# 总体思路

无侵入也是最值得思考的系统设计重点

# 全局异常

# 方式

  1. 全局异常是异常漏斗的最下一层,基本上用于捕获抛到window.onerror 事件里面捕获的异常
// 覆盖window.onerror函数及注意点
    window.onerror = function(message, source, lineno, colno, error) {
        // Script error 不需要上报,因为同源限制,上报了也没有意义
        if("Script error."=== messaage && !source) return false;
        // 这里要注意用setTimeout包装一下,防止报错太多,卡住主线程
        setTimeout(function(){
         // do something 上报
        })
    }
1
2
3
4
5
6
7
8
9
  1. 通过包装各类事件,来捕获事件异常,构造自己的异常捕获系统。来自于 sentry raven.js,可以参看 _instrumentTryCatch 函数。

# 问题

总的来说,通过全局sdk的方式,我们可以简单直接的获取一层托底异常。但是可能有几个问题:

  • 1、代码中有try{}catch(e){}类的异常不会抛到最外层,window.onerror无法捕获错误
  • 2、有些需要自定义的上报信息无法及时捕获

# 自定义异常上报

自定义异常上报,为了解决以上全局上报的问题, 一般来说,自定义上报都会提供如下信息:

  • 1、自动增加上报时间
  • 2、自动增加用户信息
  • 3、可配置增加错误信息
  • 4、用户上报的信息

# 异常分级

异常一般分为info,warn,error ;

  1. error类错误的处理方式,error类错误会实时上报后端,因为和监控系统联动的告警系统很需要这类实时数据,以便及时告警。
  2. 其他类型的错误,如果不是致命类异常错误,可能会用到离线(空闲)上报的策略,以减少消耗,提高性能。

# 实时上报

实时上报本质上就是系统的一个sendMessage的方式,一般来说,只要构造一个get请求就可以了。

// 使用image的方式send info
    function sendInfo(url) {
        var _image = new Image(1, 1);
        // 挂载到监控全局上,保证同时只有一个,减少消耗
        monitor.img=_image;
        // 发送完成后清除掉相关函数,离线上报需要改造一些
        _image.onload = _image.onerror = _image.onabort = function() {
            _image.onload = _image.onerror = _image.onabort = null;
            monitor.img = null;
        }
    }
1
2
3
4
5
6
7
8
9
10
11

本质上原理是提一个发后不理的get请求,但是由于浏览器的并发数量限制,如果上报触发太多的话,有可能会影响宿主系统的性能。为了解决这个问题,离线(空闲)上报方式就诞生了。

# 离线上报

# 解决两个问题:

  • 1、上文提到的宿主系统性能的问题
  • 2、补充一些失败的日志,这儿要在上文提到的上报部分做一些改造

# 思路:

对于非error类的需要实时收集的异常,可以采用本地存储的方式存储起来,寻机上传。至于寻机,可能是根据网络和系统的情况变化,比如从弱网情况恢复到良好网络情况,可以统一上传,这里注意上传时的节奏即可。这儿还会有一些退化重试的上传的时间间隔的算法。

总的来说,就是不必要实时上报、当前无法上报、上报失败的数据可以先存起来,择机上报。至于存在哪里,什么时候上报,是不是可以手动触发,看各个系统自己的实现了

# 4. 性能监控的实现

# 总体思路

性能监控的重点在于对各类环境的适配和监控的准确性,因为对系统性能的监控更多是一个面的监控,比如说对cgi接口的平均响应时间,如果由于部分获取时间的毛刺拉高导致数据不准就很麻烦。

# 性能监控的主要意义

  1. 改善用户体验 这方面,衍生出来的主要是客户端(小程序,H5,pc端页面)性能监控。改善体验的循环是:收集数据 -> 分析数据 -> 改代码 -> abtest -> 分析数据 -> 上线,性能监控是在收集数据阶段起作用,分析数据当前阶段,绝大部分是后台系统加体验者人肉的方式。
  2. 监控系统异常 这方面,主要谈的的cgi的性能监控,监控内容主要是各个cgi的响应时间。
    1. 帮助优化接口性能,如果普遍响应很慢,就需要做一些优化措施了
    2. 帮助发现不可用错误,如果接口响应时间长的超过阈值,那说明可能接口挂掉了,应该触发告警,让运维或者开发哥哥去查问题了。

# 主要指标

# 1. 系统获取

系统部分主要指浏览器提供的一系列高精度的网页性能指标,一般来说常规使用如下图解析 performance 对象 image.png

# 2. 监控系统定义

各监控系统会自定义一些采集指标,同时在前端的js-sdk里面进行一些采集和统计

  • 比如客户端维度的: cpu 使用率,fps监控,memory消耗等
  • 比如业务维度的:首屏加载时间,通常使用performance.timing中的domContentLoadedEventEnd - domContentLoadedEventStart 页面停留时间,一般用 unloadEventEnd - domContentLoadedEventEnd来统计。

# 3. 自定义获取

  • 为了满足不同业务的需要,监控系统一般都会给各业务代码提供灵活的自定义接口。
  • 上报是由前端代码根据一定规则解析后上报,也可以上报到后端来解析,看各监控系统的实现和约定

# 主要实现方式

  • performance对象 根据performance.timing和图的指引,减减减就完事了,可以产生出很多标准数据,是监控系统的标配。
  • 自定义模拟实现 举个例子:监控系统提供标准api,收集key和value用于上报和展示自定义指标。 产品要求,只有展示出来首页的最后一张图才算完全加载完成。前端会自己打点,使用 image.onload 记录结束时间点,然后减去记录的startTime得到首页展示时间,根据{key, value}的格式上报后在后端查看

# 性能测试工具

# 1. lighthouse

# 2. pageSpeed

老牌页面性能测试网站,听说底层是lighthouse,输入网址就能测试。

Last Updated: 10/29/2020, 1:21:25 AM