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

前言

继上篇文章 掌握主动权------系统错误监控助你降成本、提效率(上) - 掘金 (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拉你进 前端学习交流群 让我们一起 好好学习(🐟🐟🐟)吧😎😎😎

相关推荐
正小安26 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript