搭建一个前端异常监控系统

1,376 阅读3分钟

后端项目最少可以通过日志文件记录错误,但是前端项目发布后缺乏记录线上错误的手段。如果出现一个预期外的错误不能及时定位就可能会导致产品功能运行异常。 下面我就介绍一下两种搭建前端异常监控系统的两种方案,一种是手动搭建一个简易的内部项目、一种是私有化部署社区开源的sentry。

搭建一个简单的前端监控系统

系统主要内容分为两块:通过全局采集错误信息发送请求记录错误或发送警告邮件进行异常上报;在监控系统里展示出现的异常列表及相关堆栈信息,或者通过webpack打包的项目可以上传sourceMap文件到监控系统里进行错误定位。

  • 前端错误有多种,我们需要采用不同的方式才能捕获到错误,所有错误的捕获都遵循同源策略
    • try-catch、promise-catch主动处理错误
    // try-catch
    try {
      let a
      console.log(a.length)
    } catch (e) {
      console.log(e)
    }
    // promise-catch
    Promise.then(() => {
      let a
      console.log(a.length)
    }).catch(e => {
      console.log(e)
    })
    
    • window.onerror(window.addEventListener('error', () => {}))
      catch方法需要在捕获异常的代码上进行处理,全部使用这种方式会导致页面臃肿不堪,不适用于整个项目的异常捕获,window.onerror提供了全局监听异常的功能。window.onerror提供了错误的信息、错误的文件、错误行列号、错误堆栈信息,绝大部分错误都可以通过这种方式全局捕获,但是promise错误、跨域错误等使用这种方式无法捕获到。
    let a
    console.log(a.length)
    window.onerror = function() {
      console.log(arguments)
    }
    
    • window.onunhandledrejection(window.addEventListener('unhandledrejection', () => {}))
      未catch处理的promise发生异常时会抛出unhandledrejection事件。
    Promise.then(() => {
      let a
      console.log(a.length)
    })
    window.onunhandledrejection = function() {
      console.log(arguments)
    }
    
    • ErrorBoundary
      React16以后提供了componentDidCatch方法来捕获组件发生的错误
    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
      componentDidCatch(error, info) {
        // Display fallback UI
        this.setState({ hasError: true });
        // You can also log the error to an error reporting service
        logErrorToMyService(error, info);
      }
      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
      }
    }
    // 然后包裹需要处理的组件
    <ErrorBoundary>
      <App />
    </ErrorBoundary>
    
    • Vue.config.errorHandler
      vue组件默认处理了异常错误,不会抛出,如果要进行上报就需要使用errorHandler来进行上报
    Vue.config.errorHandler = function (err, vm, info) {
      // handle error
      // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
      // 只在 2.2.0+ 可用
    }
    
  • 上报信息
    为了方便定位问题,我们需要的信息有错误信息、错误行列、错误堆栈、浏览器信息、项目信息,如果是混淆过的代码我们需要利用sourceMap进行解析出真实的行列信息。由于信息数据比较复杂所以我们采用xhr请求的post方法进行上报,image上报只能使用get传递简单数据
  • 解析sourceMap
    后台使用node.js提供服务,node的source-map插件可以方便的解析sourceMap得到混淆前的文件路径及行列信息

部署Sentry

Sentry是一个实时事件的日志聚合平台。它专门监测错误并提取所有有用信息用于分析。部署Sentry需要两步,后台Docker部署、前端集成ReactSDK