跳到主要内容

前端监控

参考地址 https://zhuanlan.zhihu.com/p/619084219

为什么要做前端监控

更快的发现问题和解决问题、做产品的决策依据、为业务扩展提供了更多可能性

如何做好前端监控方案?

  • 监控指标
    • 性能指标:FP、FCP、LCP、FID、CLS 等。
    • 错误监控:JS 错误、资源加载错误、接口错误。
    • 用户行为:PV、UV、点击路径、停留时长。
  • 实现方案
    • 使用开源工具:Sentry、LogRocket、Google Analytics。
    • 自定义监控:通过 PerformanceObserverError 事件等采集数据。
    • 数据上报:使用 navigator.sendBeaconXMLHttpRequest 上报数据。

前端监控目标

稳定性 stability

  • js错误:js执行错误、promise异常
  • 资源错误:js、css资源加载异常
  • 接口错误:ajax、fetch请求接口异常
  • 白屏:页面空白

用户体验

  • pv:页面浏览量和点击量
  • uv:访问某个站点的不同ip的人数
  • 用户在每一个页面的停留时间

前端监控流程

  • 前端埋点
  • 数据上报
  • 加工汇总
  • 可视化展示
  • 监控报警

常见的埋点方案

代码埋点

嵌入代码的形式

优点:精确(任意时刻,数据量全面)

缺点:代码工作量点大

可视化埋点

用系统来代替手工插入埋点代码

无痕埋点

采集全量数据,不会出现漏埋和误埋等现象

缺点是给数据传输和服务器增加压力,也无法灵活定制数据结构

编写采集脚本

  1. 接入日志系统

  2. 监控错误: 错误分为js错误(js执行错误,promise异常)、资源加载错误

  3. 数据结构分析

    1. jsError

      {
      "title": "前端监控系统", // 页面标题
      "url": "http://localhost:8080/", // 页面URL
      "timestamp": "1590815288710", // 访问时间戳
      "userAgent": "Chrome", // 用户浏览器类型
      "kind": "stability", // 大类
      "type": "error", // 小类
      "errorType": "jsError", // 错误类型
      "message": "Uncaught TypeError: Cannot set property 'error' of undefined", // 类型详情
      "filename": "http://localhost:8080/", // 访问的文件名
      "position": "0:0", // 行列信息
      "stack": "btnClick (http://localhost:8080/:20:39)^HTMLInputElement.onclick (http://localhost:8080/:14:72)", // 堆栈信息
      "selector": "HTML BODY #container .content INPUT" // 选择器
      }
    2. promiseError

      {
      ...
      "errorType": "promiseError",//错误类型
      "message": "someVar is not defined",//类型详情
      "stack": "http://localhost:8080/:24:29^new Promise (<anonymous>)^btnPromiseClick (http://localhost:8080/:23:13)^HTMLInputElement.onclick (http://localhost:8080/:15:86)",//堆栈信息
      "selector": "HTML BODY #container .content INPUT"//选择器
      }
    3. ResourceEror

      {
      ...
      "errorType": "resourceError",//错误类型
      "filename": "http://localhost:8080/error.js",//访问的文件名
      "tagName": "SCRIPT",//标签名
      "timeStamp": "76",//时间
      }
  4. 监听拦截实现 window.addEventListener监听,然后根据type做一些处理

    1. 资源加载和js错误 -> error,
    2. promise -> unhandledrejection
  5. 异常采集脚本

    1. 异常数据结构设计

    2. 实现

      1. 使用webpack devServer模拟请求
      2. 重写xhr的open、send方法
      3. 监听load、error、abort事件
    3. 白屏数据结构设计,做一些性能指标计算,

      {
      "title": "前端监控系统",
      "url": "http://localhost:8080/",
      "timestamp": "1590822618759",
      "userAgent": "chrome",
      "kind": "stability", //大类
      "type": "blank", //小类
      "emptyPoints": "0", //空白点
      "screen": "2049x1152", //分辨率
      "viewPoint": "2048x994", //视口
      "selector": "HTML BODY #container" //选择器 elementsFromPoint api,获取屏幕水平中线和竖直中线所在的元素
      }
    4. 阶段计算

      {
      ...
      "connectTime": "0",
      "ttfbTime": "1",
      "responseTime": "1",
      "parseDOMTime": "80",
      "domContentLoadedTime": "0",
      "timeToInteractive": "88",
      "loadTime": "89"
      }

性能指标

以下是一些常见的前端性能指标及其计算方法:

  1. First Contentful Paint (FCP):首次内容绘制时间

    • 计算方法:浏览器会在内容首次绘制到屏幕时记录时间戳。
  2. Speed Index:速度指数

    • 衡量页面内容可视化的速度。
    • 计算方法:通过分析页面加载过程中的视频捕获,计算页面内容达到一定可视完成度所需的时间。
  3. Time to Interactive (TTI):可交互时间

    • 衡量页面达到可稳定交互状态的时间。
    • 计算方法:浏览器会在页面的主要内容加载完成并且主线程空闲一段时间后记录时间戳。
  4. First Input Delay (FID):首次输入延迟

    • 衡量用户首次与页面交互(如点击链接、按钮)时的响应延迟。
    • 计算方法:通过记录用户首次交互的时间戳和浏览器处理该交互的时间戳之间的差值。
  5. Total Blocking Time (TBT):总阻塞时间

    • 计算方法:从FCP到TTI之间,主线程被阻塞超过50ms的时间总和。
  6. Largest Contentful Paint (LCP):最大内容绘制时间

    • 计算方法:浏览器会在最大的可见内容元素加载完成时记录时间戳。
  7. Cumulative Layout Shift (CLS):累积布局偏移

    • 衡量页面在加载过程中发生的意外布局偏移的程度。
    • 计算方法:通过计算页面加载过程中所有意外布局偏移的总和。
  8. Resource Timing:资源加载时间

    • 计算方法:通过浏览器提供的Resource Timing API,可以获取到每个资源的加载时间。
  9. Server Response Time:服务器响应时间

    • 计算方法:通过记录请求发送到服务器的时间戳和服务器开始发送响应的时间戳之间的差值。
  10. HTTP Requests:HTTP请求次数

  • 计算方法:通过浏览器的开发者工具网络面板统计发起的请求次数。

利用window.performance API,可以获取到页面加载过程中的详细性能数据,如performance.now()可以用来计算时间间隔,performance.getEntriesByType('resource')可以获取资源加载时间等

PerformanceObserver API允许你监听浏览器性能事件,如资源加载、标记点等。通过注册一个PerformanceObserver,可以捕获到如largest-contentful-paintfirst-input-delay

在前端开发中,如何获取浏览器的唯⼀标识

  • 使用浏览器指纹库fingerprintjs2

    const fpPromise = Fingerprint2.get({ extraPlugins: true });

    fpPromise.then(output => {
    console.log(output);
    });
  • canvas指纹(会被限制)

    //它通过绘制一个 Canvas 元素并读取其像素数据来创建一个指纹。
    /由于不同的浏览器和设备在渲染 Canvas 时可能会产生不同的结果,因此可以用来作为浏览器指纹的一部分。
    function getCanvasFingerprint() {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    context.font = '14px Arial';
    context.fillText('Hello, world!', 2, 10);
    return canvas.toDataURL();
    }

如何获取当前系统中的在线⽤⼾数 (并发⽤⼾数)

  • 会话跟踪:服务器可以统计当前活跃的会话数量来估算在线用户数。
  • 数据库记录:在用户登录时,可以在数据库中创建一条记录,表示用户已登录
  • 实时通信
  • 应用日志分析: 统计在特定时间段内用户登录和登出的次数
  • 第三方服务: google analytics

在浏览器中如何监听剪切板中内容

可以通过监听 cutcopypaste 事件来实现。这些事件分别在剪切、复制和粘贴操作发生时触发。

// e.clipboardData || window.clipboardData;

在服务端应⽤中如何获得客⼾端 IP

X-Forwarded-For,通常由代理服务器(如负载均衡器、反向代理等)添加,用于记录原始请求的客户端 IP 地址

//const clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

req.connection.remoteAddress req.socket.remoteAddress 字段通常表示直接连接到服务器的客户端 IP 地址

什么是前端可用性?

从用户的角度出发,检测整个系统的可用性,

页面功能和交互复杂度增加 前端功能测试局限性 各种前端渲染框架的引入 运营线上问题反馈

前端可用性评估指标

关键指标白屏时间6s

可用性系统要求:实时性, 全面性

数据采集:请求异常、资源异常、渲染异常、交互异常。

请求状态吗异常,请求超时,返回数据格式错误。(AJAX监控)

资源加载失败(CDN监控)

渲染异常(DOM检查)

交互异常(JS错误监控)

监控预警:实时监控、阈值报警。

海量数据存储读取、可视化数据展现、多维度数据查询。

设定合理阈值、邮件短信报警

兜底容灾:容错机制、快速降级。

异步渲染机制出错跳转同步页、友好的错误用户提示。

重要机制添加降级开关、迅速(3min内)完成降级

页面性能检测方法,结合一个实际页面?

可以使用 Performance APILighthouse 来检测页面性能。

const perfData = window.performance.timing;
console.log('Page load time:', perfData.loadEventEnd - perfData.navigationStart);

看你性能优化做的多,谈一谈。从指标、采集、方案,讲了 10min

性能优化可以从以下几个方面入手:

  • 指标:FCP、LCP、TTI、TBT、CLS 等。
  • 采集:使用 PerformanceObserverweb-vitals 等工具采集性能数据。
  • 方案:代码分割、懒加载、缓存策略、CDN 加速等。

LCP 怎么采集? 一般 MutationObserver、PerformanceObserver、web-vitals

可以使用 web-vitals 库来采集 LCP。

import { getLCP } from 'web-vitals';

getLCP(console.log);

navigator.sendBeacon 是一个用于异步地向服务器发送数据的 Web API,主要用于在页面卸载时(例如,用户关闭标签页或导航到新页面)发送小量数据。这个方法的设计目的是为了解决传统的 AJAX 请求在页面卸载时可能造成的请求丢失问题。

主要特点

  1. 非阻塞请求sendBeacon 方法不会阻塞页面的卸载过程,允许浏览器在页面关闭时仍然能够成功发送数据。
  2. 支持的数据格式sendBeacon 可以发送简单的文本数据(如字符串)或 Blob,但通常用于发送 JSON 数据或表单数据。
  3. 适合的用途
    • 发送分析数据(如页面浏览、事件跟踪)。
    • 收集用户行为数据。
    • 发送日志或错误报告。

上报方式? ajax、img、navigator.sendbeacon

可以使用 navigator.sendBeacon 来上报数据。

navigator.sendBeacon('/log', JSON.stringify({ event: 'page_view' }));

性能指标 FCP 理想状态和影响因素

FCP(首次内容绘制)的理想状态应在 1 秒内。影响因素包括:

  • 资源加载时间
  • 服务器响应时间
  • 浏览器解析和渲染时间

性能指标好和坏的标准

性能指标的标准通常以用户体验为基础,理想的响应时间越短越好。

服务器反应时间对 FCP 和 SI 的影响

用户体验:较长的服务器响应时间会导致 FCP 和 SI 延迟,从而影响用户的初始体验。用户在访问网站时,看到内容的时间越长,满意度和留存率可能会下降。

SEO 影响:搜索引擎越来越重视页面加载性能,较慢的 FCP 和 SI 可能影响搜索排名。

优化建议

  • 服务器优化:提高服务器响应速度,使用缓存、CDN 等技术减少延迟。
  • 资源优化:优化静态资源,使用懒加载、压缩等手段加快内容加载。
  • 监控与分析:使用性能监控工具,定期分析服务器响应时间和用户体验指标。

首屏加载时间监控

可以使用性能监控工具(如 Lighthouse、New Relic)来监控首屏加载时间,并在超过阈值时触发告警。

Performance => navigationTiming.loadEventEnd - navigationTiming.navigationStart