# 前端监控

# 监控方法论

MetricsTracingLogging

  • Metrics监控的基础,指标是一段时间内累计的计数或度量
  • Tracing面向的是请求,可以分析出请求及链路中异常点
  • Logging展现的是应用运行而产生的事件,可以详细解释系统的运行状态

# 前端监控内容

页面加载时:

  1. 页面加载数据
  2. 资源加载数据
  3. 接口请求数据

页面运行时:

  1. 用户行为数据
  2. 运行环境数据
  3. 程序异常数据
  4. 接口请求数据
  5. 自定义数据

# 前端监控架构

数据采集阶段:

  • 性能数据(如地图fps)
  • 异常数据
  • 行为数据等等

TIP

行为数据

  • 页面跳转:哈希路由,监听hash change;非哈希路由patch pushState/replaceState
  • 元素曝光:getBoundingClientRect()/IntersectionObserver
  • 元素点击:window.addEventListener('click', (e) => {})

异常数据

  • 运行时异常:
  1. window.onerror = function(message,source,lineno,colno,error){...}
  2. window.addEventListener('unhandlerejection', function(event){...})
  3. script设置crossorigin="anonymous" 响应头 Access-Control-Allow-Origin: *
  4. 前端框架封装,Vue errorHandler
  • 资源加载异常:
  1. window.addEventListener('error', function(event){...}, true)
  2. 过滤运行时异常,避免重复上报

接口数据/基础数据

  • 接口数据:
  1. patch fetch/XMLHttpRequest
  2. 获取http errornetwork fail
  3. 提供hook业务逻辑异常
  4. 获取接口调用耗化
  • 基础数据:
  1. User-Agent
  2. IP
  3. patch console.log

性能数据

  • 页面加载性能
  1. NavigationTiming
  2. 区间耗时
  3. 加载瀑布图
  • 资源加载性能
  1. ResourceTiming
  2. 全量资源请求数据
  • 页面运行性能
  1. 帧率
  2. Long Task Observer
  • 以用户为中心的指标
  1. 首次渲染FP/首次内容渲染FCP
  2. 首次有意义渲染FMP
  3. 可交互时间TTI
  4. 长任务统计 Long Task

数据处理阶段:

  • 数据接入
  • 实时处理
  • 数据服务
  • 离线处理

数据应用阶段:

  • 监控告警
  • 可视化分析

# 异常分析与监控

异常监控:

  • PV波动
  • 资源加载失败率
  • 接口失败率
  • JS错误率

快速定位:

  • JS异常现场还原:定位源码source-map,播放录屏rrweb,记录用户行为

TIP

  1. 堆栈信息和sourcemap可以快读定位程序异常
  2. 客户端采集,内存保持最近N条行为数据,异常发生时合并上报。服务端重建,根据异常发生时会话ID,从行为数据中查询并关联。解决特定用户问题
  3. 像素级用户行为回放:LogRocket

前端录屏确实是件很酷的事情,但是不能走极端,如果把用户的所有操作都录制下来,是没有意义的。我们更关注的是,页面报错的时候用户做了哪些操作,所以监控平台只把报错前 10s 的视频保存下来 通过 定位源码 + 播放录屏 这套组合,还原错误应该够用了,同时监控平台也提供了记录用户行为这种方式。假如用户做了很多操作,操作的间隔超过了单次录屏时长,录制的视频可能是不完整的,此时可以借助用户行为来分析用户的操作,帮助复现 bug。

异常分析:

  • TopN 异常类型
  • 异常页面
  • 失败资源
  • 失败接口

明确信息:

  • JS异常堆栈信息
  • 资源异常信息
  • 接口异常信息
  • 公共维度信息

# 告警策略

  • 绝对值告警
  • 波动告警
  • 累计值告警

# 总结

异常分析 按照 5W1H 法则来分析前端异常,需要知道以下信息

What,发⽣了什么错误:JS 错误、异步错误、资源加载、接口错误等 When,出现的时间段,如时间戳 Who,影响了多少用户,包括报错事件数、IP Where,出现的页面是哪些,包括页面、对应的设备信息 Why,错误的原因是为什么,包括错误堆栈、⾏列、SourceMap、异常录屏 How,如何定位还原问题,如何异常报警,避免类似的错误发生

前端监控系统是指通过监控前端应用的运行情况,及时发现并解决潜在的问题,提升应用的稳定性和性能。设计前端监控系统需要考虑以下几个方面:

  1. 监控数据采集

前端监控系统需要采集应用的各项数据指标,包括用户行为、性能指标、错误日志等,可通过添加统计代码和错误捕获来实现。

TIP

前端监控系统的数据采集阶段是整个系统中至关重要的一个环节,它可以帮助我们快速发现应用的问题,并且进一步优化应用的性能。下面是一些常用的前端监控数据采集方式:

  • 前端埋点 前端埋点是指在页面中嵌入一段代码,通过监听用户行为和浏览器性能等指标来进行数据采集。常用的前端埋点方式有手动埋点和自动埋点两种。手动埋点需要开发者手动编写埋点代码,而自动埋点可以通过使用第三方埋点工具来自动完成埋点操作。

手动埋点一般实现流程:

  1. 在需要采集数据的元素上添加事件监听器,比如点击事件、鼠标移动事件等。
  2. 在事件监听器内部,编写采集数据的代码逻辑,将需要采集的数据传递到后台或者存储在本地。
  3. 如果需要进行大量的手动埋点操作,可以考虑将采集数据的代码逻辑封装成一个独立的模块,方便代码的维护和管理。

自动埋点(无埋点)的一般实现流程如下:

  1. 安装并引入自动埋点库,在应用启动时初始化自动埋点库。
  2. 在自动埋点库中注册需要采集数据的元素或事件,比如页面跳转、按钮点击、滚动等等。
  3. 当注册的元素或事件被触发时,自动埋点库会自动采集数据,并将数据发送到后台或者存储在本地。
// 手动埋点
// 获取按钮元素
const btn = document.getElementById('btn')

// 在按钮上添加点击事件监听器
btn.addEventListener('click', () => {
  // 编写采集数据的代码逻辑
  const data = {
    type: 'button click',
    time: Date.now()
  }

  // 将采集的数据传递到后台或者存储在本地
  sendData(data)
})

// 自动埋点
// 引入 popular 自动埋点库
import Popular from 'popular'

// 初始化自动埋点库
const popular = new Popular({
  // 配置数据上报地址等信息
  url: 'https://example.com/api/popular',
  // 配置需要采集的元素或事件
  events: ['click', 'scroll', 'pageview']
})

// 应用启动时初始化自动埋点库
popular.init()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  • 错误捕获 错误捕获是指通过监听 JavaScript 运行时错误、资源加载错误等异常情况来进行数据采集。常用的错误捕获方式有 try-catch 捕获、window.onerror 捕获和通过第三方错误监控工具来实现。

  • 性能指标采集 性能指标采集是指通过浏览器提供的 performance API 或者自定义代码来获取页面加载速度、资源加载时间等指标。常用的性能指标采集方式有自定义代码和第三方性能监控工具。

  • 服务端日志采集 服务端日志采集是指通过监听服务端日志来获取应用在服务端运行的情况。常用的服务端日志采集方式有使用系统日志模块进行记录和使用第三方日志分析工具。

  1. 数据存储和处理

采集到的数据需要进行存储和处理,通常使用数据库来存储数据,并使用后端程序进行数据处理和计算。

  1. 监控数据展示

将采集到的数据进行分析和处理后,需要通过监控数据展示模块进行展示和呈现。这个模块可以是一个前端页面,也可以是后端程序通过 API 接口提供给前端展示。

  1. 告警机制

监控系统需要设置告警机制,及时发现并解决潜在问题。例如,当错误率超过设定阈值时,发送邮件或短信通知负责人进行处理。

  1. 性能优化

监控系统需要考虑性能问题,例如如何减少采集数据对应用性能的影响,如何优化数据处理等。

  1. 安全性

监控系统需要考虑安全问题,例如如何保护用户隐私,如何防范恶意攻击等。

# 技术难点

可能整个系统比较复杂的就是如何高效合理的进行监控数据上传。除了异常报错信息本身,还需要记录用户操作日志,如果任何日志都立即上报,这无异于自造的 DDOS 攻击。那就需要考虑前端日志的存储,日志如何上传,上传前如何整理日志等问题。

前端在收集的过程中可能会影响用户体验。 后端对于收到的日志要使用合适的工具进行收集,数据量大时选择如何取舍。

可能会采取的方案:

  • indexDB 存储日志,因为容量大、异步!不用考虑阻塞页面问题。
  • 在一个 webworker 中对日志进行整理,比如对每一条日志打上标签,进行分类等操作。
  • 上报日志也在 webworker 中进行,可以按照重要紧急度区分,判断是否延时或者立即上报。