searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

web前端稳定性指标统计方案

2024-07-15 09:44:34
63
0

一、稳定性指标

js错误:js执行错误、promise异常。

资源错误:js、css、图片等资源加载异常。

白屏:页面加载完成后超过一定时间,页面仍然是空白

 

二、上报数据结构

1. 基础数据:用来记录错误发生时用户环境

参数名

参数描述

userAgent

记录用户UA信息

platform

用户操作系统平台,iPhone、iPad、Android、Windows、Mac

browser

用户浏览器,IE、Safari、Chrome、Firefox、UCBrowser、Edge、Opera、360、QQBrowswe

url

页面链接信息

screen

屏幕信息,结构:window.screen.width*window.screen.height

system

dev(开发平台)、ops(运营后台) 

userId

用户ID(后端自动记录)

createTime

上报时间(后端自动记录)

 

 

2. 错误数据:用来记录具体的错误信息

2.1 基础错误字段

参数名

参数描述

type

错误类型,jsError、resError、blankError

 

2.2 js错误字段

参数名

参数描述

subType

子类型,jsError有两种子类型 jsError、vueError、promiseError

message

错误消息

stack

错误堆栈

position

行列信息,结构: lineno:colno

 

2.3 资源加载错误字段

参数名

参数描述

tagName

标签名,如IMG

resUrl

资源链接

 

3. 上报示例

3.1 jsError:js执行错误

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "jsError",
	"subType": "jsError",
	"message": "Uncaught ReferenceError: myFunc is not defined",
	"stack": "ReferenceError: myFunc is not defined\ n at eval(webpack - internal: ///./src/main.ts:78:3)\n    at sentryWrapped (webpack-internal:///./node_modules/@sentry/browser/esm/helpers.js:99:17)",
	"position": "121:7"
}

3.2 jsError:promise错误

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "jsError",
	"subType": "promiseError",
	"message": "Promise wrong!",
	"stack": "Error: Promise wrong!\n    at eval (webpack-internal:///./src/main.ts:80:12)\n    at sentryWrapped (webpack-internal:///./node_modules/@sentry/browser/esm/helpers.js:99:17)"
}

3.3 resError:资源加载错误

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "resError",
	"tagName": "IMG",
	"resUrl": "https://local.qq.com:8080/res/1.png"
}

 3.4 blankError:白屏上报

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "blankError"
}

三、指标采集

1. js执行错误和资源加载错误采集

window.addEventListener(
  'error',
  function (event) {
    console.log('error')
    console.log(event)
    if (event.target && (event.target.src || event.target.href)) {
      console.log(
        `Loading failure for ${event.target.tagName} with source ${event.target.src || event.target.href}`
      )
    } else {
      console.log('JavaScript 运行时错误:', { message: event.message, stack: event.error.stack })
    }
  },
  true
)

2.  vue组件内错误采集

vue组件内部的js错误不会被error事件捕获

Vue.config.errorHandler = function (err, vm, info) {
  console.log('Vue jsError :', { message: err.message, stack: err.stack })
}

3.  promise异常采集

window.addEventListener('unhandledrejection', function (event) {
  console.log('Unhandled rejection :', { message: event.reason.message, stack: event.reason.stack })
})

 

4. 白屏数据采集

4.1白屏判定:根节点检测方案

通过检测根节点是否有dom确定是否是白屏,特点:适用SPA应用,通用性差。

function checkWhiteScreen() {
  const rootNode = document.querySelector('#app')
  if (rootNode.children.length === 0) {
    return true
  } else {
    return false
  }
}

4.2 白屏判定:elementsFromPoint采样检测方案

下面是采用垂线采样,屏幕中采样点如果都是白屏那么就是白屏状态。特点:通用性强,代码复杂,需要消耗更多前端计算资源。因为我们是SPA应用,所以我们选择根节点检测方案即可。

function checkWhiteScreen() {
  // 定义外层容器元素的集合
  const containerElements = ['html', 'body', '#app', '#root']
  // 容器元素个数
  let emptyPoints = 0
  // 选中dom的名称
  function getSelector(element) {
    if (element.id) {
      return '#' + element.id
    } else if (element.className) {
      // div home => div.home
      return (
        '.' +
        element.className
          .split(' ')
          .filter(item => !!item)
          .join('.')
      )
    } else {
      return element.nodeName.toLowerCase()
    }
  }
  // 是否为容器节点
  function isContainer(element) {
    const selector = getSelector(element)
    if (containerElements.indexOf(selector) != -1) {
      emptyPoints++
    }
  }
  // 页面加载完毕初始化
  for (let i = 1; i <= 9; i++) {
    const xElements = document.elementsFromPoint((window.innerWidth * i) / 10, window.innerHeight / 2)
    const yElements = document.elementsFromPoint(window.innerWidth / 2, (window.innerHeight * i) / 10)
    isContainer(xElements[0])
    // 中心点只计算一次
    if (i != 5) {
      isContainer(yElements[0])
    }
  }
  // 17个点都是容器节点算作白屏
  if (emptyPoints == 17) {
    return true
  }
  return false
}

4.3 检测时机:轮询超时检测方案

定义:

T0:页面onload

T1:页面白屏检测间隔

T2:页面超时判定白屏的时间

 这里先暂时将T1设置3s,T2设置6s

方法:

当页面onload后,每隔T1检测用户是否白屏,如果不是白屏停止检测,如果是白屏继续按照T1间隔继续检测,当检测的总时间大于T2判定为白屏。

// 页面加载完毕
function onload(callback) {
  if (document.readyState === 'complete') {
    callback()
  } else {
    window.addEventListener('load', callback)
  }
}

// 定义T1和T2
const T1 = 3000; // 3秒检测间隔
const T2 = 6000; // 6秒超时判定

// 白屏检测逻辑
function startWhiteScreenDetection() {
  let totalTime = 0;
  const intervalId = setInterval(() => {
    totalTime += T1;
    const isWhiteScreen = checkWhiteScreen();
    if (!isWhiteScreen) {
      console.log('Page loaded successfully, stopping detection');
      clearInterval(intervalId); // 停止检测
    } else if (totalTime >= T2) {
      console.warn('White screen detected');
      // 上报白屏问题到你的监控服务
      // sendToAnalytics({ issue: 'white-screen' });
      clearInterval(intervalId); // 停止检测
    }
  }, T1);
}

// 页面加载完毕后开始白屏检测
onload(startWhiteScreenDetection);
0条评论
作者已关闭评论
牛****恒
1文章数
0粉丝数
牛****恒
1 文章 | 0 粉丝
牛****恒
1文章数
0粉丝数
牛****恒
1 文章 | 0 粉丝
原创

web前端稳定性指标统计方案

2024-07-15 09:44:34
63
0

一、稳定性指标

js错误:js执行错误、promise异常。

资源错误:js、css、图片等资源加载异常。

白屏:页面加载完成后超过一定时间,页面仍然是空白

 

二、上报数据结构

1. 基础数据:用来记录错误发生时用户环境

参数名

参数描述

userAgent

记录用户UA信息

platform

用户操作系统平台,iPhone、iPad、Android、Windows、Mac

browser

用户浏览器,IE、Safari、Chrome、Firefox、UCBrowser、Edge、Opera、360、QQBrowswe

url

页面链接信息

screen

屏幕信息,结构:window.screen.width*window.screen.height

system

dev(开发平台)、ops(运营后台) 

userId

用户ID(后端自动记录)

createTime

上报时间(后端自动记录)

 

 

2. 错误数据:用来记录具体的错误信息

2.1 基础错误字段

参数名

参数描述

type

错误类型,jsError、resError、blankError

 

2.2 js错误字段

参数名

参数描述

subType

子类型,jsError有两种子类型 jsError、vueError、promiseError

message

错误消息

stack

错误堆栈

position

行列信息,结构: lineno:colno

 

2.3 资源加载错误字段

参数名

参数描述

tagName

标签名,如IMG

resUrl

资源链接

 

3. 上报示例

3.1 jsError:js执行错误

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "jsError",
	"subType": "jsError",
	"message": "Uncaught ReferenceError: myFunc is not defined",
	"stack": "ReferenceError: myFunc is not defined\ n at eval(webpack - internal: ///./src/main.ts:78:3)\n    at sentryWrapped (webpack-internal:///./node_modules/@sentry/browser/esm/helpers.js:99:17)",
	"position": "121:7"
}

3.2 jsError:promise错误

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "jsError",
	"subType": "promiseError",
	"message": "Promise wrong!",
	"stack": "Error: Promise wrong!\n    at eval (webpack-internal:///./src/main.ts:80:12)\n    at sentryWrapped (webpack-internal:///./node_modules/@sentry/browser/esm/helpers.js:99:17)"
}

3.3 resError:资源加载错误

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "resError",
	"tagName": "IMG",
	"resUrl": "https://local.qq.com:8080/res/1.png"
}

 3.4 blankError:白屏上报

{
	"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "platform":"Mac",
    "browser":"Chrome",
	"url": "https://local.qq.com:8080/api",
	"screen": "1728*1117",
	"system": "ops",
	"type": "blankError"
}

三、指标采集

1. js执行错误和资源加载错误采集

window.addEventListener(
  'error',
  function (event) {
    console.log('error')
    console.log(event)
    if (event.target && (event.target.src || event.target.href)) {
      console.log(
        `Loading failure for ${event.target.tagName} with source ${event.target.src || event.target.href}`
      )
    } else {
      console.log('JavaScript 运行时错误:', { message: event.message, stack: event.error.stack })
    }
  },
  true
)

2.  vue组件内错误采集

vue组件内部的js错误不会被error事件捕获

Vue.config.errorHandler = function (err, vm, info) {
  console.log('Vue jsError :', { message: err.message, stack: err.stack })
}

3.  promise异常采集

window.addEventListener('unhandledrejection', function (event) {
  console.log('Unhandled rejection :', { message: event.reason.message, stack: event.reason.stack })
})

 

4. 白屏数据采集

4.1白屏判定:根节点检测方案

通过检测根节点是否有dom确定是否是白屏,特点:适用SPA应用,通用性差。

function checkWhiteScreen() {
  const rootNode = document.querySelector('#app')
  if (rootNode.children.length === 0) {
    return true
  } else {
    return false
  }
}

4.2 白屏判定:elementsFromPoint采样检测方案

下面是采用垂线采样,屏幕中采样点如果都是白屏那么就是白屏状态。特点:通用性强,代码复杂,需要消耗更多前端计算资源。因为我们是SPA应用,所以我们选择根节点检测方案即可。

function checkWhiteScreen() {
  // 定义外层容器元素的集合
  const containerElements = ['html', 'body', '#app', '#root']
  // 容器元素个数
  let emptyPoints = 0
  // 选中dom的名称
  function getSelector(element) {
    if (element.id) {
      return '#' + element.id
    } else if (element.className) {
      // div home => div.home
      return (
        '.' +
        element.className
          .split(' ')
          .filter(item => !!item)
          .join('.')
      )
    } else {
      return element.nodeName.toLowerCase()
    }
  }
  // 是否为容器节点
  function isContainer(element) {
    const selector = getSelector(element)
    if (containerElements.indexOf(selector) != -1) {
      emptyPoints++
    }
  }
  // 页面加载完毕初始化
  for (let i = 1; i <= 9; i++) {
    const xElements = document.elementsFromPoint((window.innerWidth * i) / 10, window.innerHeight / 2)
    const yElements = document.elementsFromPoint(window.innerWidth / 2, (window.innerHeight * i) / 10)
    isContainer(xElements[0])
    // 中心点只计算一次
    if (i != 5) {
      isContainer(yElements[0])
    }
  }
  // 17个点都是容器节点算作白屏
  if (emptyPoints == 17) {
    return true
  }
  return false
}

4.3 检测时机:轮询超时检测方案

定义:

T0:页面onload

T1:页面白屏检测间隔

T2:页面超时判定白屏的时间

 这里先暂时将T1设置3s,T2设置6s

方法:

当页面onload后,每隔T1检测用户是否白屏,如果不是白屏停止检测,如果是白屏继续按照T1间隔继续检测,当检测的总时间大于T2判定为白屏。

// 页面加载完毕
function onload(callback) {
  if (document.readyState === 'complete') {
    callback()
  } else {
    window.addEventListener('load', callback)
  }
}

// 定义T1和T2
const T1 = 3000; // 3秒检测间隔
const T2 = 6000; // 6秒超时判定

// 白屏检测逻辑
function startWhiteScreenDetection() {
  let totalTime = 0;
  const intervalId = setInterval(() => {
    totalTime += T1;
    const isWhiteScreen = checkWhiteScreen();
    if (!isWhiteScreen) {
      console.log('Page loaded successfully, stopping detection');
      clearInterval(intervalId); // 停止检测
    } else if (totalTime >= T2) {
      console.warn('White screen detected');
      // 上报白屏问题到你的监控服务
      // sendToAnalytics({ issue: 'white-screen' });
      clearInterval(intervalId); // 停止检测
    }
  }, T1);
}

// 页面加载完毕后开始白屏检测
onload(startWhiteScreenDetection);
文章来自个人专栏
前端知识
1 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0