前端异常监控系统

  1. 收集前端错误

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

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

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

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

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

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

window.addEventListener("unhandledrejection", e => {
  throw e.reason
});
window.addEventListener('error', args => {
  console.log(
    'error event:', args
  );
  return true;
}, true);

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

我们在src/main.js

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

通讯方式

动态创建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

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

window.addEventListener('error', args => {
  console.log(
    'error event:', args
  );
  uploadError(args)
  return true;
}, true);
function uploadError({
    lineno,
    colno,
    error: {
      stack
    },
    timeStamp,
    message,
    filename
  }) {
    // 过滤
    const info = {
      lineno,
      colno,
      stack,
      timeStamp,
      message,
      filename
    }
    // const str = new Buffer(JSON.stringify(info)).toString("base64");
  	const str = window.btoa(JSON.stringify(info))
    const host = 'http://localhost:7001/monitor/error'
    new Image().src = `${host}?info=${str}`
}

异常收集

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

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

搭建eggjs工程

# 全局安装egg-cli
npm i egg-init -g 
# 创建后端项目
egg-init backend --type=simple
cd backend
npm i
# 启动项目
npm run dev

编写error上传接口

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

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

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

'use strict';
 
const Controller = require('egg').Controller;
const { getOriginSource } = require('../utils/sourcemap')
const fs = require('fs')
const path = require('path')
 
class MonitorController extends Controller {
  async index() {
    const { ctx } = this;
    const { info } = ctx.query
    const json = JSON.parse(Buffer.from(info, 'base64').toString('utf-8'))
    console.log('fronterror:', json)
    ctx.body = '';
  }
}
 
module.exports = MonitorController;

记入日志文件

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

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

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值