前情摘要

此前发布的低代码前端异常监控相关文章中,我们已了解到通过 Sentry 实现错误监控与日志上报的核心要点。这不仅有助于快速定位和解决问题,还能提升应用程序的稳定性和用户体验:

  • 优化日志上报机制:通过手动和自动上报日志,确保所有错误都能被记录和上报。
  • 提高问题定位效率:利用Sentry的搜索和分析功能,快速定位问题根源。
  • 建立使用规范:通过规范Sentry的使用,确保日志信息的准确性和一致性。
  • 提升开发效率:减少因问题定位困难而导致的开发时间浪费,提高开发效率。

Sentry作为一个强大的错误监控和日志上报工具,能够帮助开发者更好地管理和维护应用程序。

通过本文的指导,开发者可以了解项目接入Sentry整体方案以便快速落地Sentry应用场景

本文将以七巧低代码前端项目接入Sentry进行案例说明。

第一步Sentry中创建项目

第二步代码改造

安装依赖

文件package.json


"dependencies": {
    "@sentry/integrations": "^6.2.1",
    "@sentry/rrweb": "^0.3.1",
    "rrweb": "^0.9.14",
    "@sentry/tracing": "6.14.1",
    "@sentry/vue": "6.14.1",
    "raven-js": "^3.27.2",
}
"devDependencies": {
    "@sentry/webpack-plugin": "1.15.1",
    "@sentry/cli": "1.64.1",
}

在根目录添加配置文件

文件:.sentryclirc

[defaults]
url=https://sentry.do1.com.cn/
org=sentry
project=console-web-v2

[auth]
token=83a43db6277c442b8e813f9bb0c2b234e59a7820684743ecbab36344a3d84b58

文件.npmrc

registry = "https://registry.npm.taobao.org/"
SENTRYCLI_CDNURL = "https://npm.taobao.org/mirrors/sentry-cli"
sentrycli_cdnurl = "https://npm.taobao.org/mirrors/sentry-cli"

初始化文件

文件:sentryInit.js

import Report from '@/utils/report'
import Vue from 'vue'
// 引入Sentry异常监控
import * as Sentry from '@sentry/vue'
import { Integrations } from '@sentry/tracing'
import SentryRRWeb from '@sentry/rrweb'
import authUtils from '@/utils/authUtils'

const sentryDsn = 'https://xxxxxxxxxxxxxxxxxxxxxxxxx'
// 缓存openSentry为true && 处于qa环境时,上报错误日志
export function sentryInitFunc(branchPath) {
  Sentry.init({
    Vue: Vue,
    dsn: sentryDsn,
    release: branchPath,
    environment: process.env.NODE_ENV,
    integrations: [
      new Integrations.BrowserTracing()
      // new SentryRRWeb()
    ],
    // 控制给定事务发送到 Sentry 的机会百分比, 过滤交易
    tracesSampleRate: 0.5,
    tracingOptions: {
      trackComponents: true
    }
  })

  const sentry = Report.getInstance(Vue, {}, branchPath, sentryDsn)
  Vue.prototype.$console = sentry

  const notLoginTip = '此用户未登录'
  try {
    const userData = authUtils.getLocalUserData()
    // 记录用户信息
    Sentry.setUser({ username: userData.personName })
    // 租户信息标签
    Sentry.setTag('corpId', userData.corpId)
    // 用户ID标签
    Sentry.setTag('userId', userData.id)
    // 组织名标签
    Sentry.setTag('orgName', userData.orgName)
    // 账号名标签
    Sentry.setTag('accountNum', userData.userName)
    // 当前报错页面标签
    Sentry.setTag('url', location.href)
    // 当前环境
    Sentry.setTag('tenantType', userData.tenantInfo ? userData.tenantInfo.tenantType : '')
  } catch (error) {
    console.error(error)
    Sentry.setUser({ username: notLoginTip })
  }
}


文件report.js (业务文件)

import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'
import authUtils from '@/utils/authUtils'
import Cookies from 'js-cookie'
import { timetrans } from '@/utils/common'
class Report {
  constructor(Vue, options = { user: '', corpId: '' }, release, sentryDsn) {
    this.Vue = Vue
    this.options = options
    this.release = release
    this.sentryDsn = sentryDsn
    this.userData = ''
  }

  /**
   * 单例模式
   */
  static getInstance(Vue, options, release, sentryDsn) {
    if (!(this.instance instanceof this)) {
      this.instance = new this(Vue, options, release, sentryDsn)
      this.instance.init()
    }
    return this.instance
  }

  /**
   * 初始化
   */
  init() {
    Raven.config(this.sentryDsn, {
      release: this.release,
      environment: process.env.NODE_ENV
    }).addPlugin(RavenVue, this.Vue).install()
    try {
      this.userData = authUtils.getLocalUserData()
      // 记录用户信息
      Raven.setUserContext({
        username: this.userData.personName || ''
      })
      // 设置全局tag标签
      Raven.setTagsContext({
        corpId: this.userData.corpId || '',
        accountNum: this.userData.userName || '',
        url: location.href,
        userId: this.userData.id || '',
        orgName: this.userData.orgName || ''
      })
    } catch (error) {
      console.error(error)
      // 记录用户信息
      Raven.setUserContext({
        username: '用户未登录'
      })
    }
  }

  // 组件内调用此方法即可上报sentry: this.$console.log('错误') this.$console.error('错误') this.$console.warn('错误')

  log() {
    console.log(...arguments)
    this.reportFunc(arguments, 'info')
  }

  error() {
    console.error(...arguments)
    this.reportFunc(arguments, 'error')
  }

  warn() {
    console.warn(...arguments)
    this.reportFunc(arguments, 'warning')
  }

  tips(data) {
    this.setBreadCrumb(data)
  }

  setBreadCrumb({ message, data }) {
    Raven.captureBreadcrumb({
      message: message,
      category: 'action',
      data: data
    })
  }

  /**
   * 主动上报
   * type: 'info','warning','error'
   */
  reportFunc(data = null, type) {
    const args = Array.from(data)
    let param = ''
    for (const i in Array.from(data)) {
      if (Number(i) !== args.length - 1) {
        param += `${JSON.stringify(args[i])}, `
      } else {
        param += `${JSON.stringify(args[i])}`
      }
    }
    // 异常上报
    // Raven.captureException(param, {
    //   level: type,
    //   logger: '手动上报数据',
    //   extra: {
    //     findDate: timetrans(Date.now(), 'y')
    //   }
    // })
    Raven.captureException(`level=${type} | 租户${this.userData ? this.userData.corpId : 'noLogin'} | report error: ${param}`, {
      level: type,
      logger: location.hash,
      extra: {
        data: param,
        options: args,
        findDate: timetrans(Date.now(), 'y')
      }
    })
  }
}
export default Report

使用

文件:main.js

import { sentryInitFunc } from '@/utils/sentryInit'
// 业务代码
if (process.env.NODE_ENV === 'production' && process.env.SENTRY_ENV === true) {
  sentryInitFunc('fixbug-2.0')
}

webpack核心配置

件:webpack.config.js

const SentryCliPlugin = require('@sentry/webpack-plugin')
/*
*
* 业务代码
*
*/ 
// sentry
const qiqiaoPlusSentry = JSON.stringify(process.env.npm_config_sentry)
/*
*
* 业务代码
*
*/ 
// ==========Sentry参数==========
let isBuildSentry = false
if (qiqiaoPlusSentry === '"true"' || process.env.SENTRY_ENV === 'build') {
  isBuildSentry = true
}
// 分支,暂不能拿到分支,先写死
let BRANCH_PATH = JSON.stringify(process.env.npm_config_branch) || '"fixbug-2.0"'
/*
*
* 业务代码
*
*/ 
plugins: [
  new webpack.DefinePlugin({
    'process.env.SENTRY_ENV': isBuildSentry || '"noBuild"',
    BRANCH_PATH
  })
]
/*
*
* 业务代码
*
*/ 
// 是否上传源码至sentry中
if (isBuildSentry) {
  let version = ''
  if (BRANCH_PATH) {
    version = BRANCH_PATH.replace(/"/g, '')
  }
  console.log('Sentry开启源码上传', '版本分支为:' + version)
  webpackConfig.plugins.push(
    new SentryCliPlugin({
      release: version,
      include: path.join(__dirname, '../dist'),
      ignore:  ['node_modules'],
      configFile: `sentry.properties`,
      urlPrefix: `~/qiqiao2/cnosole/`,
      errorHandler: function () {
        console.log('Sentry构建失败')
      }
    })
  )
} else {
  console.log('Sentry关闭源码上传')
}

工具函数

文件:common.js

// 根据时间戳转日期格式
export function timetrans(time, str) {
  const date = new Date(time)
  const Y = date.getFullYear() + '-'
  const M =
    (date.getMonth() + 1 < 10
      ? '0' + (date.getMonth() + 1)
      : date.getMonth() + 1) + '-'
  const D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
  const h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
  const m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
  const s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
  switch (str) {
    case 'y':
      return Y + M + D + '  ' + h + m
    case 'm':
      return M + D + '  ' + h + m
  }
}

第三部服务构建

npm run build --sentry

总结

本文详细介绍了将Sentry集成到前端项目的过程,包括创建Sentry项目、代码改造、服务构建等步骤。通过安装依赖、配置文件、初始化Sentry和webpack插件,实现了错误监控和日志上报功能。文章强调了自动化错误上报和丰富上下文信息的重要性,以提高问题定位效率。最终,通过构建命令自动上传源码至Sentry,确保了开发效率和应用稳定性的提升。


作者:道一云低代码

作者想说:喜欢本文请点点关注~

更多资料分享

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐