当前位置: 首页 > news >正文

前端业务监控系统,异常上报业务,异常队列收集,异常捕获

前端在开发业务监控系统,特别时一些指标类业务系统时,常常需要配合进行异常收集上报工作。
大致工作分为
1. 异常捕获
2. 异常队列收集
3. 异常队列边界
4. 上报时机

一:异常捕获

这里需要关注具体的业务重点,我们不做具体举例,这里只用常见的几种类型收集来做说明
1、 业务系统界面卡顿
前端常常会遇到使用过程中业务系统卡顿情况,这里需要使用PerformanceObserver 进行性能监控

if (typeof window !== 'undefined' && 'PerformanceObserver' in window) {try {const observer = new window.PerformanceObserver((list) => {list.getEntries().forEach(entry => {collectError({type: 'longTask',name: entry.name,startTime: entry.startTime,duration: entry.duration,detail: entry});});});observer.observe({ entryTypes: ['longtask'] });} catch (e) {}
}

2.业务系统界面崩溃

// 2. 页面挂了/业务代码报错(全局异常)
if (typeof window !== 'undefined') {window.addEventListener('error', function (event: any) {collectError({type: 'jsError',msg: event.message,url: event.filename,line: event.lineno,col: event.colno,stack: event.error && event.error.stack});}, true);window.addEventListener('unhandledrejection', function (event: any) {collectError({type: 'promiseError',msg: event.reason ? (event.reason.message || String(event.reason)) : '',stack: event.reason && event.reason.stack});});
}

3.接口请求异常
这里可以是所有接口捕获,也可以指定几个重点监控的接口名称进行追踪

  1. 针对普通fetch
// 3. 接口异常(fetch 拦截)
if (typeof window !== 'undefined' && 'fetch' in window) {const rawFetch = window.fetch;window.fetch = async function (...args) {try {return await rawFetch.apply(this, args);} catch (err:any) {collectError({type: 'apiError',url: args[0],    //请求地址params: args[1], //请求参数msg: err.message,stack: err.stack});throw err;}};
}

2.针对使用了axios或者其他工具并且定义了拦截器

axiosInstance.interceptors.response.use((response: AxiosResponse) => {const { data } = responsereturn data},(error: AxiosError) => {//错误收集,上报使用collectError({type: 'apiError',url: error.config && error.config.url,params: error.config && error.config.data,method: error.config && error.config.method,msg: error.message,stack: error.stack,response: error.response // 可选}))

二: 异常队列收集

我们在收集异常时往往不是收集到了就立刻上报,这样效率和资源都会有损耗,推荐的做法时,建立一个异常队列,用来暂时存储收集到的异常

// 异常队列
const errorQueue: any[] = [];

三:异常队列边界

有了异常队列,我们往往需要人为定义一个边界,当收集到一定数量后就可以进行上报任务

const MAX_QUEUE_LENGTH = 10;   //异常队列长度

四:上报时机

需要明确一点,异常上报不是我们的重点任务,它时服务于业务系统运行的。所以我们要有主次感,只有在队列任务空闲时才会上报,不分主次占用资源的进行上报,因为使用上报的话,频率往往会高于正常业务

requestIdleCallback,接受两个参数,一个是需要被执行的函数,一个时配置对象{},含一个空闲时间,一个是否因为超时强制执行

当然,requestIdleCallback并不是唯一的选择,在React中就没有采用这种方式,而是使用scheduler调度器策略,内部降级使用`setTimeout 等其他方式。

由于`requestIdleCallback运行环境的限制:
requestIdleCallback 目前不是所有浏览器都支持(如 Safari 兼容性较差,移动端支持也不完全支持)

// 定时上报,防止遗漏
setInterval(() => {if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {window.requestIdleCallback(reportErrors);} else {setTimeout(reportErrors, 0);}
}, REPORT_INTERVAL);

import { POST } from '@/httpUtils/http';const MAX_QUEUE_LENGTH = 10;   //异常队列长度
const REPORT_INTERVAL = 5000; // 5秒上报间隔// 异常队列
const errorQueue: any[] = [];
//上报地址
const fetchUrl='129.168.0.53/sys/error/queue'//重点监控接口清单
const importantUrl=['/sys/load/file','/sys/load/list','/sys/load/map']// 异常上报接口
const reportApi = async (errors: any[]): Promise<void> => {await POST(fetchUrl, {errors});return undefined;
};//主动上报方法
const reportErrors = async () => {if (errorQueue.length === 0) return;const errorsToSend = errorQueue.splice(0, errorQueue.length);try {await reportApi(errorsToSend);if (typeof window !== 'undefined') {window.alert('异常上报成功!');} else {console.log('异常上报成功!');}} catch (e) {// 失败提示if (typeof window !== 'undefined') {window.alert('异常上报失败:' + (e as Error).message);} else {console.error('异常上报失败:', e);}}
};// 收集异常
export const collectError = (error: any) => {// 判断是否为重点接口if (error.type === 'apiError' && importantUrl.some(u => error.url && error.url.includes(u))) {reportApi([error]);return;}// 其他异常,正常入队列errorQueue.push(error);if (errorQueue.length >= MAX_QUEUE_LENGTH) {reportErrors();}
}// 定时上报,防止遗漏
setInterval(() => {if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {window.requestIdleCallback(reportErrors);} else {setTimeout(reportErrors, 0);}
}, REPORT_INTERVAL);// 自动捕获场景 -- 页面卡顿(长任务)
if (typeof window !== 'undefined' && 'PerformanceObserver' in window) {try {const observer = new window.PerformanceObserver((list) => {list.getEntries().forEach(entry => {collectError({type: 'longTask',name: entry.name,startTime: entry.startTime,duration: entry.duration,detail: entry});});});observer.observe({ entryTypes: ['longtask'] });// eslint-disable-next-line @typescript-eslint/no-unused-vars} catch (e) {// 某些低版本浏览器不支持 longtask}
}// 自动捕获场景  -- 页面挂了/业务代码报错(全局异常)
if (typeof window !== 'undefined') {window.addEventListener('error', function (event: any) {collectError({type: 'jsError',msg: event.message,url: event.filename,line: event.lineno,  //代码行号col: event.colno,   stack: event.error && event.error.stack});}, true);window.addEventListener('unhandledrejection', function (event: any) {collectError({type: 'promiseError',msg: event.reason ? (event.reason.message || String(event.reason)) : '',stack: event.reason && event.reason.stack});});
}// 自动捕获场景 -- 接口异常(原生fetch 拦截)
if (typeof window !== 'undefined' && 'fetch' in window) {const rawFetch = window.fetch;window.fetch = async function (...args) {try {return await rawFetch.apply(this, args);} catch (err:any) {collectError({type: 'apiError',url: args[0],    //请求地址params: args[1], //请求参数msg: err.message,stack: err.stack});throw err;}};
}// 导出队列和上报函数(如需手动调用)
export { errorQueue, reportErrors };
http://www.lryc.cn/news/583546.html

相关文章:

  • 【实习篇】之Http头部字段之Disposition介绍
  • HTML + CSS + JavaScript
  • http get和http post的区别
  • C++ 中最短路算法的详细介绍
  • JAVA策略模式demo【设计模式系列】
  • LaCo: Large Language Model Pruning via Layer Collapse
  • Java 大视界 -- 基于 Java 的大数据分布式计算在生物信息学蛋白质 - 蛋白质相互作用预测中的应用(340)
  • windows指定某node及npm版本下载
  • Using Spring for Apache Pulsar:Message Production
  • Softmax函数的学习
  • 矩阵之方阵与行列式的关系
  • Flink-1.19.0源码详解6-JobGraph生成-后篇
  • Android Soundtrigger唤醒相关时序学习梳理
  • 常见 HTTP 方法的成功状态码200,204,202,201
  • C++并发编程-11. C++ 原子操作和内存模型
  • Token 和 Embedding的关系
  • 通过Tcl脚本命令:set_param labtools.auto_update_hardware 0
  • AI Agent:我的第一个Agent项目
  • 在 macOS 上安装与自定义 Oh My Zsh:让终端美观又高效 [特殊字符]
  • css支持if else
  • WIndows 编程辅助技能:格式工厂的使用
  • 单片机STM32F103:DMA的原理以及应用
  • React面试高频考点解析
  • 【LeetCode 热题 100】21. 合并两个有序链表——(解法二)递归法
  • Spark流水线数据对比组件
  • 第6章应用题
  • 01-elasticsearch-搭个简单的window服务-ik分词器-简单使用
  • 【01】MFC入门到精通—— MFC新建基于对话框的项目 介绍(工作界面、资源视图 、类视图)
  • 【前端】ikun-markdown: 纯js实现markdown到富文本html的转换库
  • Java SE 实现简单的图书管理系统(完善菜单操作)