zoukankan      html  css  js  c++  java
  • [转] vue前端异常监控sentry实践

    1. 监控原理

    1.1 onerror

    传统的前端监控原理分为异常捕获和异常上报。一般使用onerror捕获前端错误:

    window.onerror = (msg, url, line, col, error) => {
      console.log('onerror')
      // TODO
    }

    1.2 promise

    但是onerror事件无法捕获到网络异常的错误(资源加载失败、图片显示异常等),例如img标签下图片url 404 网络请求异常的时候,onerror无法捕获到异常,此时需要监听unhandledrejection

    window.addEventListener('unhandledrejection', function(err) {
      console.log(err)
    })

    1.3 上报

    捕获的异常如何上报?常用的发送形式主要有两种:

    1. 通过 ajax 发送数据(xhr、jquery...)
    2. 动态创建 img 标签的形式
    function report(error) {
      var reportUrl = 'http://xxxx/report'
      new Image().src = reportUrl + '?error=' + error
    }

    1.4 使用sentry

    sentry是一套开源的强大的前端异常监控上报工具,官网地址:https://sentry.io,官方提供了如何搭建sentry服务,此处略过安装流程,直接使用已有的服务。

    1.5 与vue结合

    针对vue,sentry官方推荐使用raven配合sentry进行异常捕获和上报。而在vue中,vue提供了错误捕获方法vue error handler,官方也推荐使用错误追踪服务 sentry 并通过vue error handler选项提供了官方支持。

    2. 安装raven

    raven是sentry官方针对vue推荐的插件,yarn安装raven-js即可。

    $ yarn add raven-js

    3. 初始化sentry

    初始化引入Vue、Raven、RavenVue即可,sentry能主动监听上报错误。

    import Raven from 'raven-js'
    import RavenVue from 'raven-js/plugins/vue'
    const dsn = 'https://<key1>@sentry.io/<key2>'
    Raven.config(dsn).addPlugin(RavenVue, Vue).install()

    4. 手动上报

    对于一些其他信息,如提示日志等,无法自动捕获,需要手动进行上报。

    log (data = null, type = 'error', options = {}) {
      // 添加面包屑
      Raven.captureBreadcrumb({
        message: data,
        category: 'manual message'
      })
      // 异常上报
      if (data instanceof Error) {
        Raven.captureException(data, {
          level: type,
          logger: 'manual exception',
          tags: { options: options }
        })
      } else {
        Raven.captureException('error', {
          level: type,
          logger: 'manual data',
          extra: {
            data: data,
            options: this.options,
            date: new Date()
          }
        })
      }
    }

    5. 封装异常上报类 Report.js

    针对上述内容,封装异常上报类Report,使用单例模式,避免监控类重复实例化。

    /**
     * by csxiaoyao
     * 2019.03.17
     * sunjianfeng@csxiaoyao.com
     */
    import Raven from 'raven-js'
    import RavenVue from 'raven-js/plugins/vue'
    class Report {
      static dsn = 'https://<key1>@sentry.io/<key2>'
      constructor (Vue, options = {}) {
        if (process.env.NODE_ENV === 'production') { // TODO }
        this.Vue = Vue
        this.options = options
      }
      /**
       * 单例模式
       */
      static getInstance (Vue, options) {
        if (!(this.instance instanceof this)) {
          this.instance = new this(Vue, options)
          this.instance.install()
          this.instance.registerError()
        }
        return this.instance
      }
      /**
       * init
       */
      install () {
        Raven.config(Report.dsn, {
          release: '1.0.0',
          environment: 'production'
          // whitelistUrls: [/localhost/, /test.oa.com/]
        }).addPlugin(RavenVue, this.Vue).install()
        // 记录用户信息
        Raven.setUserContext({
          user: this.options.user || ''
        })
        // 设置全局tag标签
        Raven.setTagsContext({ environment: this.options.env || '' })
      }
      /**
       * 注册全局错误处理
       */
      registerError () {
        // 监听error
        window.onerror = (msg, url, line, col, error) => {
          console.log('onerror')
          if (msg !== 'Script error.' && !url) {
            return true
          }
          setTimeout(() => {
            let data = {}
            col = col || (window.event && window.event.errorCharacter) || 0
            data.url = url
            data.line = line
            data.col = col
            data.error = error
            if (&& error.stack) {
              data.msg = error.stack.toString()
            }
            this.log(data)
          }, 0)
          return true
        }
        // 监听promise
        window.addEventListener('unhandledrejection', err => {
          console.log('unhandledrejection')
          setTimeout(() => {
            this.log(JSON.stringify(err))
          }, 0)
        })
      }
      /**
       * 主动上报
       * type: 'info','warning','error'
       */
      log (data = null, type = 'error', options = {}) {
        // 添加面包屑
        Raven.captureBreadcrumb({
          message: data,
          category: 'manual message'
        })
        // 异常上报
        if (data instanceof Error) {
          Raven.captureException(data, {
            level: type,
            logger: 'manual exception',
            tags: { options: options }
          })
        } else {
          Raven.captureException('error', {
            level: type,
            logger: 'manual data',
            extra: {
              data: data,
              options: this.options,
              date: new Date()
            }
          })
        }
      }
    }
    export default Report

    6. 调用 Report.js 类

    main.js中引入Report类,并绑定实例化后的sentry实例到Vue上以便全局调用。

    import Report from '@/assets/Report'
    let sentry = Report.getInstance(Vue, {})
    Vue.prototype.$sentry = sentry // 设置全局变量

    在其他的vue组件中手动上报日志。

    this.$sentry.log('test')

    7. sourceMap

    sentry针对压缩过的js文件提供了sourceMap分析,只需要上传版本对应的sourceMap,就可以在错误日志中查看对应的源码信息。详细方法见官方文档:https://docs.sentry.io/clients/javascript/sourcemaps/(https://docs.sentry.io/clients/javascript/sourcemaps/)

    转自:https://cloud.tencent.com/developer/article/1404307

  • 相关阅读:
    NET在后置代码中输入JS提示语句(背景不会变白)
    corev4.css 左菜单修改CSS
    寺庙里的那点荡事儿
    sharepoint 2010中通过命令部署和卸载FEATURE
    定时任务 Timer JOB
    获取MOSS个人站点的SPWeb对象
    C#对Active Directory进行增删修查的类源码
    权限操作
    在SharePoint中,检验用户(SPUser)是否属于给定的组(SPGroup)的方法(代码)
    DirectoryEntry所有字段对应解释
  • 原文地址:https://www.cnblogs.com/chris-oil/p/11512923.html
Copyright © 2011-2022 走看看