• 前端异常监控系统


    1. 收集前端错误

    2. 编写错误上报逻辑,上报错误

    3. 代码上线打包将sourcemap文件上传至错误监控服务器

    4. 发生错误时监控服务器接收错误并记录到日志中

    5. 根据sourcemap和错误日志内容进行错误分析

    异常类型同步方法异步方法资源加载Promiseasync/await
    try/catch✔️✔️
    onerror✔️✔️
    error事件监听✔️✔️✔️
    unhandledrejection事件监听✔️✔️

     实际上我们可以将unhandledrejection事件抛出的异常再次抛出就可以统一通过error事件进行处理了。

    1. window.addEventListener("unhandledrejection", e => {
    2. throw e.reason
    3. });
    4. window.addEventListener('error', args => {
    5. console.log(
    6. 'error event:', args
    7. );
    8. return true;
    9. }, true);

    为了对Vue发生的异常进行统一的上报,需要利用vue提供的handleError句柄。一旦Vue发生异常都会调用这个方法。

    我们在src/main.js

    1. Vue.config.errorHandler = function (err, vm, info) {
    2. console.log('errorHandle:', err)
    3. }

    通讯方式

    动态创建img标签

    其实上报就是要将捕获的异常信息发送到后端。最常用的方式首推动态创建标签方式。因为这种方式无需加载任何通讯库,而且页面是无需刷新的。基本上目前包括百度统计 Google统计都是基于这个原理做的埋点

    new Image().src = 'http://localhost:7001/monitor/error'+ '?info=xxxxxx'

    通过动态创建一个img,浏览器就会向服务器发送get请求。可以把你需要上报的错误数据放在querystring字符串中,利用这种方式就可以将错误上报到服务器了。

    Ajax上报

    上报哪些数据

    error事件参数

    属性名称含义类型
    message错误信息string
    filename异常的资源urlstring
    lineno异常行号int
    colno异常列号int
    error错误对象object
    error.message错误信息string
    error.stack错误信息string

    核心是错误栈,包含了绝大多数调试有关新。其中包括了异常位置(行号,列号),异常信息

    上报数据序列化

    [译]JavaScript错误处理和堆栈追踪 · Issue #49 · dwqs/blog · GitHub

    由于通讯的时候只能以字符串方式传输,我们需要将对象进行序列化处理。

    大概分成以下三步:

    • 将异常数据从属性中解构出来存入一个JSON对象

    • 将JSON对象转换为字符串

    • 将字符串转换为Base64

    当然在后端也要做对应的反向操作

    1. window.addEventListener('error', args => {
    2. console.log(
    3. 'error event:', args
    4. );
    5. uploadError(args)
    6. return true;
    7. }, true);
    8. function uploadError({
    9. lineno,
    10. colno,
    11. error: {
    12. stack
    13. },
    14. timeStamp,
    15. message,
    16. filename
    17. }) {
    18. // 过滤
    19. const info = {
    20. lineno,
    21. colno,
    22. stack,
    23. timeStamp,
    24. message,
    25. filename
    26. }
    27. // const str = new Buffer(JSON.stringify(info)).toString("base64");
    28. const str = window.btoa(JSON.stringify(info))
    29. const host = 'http://localhost:7001/monitor/error'
    30. new Image().src = `${host}?info=${str}`
    31. }

    异常收集

    异常上报的数据一定是要有一个后端服务接收才可以。

    我们就以比较流行的开源框架eggjs为例来演示

    搭建eggjs工程

    1. # 全局安装egg-cli
    2. npm i egg-init -g
    3. # 创建后端项目
    4. egg-init backend --type=simple
    5. cd backend
    6. npm i
    7. # 启动项目
    8. npm run dev

    编写error上传接口

    首先在app/router.js添加一个新的路由

    1. module.exports = app => {
    2. const { router, controller } = app;
    3. router.get('/', controller.home.index);
    4. // 创建一个新的路由
    5. router.get('/monitor/error', controller.monitor.index);
    6. };

    创建一个新的controller (app/controller/monitor)

    1. 'use strict';
    2. const Controller = require('egg').Controller;
    3. const { getOriginSource } = require('../utils/sourcemap')
    4. const fs = require('fs')
    5. const path = require('path')
    6. class MonitorController extends Controller {
    7. async index() {
    8. const { ctx } = this;
    9. const { info } = ctx.query
    10. const json = JSON.parse(Buffer.from(info, 'base64').toString('utf-8'))
    11. console.log('fronterror:', json)
    12. ctx.body = '';
    13. }
    14. }
    15. module.exports = MonitorController;

    记入日志文件

    错误记入日志。实现的方法可以自己用fs写,也可以借助log4js这样成熟的日志库。

    当然在eggjs中是支持我们定制日志那么我么你就用这个功能定制一个前端错误日志好了。

    在/config/config.default.js中增加一个定制日志配置

    1. // 定义前端错误日志
    2. config.customLogger = {
    3. frontendLogger : {
    4. file: path.join(appInfo.root, 'logs/frontend.log')
    5. }
    6. }

    在/app/controller/monitor.js中添加日志记录

    1. async index() {
    2. const { ctx } = this;
    3. const { info } = ctx.query
    4. const json = JSON.parse(Buffer.from(info, 'base64').toString('utf-8'))
    5. console.log('fronterror:', json)
    6. // 记入错误日志
    7. this.ctx.getLogger('frontendLogger').error(json)
    8. ctx.body = '';
    9. }

  • 相关阅读:
    超全!Python图形界面框架PyQt5使用指南!
    k8s在线安装harbor镜像仓库
    JS进阶-构造函数创建对象
    Python modbus_tk 库源码分析
    软考 系统架构设计师系列知识点之软件架构风格(8)
    从心灰意冷到自学Java3个月顺利拿到offer,多亏这份文档
    Day40
    SpringBoot整合百度云人脸识别功能
    驱动开发:通过应用堆实现多次通信
    STM32读写RTC内部时钟外设,设置和显示时钟
  • 原文地址:https://blog.csdn.net/YouZi_X/article/details/125661023