掌握主动权——系统错误监控助你降成本、提效率(下)

前言

继上篇文章 掌握主动权------系统错误监控助你降成本、提效率(上) - 掘金 (juejin.cn) 我们实现了前端错误捕获、错误上报的主要功能。

本文主要记录了我自己在项目中加入错误监控时,服务端的接口开发的实践过程。可能会存在一些问题,有需要完善的部分。欢迎大家评论区指点、讨论。

1、服务端接口实现

服务端我是用的node环境,关于node使用请自行学习,网上资料很多。我这里就记录一下大致流程和遇到的问题。

搭建好服务环境后,首先要满足的就是我们前端需要的接口:

source-map文件上传接口

上篇文章我们前端项目中自己写了webpack插件,在打包时就会生成source-map文件,同时调用上传接口。这个接口做的事情很简单,就是接收数据、创建文件夹、将source-map内容写入磁盘(写入磁盘时需要注意的是每次上传后的内容要覆盖上一次内容)

js 复制代码
  async function upload (req, res) {
    let { mapsArr } = req.body
    // 要存储的源码路径
    const filePath = path.join(__dirname, '../', 'source-maps');
    // 检测文件夹是否存在
    if (!fs.existsSync(filePath)) {
      fs.mkdirSync(filePath)
    }
    // 将source-map内容写入磁盘
    const result = await writeSourceMapFile(filePath, mapsArr)
  }

错误信息上报接口

这个接口主要是需要前端用一个 tyep 字段做一个区分是资源错误还是其他错误。因为资源错误时是拿不到line、column等信息的,所以资源错误时就不需要去解析了,直接返回当前资源错误的url、src信息。

js 复制代码
async function img (req, res) {req.query.data)
  const { stack, ...args } = JSON.parse(req.query.data);
  if (args.type === 'resourceError') {
    const srcName = path.basename(stack.src);
    const obj = {
      ...stack,
      name: srcName,
    }
    return
  }
  // 非资源错误时使用堆栈信息去解析真实信息
  const { line, column, url } = stack
  const basename = path.basename(url);
  // 解析源码返回真实的错误信息
  const sourceDatas = await searchSource({ basename, line, column })
}

2、错误信息回溯(错误解析)

使用source-map插件解析错误

安装 npm i source-map,在错误上报后,我们拿到了关键的 错误栈信息,这时候就需要去解析对应的真实源码信息了

js 复制代码
 function searchSource ({ basename, line, column, message }) {
   const filePath = path.join(__dirname,
     "../",
     "source-maps",
     basename+'.js.map')
   const rawSourceMap = fs.readFileSync(filePath, 'utf-8')
   // 创建 SourceMapConsumer 对象
   const consumer = new SourceMapConsumer(rawSourceMap)
   // 解析源码,将第 line 行第 column 列的位置信息,转换为对应真实源代码位置信息
   const res = consumer.originalPositionFor({ line, column });
   // 执行完销毁
   consumer.destroy();
   console.log("最终数据:", res)
 }

不出意外的话,到这一步,我们就完全还原了错误发生现场 ,此时的 source 字段就是真实发生错误的文件,linecolumn 字段就是该错误发生的具体行数列数。后续我们把这些信息存储到数据库后,就可以愉快的进行问题回溯了。

解析错误信息时踩坑

  • 在解析时报错如下

    这里是因为在使用 new SourceMapConsumer() 构造函数创建 SourceMapConsumer 对象时,如果传递的 sourceMap 参数不是一个符合 Sourcemap 规范的 JavaScript 对象,则会报错。其中,"version" 是必需的参数,因为它指定了源映射的版本号。

    解决:

    js 复制代码
    // 转换为json对象
    const sourceMap = JSON.parse(filePath, 'utf8')); 
    
    // 检查 sourceMap 是否符合规范 
    if (!sourceMap.hasOwnProperty('version')){ 
        throw new Error('Invalid Sourcemap format: "version" field is missing.'); 
     }
  • 根据堆栈行列信息解析后结果字段都为null

    找到对应源码文件,观察:chunk-a8c0af14 内容:

    发现 file 字段文件后缀是.css,奇怪!我们的报错不应该是js里的吗? 这里我一度怀疑是我前端项目打包配置出错了,css和js混了。 而且观察 sourcesContent字段只有样式源码,没有js内容。这样肯定是解析不到的!!!

经过查询资料、请教掘友、自己排查webpack配置折腾一番后发现,我是没有开启 productionSourceMap: true选项,只配置了 devtool: 'source-map', 这样虽然打包时生成 sourceMap 文件了,但是还需要开启 productionSourceMap: true 后才能生成具体的sourceMap内容。 这块真的醉了,太粗心了。修改配置后重新打包就没问题了。

3、错误信息持久化

还原了错误发生的现场后,我们就需要做数据持久化了,这里我使用的是 MongoDB 数据库
对于前端错误信息的上报,推荐使用 NoSQL 数据库,特别是针对非常大量快速变化的数据 。其中,常用的 NoSQL 数据库包括 MongoDB、Cassandra、Redis等。

这些数据库具有高可扩展性高并发性高吞吐量等特点,可以有效地存储和处理前端错误信息,并支持实时查询和分析。

mongoose创建模型

为了方便,这里使用 mongoose 来操作数据库。具体 mongoose操作自行学习。

创建约束对象、映射、创建模型对象、且对外暴露。

js 复制代码
const mongoose = require('mongoose')
// 引入模式对象
let Schema = mongoose.Schema
// 创建约束对象
let errorInfoRule = new Schema({
  errorCount: {
    tyep: Number,
    default: 0
  },
  errorType: {
    type: String,
    required: true,
  },
  message: {
    type: String,
    required: true,
  },
  date: {
    type: String,
    default: Date.now()
  },
  stack: {
    type: Object,
    default: {}
  },
})
// 映射、创建模型对象、且对外暴露
module.exports = mongoose.model('errorInfo', errorInfoRule)

保存错误数据到数据库

当错误信息上报、解析后我们对格式化后的错误数据进行保存到数据库。

js 复制代码
const errorInfoModel = require('../model/errorInfoModel')
// 保存错误信息到数据库
async function addErrorInfo (res, baseData, stack) {
  let { type, message, date } = baseData;
  if (!!type && !!message) {
    let conditions = {
      errorType: type,
      message: message,
      date: date,
      stack: stack
    }
    try {
       const result = await errorInfoModel.create(conditions)
        if (result) {
          res.status(200)
          res.send('错误信息上报成功!')
        }
      } catch (err) {
        console.log('添加错误数据到数据库错误:', err)
     }
  } else {
    console.log('缺少字段!')
    res.status(400)
    res.send('缺少字段!')
  }
}

这时刷新数据库就可以看到数据已经保存了

4、错误信息回显

最后一步就是整一个前端页面来进行错误信息回显了,我这里就先做了一个简单的表格去展示一下错误数据的关键信息,还可以进行按ID、错误类型、错误次数等方式进行过滤搜索,方便我们查看错误溯源。

后期可以根据自己项目的情况更细化的完善和扩展数据监控回显功能,比如以图表形式展示、计算出错频率、错误报警通知等

最终效果图

总结

我觉得首先是不要怕错,对于新鲜事物只要勇敢迈出第一步就是对的,只有尝试自己不擅长的东西才能收获更多!本文只是做了一个简单的错误监控实现,对于复杂场景还需进一步扩展。如果感兴趣的小伙伴可以去深入这方面研究,学无止境,加油。

如果文章对你有帮助,可以点赞、评论、收藏、转发互动支持哈 😀😀😀

点击链接 学习交流群(前端微信群) 加vx拉你进 前端学习交流群 让我们一起 好好学习(🐟🐟🐟)吧😎😎😎

相关推荐
cy玩具18 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫2 小时前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web