字节前端监控实践

方式

  • 数据的采集(埋点与收集)

  • 数据上报与监控

JS 异常监控

// 同步
window.addEventListener("error", function (e) {
  console.log(e);
});
// 异步
window.addEventListener("unhandleRejection", function (e) {
  console.log(e);
});

对 sourceMap 的进行反编译

通过 issue Grouping 聚合提交

注意落地:

  1. 线上报错项目对应的源代码仓库元信息 2.线上报错代码的发生版本 3.线上报错版本的关联的起止信息

性能监控 性能指标

一. 指标采集: Web Vitals & Navigation Timings

二. 关联用户行为

1.采集交互事件,触发全局 action_id 记录 通过 addEventListen 记录下 2.Mutation Observer 观察 DOM,观察后续请求,静态资源加载,longtask 等数据 3.100ms 内若没有新的变更产生,则结算上报,若持续时长超过 10s,强制结算上报

三:单页面视角的性能度量

请求/静态资源监控

采集方案: 手动打点: 使用场景:请求耗时兜底、请求状态、请求响应相关信息 监控方式: hook XMLHttpRequest.prototype Hook fetch -> wrappedFetch 优势: 兼容性佳、采集方便 ResourceTiming: 使用场景:精确的请求耗时、静态资源耗时、分阶段观测数据 监控方式:performance.getEntriesByType('resource') PerformanceObserver.observe(type) 优势: 更精准,可以避开额外的事件队列处理耗时

SDK 设计

异步加载

js nipper 异步加载 运用了 async

预收集

事件驱动

1.按需加载,不使用的代码就不拉取 2.高扩展性,允许开发自己的采集逻辑 3.降低多端开发成本

异步加载

搭建一个前端监控系统需要几步

数据埋点:前端 sdk 埋点,精准捕获性能数据[性能监控 (包括页面加载耗时、接口耗时等各项数据统计)]和异常数据

事实上数据埋点分为三类:

  • 业务埋点,统计诸如 PV、UV、点击率、流失率、转化率等.

  • 大数据埋点,统计与用户行为相关信息,比如那个用户点击了那个商品,上报用户 ID 和商品 ID,方便后台分析用户和商品的关系,可以用做大数据分析,推荐算法来为用户推荐商品。

  • 工程埋点,统计工程上的数据信息,比如页面秒开率,DNS 时间等。

存储与分析:TB 级数据清洗,实时入库存储 前端可视化:前端数据可视化,提供数据分析图形和报表 实时报警:设置报警规则和报警阙值,及时通知开发者

前端采集: 性能 错误 点击 停留 用户行为

要想做线上监控,分两个部分:数据采集;数据展现。数据采集部分,同样需要发布平台或者开发工具来配合,对性能数据来说,Performance API 非常好用,它是浏览器记录的性能数据,一般来说,我们用统一的代码把它上传到服务器端就够用了。

数据的展现部分就比较自由了,可以用不同的数据可视化方案来展现性能数据,没有一定之规。一般的数据监控平台,会提供报警机制,对性能来说,报警需求不是特别强烈,但是也可以设置一些条件,针对秒开率特别低的网页报警。

如何检测到页面的白屏?

  1. 利用性能指标: 通过 PerformanceObserver 监听 paint 类型的性能条目,获取 First Paint(FP)和 First Contentful Paint(FCP)指标.

const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    if (entry.entryType === "paint") {
      console.log(`${entry.name}: ${entry.startTime}`);
    }
  });
});
observer.observe({ entryTypes: ["paint"] });

通过监测这些指标,可以判断页面是否存在白屏现象。

  1. DOM 变化检测: 通过 MutationObserver 监听 DOM 变化,判断页面是否存在白屏现象。

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === "childList") {
      console.log("DOM 变化");
      // 判断特定元素是否已渲染
    }
  });
});
observer.observe(document.body, { childList: true });
  1. 资源加载监控:监听关键资源(如 CSS、JS、图片)的加载状态,确保它们在页面渲染前已加载完成。

window.addEventListener("load", () => {
  // 检查关键资源加载状态
});

如何检测并上报页面的卡死?

页面卡死通常指主线程长时间被阻塞,导致页面无法响应用户操作。

  1. 使用 PerformanceObserver 监听 longtask 指标,检测页面是否存在长任务。

const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    if (entry.entryType === "longtask") {
      console.log(`Longtask: ${entry.duration}ms`);
    }
  });
});
observer.observe({ entryTypes: ["longtask"] });
  1. 使用 requestAnimationFrame 检测卡顿:通过 requestAnimationFrame 定期检查页面渲染帧率,判断是否存在卡顿。

let lastTime = 0;
function checkFrame() {
  const now = performance.now();
  const delta = now - lastTime;
  if (delta > 1000 / 60) {
    // 页面卡顿,执行上报
  }
  lastTime = now;
  requestAnimationFrame(checkFrame);
}
requestAnimationFrame(checkFrame);
  1. Web Worker 心跳检测:使用 Web Worker 定期向主线程发送心跳消息,检测主线程是否响应。

// 主线程
const worker = new Worker("worker.js");
worker.postMessage("start");
worker.onmessage = (event) => {
  if (event.data === "alive") {
    // 主线程正常
  } else {
    // 主线程卡死,执行上报
  }
};

// worker.js
let status = "alive";
setInterval(() => {
  if (status === "dead") {
    postMessage("dead");
  } else {
    postMessage("alive");
  }
  status = "dead";
  setTimeout(() => {
    if (status === "dead") {
      postMessage("dead");
    }
  }, 3000);
}, 6000);

如何优化首页渲染性能?

  1. 资源预加载:使用 提前加载关键资源,减少首屏加载时间。

<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style" />
<link rel="preconnect" href="https://cdn.example.com" />

<!-- 异步非关键JS -->
<script defer src="non-critical.js"></script>
  1. 代码拆分:利用 Webpack 等工具进行代码拆分,按需加载,减少初始加载的 JavaScript 体积。

  2. 懒加载:对非首屏内容使用懒加载,延迟加载不影响首屏渲染的资源。

  3. 服务端渲染(SSR):在服务器端渲染页面,减少客户端的渲染负担,加快首屏渲染速度。

最后更新于

这有帮助吗?