前端实现错误自动上报

背景

项目上线之后,用户如果出现错误(代码报错、资源加载失败以及其他情况),基本上没有办法复现,如果用户出了问题但是不反馈或直接不用了,对开发者或公司来说都是损失。前端实现错误自动上报(Error Reporting 或 Error Tracking)是一个重要的功能,它帮助开发者及时发现并修复生产环境中的错误,从而提升用户体验和应用的稳定性。

实现

  • window.onerror和window.addEventListener相比,无法监听网络异常。window.onerrorwindow.addEventListener,对Promise报错都是无法捕获。
  • 每一个Promise写一个catch,如果觉得麻烦,那么就要使用一个新的事件,unhandledrejection。
  • vue异常处理
  • 上报错误数据

使用tracekit库来解析错误的堆栈信息,创建文件errorReporting.js在src/main.js中引入。

import Vue from 'vue'
import TraceKit from 'tracekit'
import dayjs from 'dayjs'
import http from '@/base/http'

const protcol = window.location.protocol

// 用于订阅错误报告的通知或事件
TraceKit.report.subscribe((error, service) => {
  const { message, stack = [] } = error || {}
  const obj = {
    message,
    stack: {
      column: stack[0].column,
      line: stack[0].line,
      func: stack[0].func,
      url: stack[0].url
    }
  }
  const params = {
    error: obj,
    data: {
      errTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
      isMobile: /iPhone|iPad|iPod|Android/i.test(navigator.userAgent), // 是否移动端
      isWechat: /MicroMessenger/i.test(navigator.userAgent), // 是否微信浏览器
      isIOS: /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream, // 两个都是false就是未知设备
      isAndroid: /Android/.test(navigator.userAgent) && !/Windows Phone/.test(navigator.userAgent)
    },
    browserInfo: {
      userAgent: navigator.userAgent,
      protcol: protcol
    }
  }
  console.log(params, '错误上报')
  // http.post(service, params).then(() => {
  //   console.log('错误上报成功')
  // }).catch(() => {
  //   console.log('错误上报失败')
  // })
})

// window.onerror和window.addEventListener,对Promise报错都是无法捕获
// 图片、同步、网络、try catch(不写catch会不会抛)、try catch 不能捕获异步,同时阻塞js
window.addEventListener('error', args => {
  console.log(args, 'windowArgs')
  const err = args.target.src || args.target.href
  const obj = {
    message: '加载异常' + err
  }
  if (!err) {
    return true
  }
  TraceKit.report(obj, 'reportWindowError')
}, true) // 捕获

// Promise、async/await报错
window.addEventListener('unhandledrejection', error => {
  console.log('unhandledrejection', error)
  TraceKit.report(error.reason, 'reportPromiseError')
}, true)

// vue框架
Vue.config.errorHandler = (err, vm, info) => {
  console.log('Error: ', err) // 错误对象,包含错误消息、堆栈信息等
  console.log('vm', vm) // 引发错误的vue组件实例,可以获取组件的状态、数据和方法
  console.log('info: ', info) // 错误的额外信息,描述错误发生的位置或上下文
  TraceKit.report(err, 'reportVueError')
}
// 至此,js中同步、异步、资源加载、Promise、async/await都有相对应的捕获方式

  • 搭建监控后台

npm init -y 使用express进行搭建后端,source-map用于解析js.map文件,npm i express nodemon source-map。

  • 设置允许跨域

可以自己手动设置响应头实现跨域,我这里选择使用cors库,npm i cors,

const cors = require('cors');
app.use(cors()); // 这条需要放在 const app = express(); 后
  • monitor后台项目,server.js文件
const express = require('express')
const SourceMap = require('source-map')
const dayjs = require('dayjs')
const cors = require('cors')
const path = require('path')
const fs = require('fs')

const PORT = 9999

const app = express()
app.use(cors())
// 解析表单中的application/x-www-form-urlencoded和application/json
app.use(express.urlencoded({
  extended: true
}))
app.use(express.json())

const errorLog = (urlParams, res, req) => {
  const type = urlParams.error.source || 'Vue'
  const today = dayjs().format('YYYY-MM-DD') // 今天

  const logDirPath = path.join(__dirname, 'log')
  const logFilePath = path.resolve(__dirname, 'log/' + `log-${today}.txt`)

  if (!fs.existsSync(logDirPath)) {
    fs.mkdirSync(logDirPath, { recursive: true })
  }
  if (!fs.existsSync(logFilePath)) {
    fs.writeFileSync(logFilePath, '', 'utf8')
  }
  const writeStream = fs.createWriteStream(logFilePath, { flags: 'a' })
  writeStream.on('open', () => {
    writeStream.write(`错误类型:${type}` + '\n')
    writeStream.write('错误发生时间:' + urlParams.data.errTime + '\n')
    writeStream.write('IP:' + req.ip + '\n')
    writeStream.write(`安卓: ${urlParams.data.isAndroid} IOS: ${urlParams.data.isIOS} 移动端: ${urlParams.data.isMobile} 微信: ${urlParams.data.isWechat} (安卓和ios同时为false表示未知设备)` + '\n')
    writeStream.write('用户代理:' + urlParams.browserInfo.userAgent + '\n')
    writeStream.write('错误信息:' + JSON.stringify(urlParams.error) + '\n')
    writeStream.write('---------------------------------- \n')
    writeStream.end(() => {
      res.status(200).send({
        data: '错误上报成功',
        code: 200,
      })
    })
  })
  writeStream.on('error', err => {
    res.status(404).send({
      data: '错误上报失败' + err,
      code: 404,
    })
  })
}
app.post('/reportError', async (req, res) => {
  const urlParams = req.body
  const source = urlParams.error.source
  if (source !== 'window') {
    const stack = urlParams.error.stack || {}
    // 获取文件名
    const fileName = path.basename(stack.url || '')
    // 查找map文件
    const filePath = path.join(__dirname, 'uploads', fileName + '.map')
    const readFile = filePath => {
      return new Promise((resolve, reject) => {
        fs.readFile(filePath, {
          encoding: 'utf-8'
        }, (err, data) => {
          if (err) {
            return reject(err)
          }
          resolve(JSON.parse(data))
        })
      })
    }
    const searchSource = async ({ filePath, line, column }) => {
      const rawSourceMap = await readFile(filePath)
      const consumer = await new SourceMap.SourceMapConsumer(rawSourceMap)
      const res = consumer.originalPositionFor({
        line,
        column
      })
      consumer.destroy()
      return res
    }
    let sourceMapParseResult = ''
    try {
      // 解析sourceMap结果
      sourceMapParseResult = await searchSource({
        filePath,
        line: stack.line,
        column: stack.column
      })
    } catch (err) {
      sourceMapParseResult = err
    }
    console.log('解析结果', sourceMapParseResult)
  }
  errorLog(urlParams, res, req)
})
// 监听端口  
app.listen(PORT, () => {
  console.log(`服务启动成功,端口号为:${PORT}`)
})

通过报错提示的js文件,查看后都是压缩混淆之后的js代码,这时候就需要打包时生成的source map文件了,这个文件中保存着打包后代码和源码对应的位置,我们只需要拿到报错的堆栈信息,通过转换,就能通过source map找到对应我们源码的文件及出错的代码行列信息

tracekit、Sentry 和 Bugsnag

都是流行的错误追踪和监控工具,它们帮助开发者在应用程序运行时捕获、报告和分析错误。尽管它们都有类似的目标,但它们在功能、集成方式、定价模型等方面有所不同。下面是对这三个工具的简要概述:

TraceKit

概述:TraceKit 是一个轻量级的 JavaScript 错误追踪库,它可以帮助你捕获和报告浏览器中的未捕获异常。它通常被集成到前端项目中,以便在客户端捕获错误。

特点:

捕获并报告未捕获的异常。

支持跨域脚本错误(如果浏览器允许)。

可以自定义错误报告的内容和格式。

易于集成到现有的前端项目中。

限制:

主要关注于前端错误追踪。

可能需要额外的后端服务来接收和存储错误报告。

缺少一些高级功能,如性能监控、崩溃报告等。

Sentry

概述:Sentry 是一个开源的错误追踪系统,它支持多种语言和平台,包括 JavaScript、Python、Ruby、Node.js 等。它提供了一个强大的平台来监控和修复崩溃、错误和性能问题。

特点:

实时错误追踪和报告。

详细的错误堆栈跟踪和上下文信息。

性能监控和崩溃报告。

强大的查询和过滤功能,以便快速定位问题。

集成到多个开发工具和平台中,如 GitHub、Slack、Jira 等。

支持自定义错误处理和警报。

定价:

Sentry 提供免费的基础计划,但高级功能需要付费订阅。

Bugsnag

概述:Bugsnag 是另一个流行的错误监控和报告工具,它专注于帮助开发者快速发现和修复应用中的错误。它支持多种编程语言和平台,包括移动应用、Web 应用和服务器端应用。

特点:

实时错误追踪和报告。

详细的错误堆栈跟踪和上下文信息。

支持自定义错误处理和警报。

崩溃报告和性能监控。

易于集成到现有的开发流程中。

提供了丰富的 API 和 SDK,以便在多种环境中使用。

定价:

Bugsnag 提供免费的基础计划,但高级功能和更大的存储空间需要付费订阅。

总结

选择哪个工具取决于你的具体需求、预算以及你正在使用的技术栈。如果你只需要一个简单的前端错误追踪解决方案,并且不介意自己处理错误报告的存储和检索,那么 TraceKit 可能是一个不错的选择。然而,如果你正在寻找一个更全面的错误监控和报告解决方案,包括性能监控、崩溃报告以及与其他开发工具的集成,那么 Sentry 或 Bugsnag 可能更适合你的需求。最终的选择应该基于你的具体需求和对这些工具的评估。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值