nuxt.js项目中全局捕获异常并生成错误日志全过程

2019-12-04 10:47:59

参考地址  nuxt.js项目中全局捕获异常并生成错误日志全过程

 需求:客户在使用过程中页面报错时,可以生成错误记录传回服务器,以便改进。

  步骤:
    一.全局捕获异常,
    二.发送到服务端,
    三.生成错误日志。

  一.全局捕获异常

如图,vue提供了errorHandle这个方法来处理全局异常,更多详细内容参见官网

 

我在页面中写了一个错误的函数,触发了errorHandler,控制台打印如下:

 

在utils.js中写了如下代码:

1 //系统错误捕获2 const errorHandler = (error,vm,info)=>{3   getErr(error,vm,info);4 }5 6 Vue.config.errorHandler = errorHandler;7 Vue.prototype.$throw = (error,vm,info)=> errorHandler(error,vm,info);

然后在另一个公用的js(commonService.js)中:

/**
 * 捕获异常 */const getErr = async(err,_this,info) => {
  _this.$store.dispatch('getErr',{
    err:err.stack,
    hook:info
  }
}

说明一下,之所以写在两个文件中,是因为项目结构就是这样的。

 

  二.发送到服务端

 

  接下来就是如何把请求发送到node服务器上了。既然通过dispatch触发,那就统一在store目录下的index.js中处理:

 

// 捕获异常,存在node服务器中async getErr({ commit },{ err_info }) {
    console.log({err_info})
    await axios.post('/api/getErr',{ err_info })
}

 

在浏览器中调试,发现接口报了500.发现err_info是undefined,即{err_info}是{"err_info":undefined}。找了半天也没发现问题,所以就不再通过dispatch触发,直接在commonService.js中拿到数据就发到node服务器。另外,查资料的时候看到dispatch中最多只能传两个参数,还有一个是commit,所有可以把其他的参数拼装在一个对象中,避免出现undefined。这条没有实践过,暂时存疑。于是我在commonService.js中修改了原来的代码,结果如下:

 

const getErr = async(err,_this,info) => {
  await axios.post('/api/getErr',{ err:err.stack,hook:info })
}

 

 运行一下,请求发送成功,如图:

 

 

 

  三.生成错误日志

  OK,现在服务端已经收到请求,但是还没有返回值,所以要开始写服务端的代码了。我们的项目是基于nuxt的,所以代码在api/index.js中:

 

// 捕获异常router.post('/getErr', (req, res) => {
  req.session.getErr = {err:req.body.err,hook:req.body.hook};  return res.json({ok: true})
})

 

终于在network中看到返回值了...接下来就要生成错误日志并保存到服务器了。照例开始查文档:http://nodejs.cn/api/fs.html。首先要引入文件系统(File System,就是下文的fs):

const fs = require('fs');

写文件的方法是writeFile,异步地写入数据到文件,如果文件已经存在,则覆盖文件。

fs.writeFile(file, data[, options], callback)

具体参数如下:

文件名加上时间戳,每次都生成一个新文件,点点点点,于是有了好多日志文件

贴一下代码:

// 捕获异常router.post('/getErr', (req, res) => {
  req.session.getErr = {err:req.body.err,hook:req.body.hook,userInfo:req.body.userInfo};
  let time = new Date();  // 记录错误内容  fs.writeFile(    'tm_wap_err_' + time.getTime() +'.txt',    '报错内容:' + req.session.getErr.err + '\r\n' +
    '所在钩子:' + req.session.getErr.hook + '\r\n' +
    '报错时间:' + time.toLocaleString() + '\r\n' +
    '用户信息:' + JSON.stringify(req.session.getErr.userInfo),
    (err) => {    if (err) throw err;
  });  // console.log(666,req.session.getErr);
  return res.json({ok: true});
})

这里我还记录了时间用户的登录状态。需求大体完成了,想办法优化一下,每次报错都生成一个新文件感觉太奢侈了,能不能搞个增量更新,统一记录在一个文件中?既方便查阅又省空间,还能练手,那就搞起来吧!大致思路如下:先判断文件是否存在,若不存在就创建一个。读取到文件内容以后再新加上跟新的内容,然后再写入。这种方式涉及到了I/O操作,但是相比增加很多文件还是会性能更好吧。最终代码如下:

// 捕获异常router.post('/getErr', (req, res) => {
  req.session.getErr = {
    err:req.body.err,
    hook:req.body.hook,
    userInfo:req.body.userInfo,
    url:req.body.url
  };
  let time = new Date();
  let content = '';  // 若文件不存在,就创建一个吧!
  fs.exists("toolmall_wap_err.txt", function(exists) {    if(!exists) {
      fs.writeFile('toolmall_wap_err.txt','', function(err) {        if(err) {          return console.log(err);
        }
      });
    }
  });  // 增量更新日志文件,先读取
  fs.readFile('toolmall_wap_err.txt','utf8',(err, data) => {    if (err) throw err;
    data += '\r\n';
    data += '报错内容:' + req.session.getErr.err + '\r\n';
    data += '所在钩子:' + req.session.getErr.hook + '\r\n';
    data += '报错时间:' + time.toLocaleString() + '\r\n';
    data += '报错页面:' + req.session.getErr.url + '\r\n';
    data += '用户信息:' + JSON.stringify(req.session.getErr.userInfo) + '\r\n';
    content = data;    // 记录错误内容    fs.writeFile(      'toolmall_wap_err.txt',
      content,
      (err) => {      if (err) throw err;
    });
  });  return res.json({ok: true});
})

最终成果如下:

以上是文件夹,放在了根目录下。

下面是日志的内容:


  • 2019-09-06 10:30:20

    ffmpeg错误码

    AVERROR_BSF_NOT_FOUND = -1179861752 AVERROR_BUG = -558323010 AVERROR_DECODER_NOT_FOUND = -1128613112 AVERROR_DEMUXER_NOT_FOUND = -1296385272 AVERROR_ENCODER_NOT_FOUND = -1129203192 AVERROR_EOF = -541478725 AVERROR_EXIT = -1414092869 AVERROR_FILTER_NOT_FOUND = -1279870712 AVERROR_INVALIDDATA = -1094995529 AVERROR_MUXER_NOT_FOUND = -1481985528 AVERROR_OPTION_NOT_FOUND = -1414549496 AVERROR_PATCHWELCOME = -1163346256 AVERROR_PROTOCOL_NOT_FOUND = -1330794744 AVERROR_STREAM_NOT_FOUND = -1381258232 AVERROR_BUG2 = -541545794 AVERROR_UNKNOWN = -1313558101

  • 2019-09-08 09:05:54

    MyBatis Generator 插件的拓展插件包

    应该说使用Mybatis就一定离不开MyBatis Generator这款代码生成插件,而这款插件自身还提供了插件拓展功能用于强化插件本身,官方已经提供了一些拓展插件,本项目的目的也是通过该插件机制来强化Mybatis Generator本身,方便和减少我们平时的代码开发量。

  • 2019-09-08 09:09:48

    mybatis-generator自动生成代码插件使用详解

      mybatis-generator是一款在使用mybatis框架时,自动生成model,dao和mapper的工具,很大程度上减少了业务开发人员的手动编码时间,今天自己研究了一下,也分享一下使用心得供大家简单使用。

  • 2019-09-08 15:09:14

    IDEA从mapper.java跳转到mapper.xml

    在IDEA中写项目后台的时候,从controller到service到mapper到dao,都可以直接跳转,但是mapper.java到mapper.xml就需要自行寻找,为了开发方便,安装相应插件--mybais

  • 2019-09-08 21:44:15

    git pre-commit hook failed 解决办法

    今天在上传项目的时候在commit阶段遇到一个问题,无论是在Sourcetree上传还是用命令git commit -m 'xxx'都报了一下错误:

  • 2019-09-08 21:45:31

    git index.lock

    因是在你进行某些比较费时的git操作时自动生成,操作结束后自动删除,相当于一个锁定文件,目的在于防止对一个目录同时进行多个操作。 有时强制关闭进行中的git操作,这个文件没有被自动删除,之后你就无法进行其他操作,必须手动删除,进入.git文件中删除,打开显示隐藏文件。如果没有看见.git文件夹,可以直接用命令rm -f ./.git/index.lock。之后就可以正常使用。 ———————————————— 版权声明:本文为CSDN博主「李瑞豪」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_39520417/article/details/81941111

  • 2019-09-09 05:28:54

    IntelliJ IDEA 进阶教程: 语言注入

    我真的太久没发 IntelliJ 的教程了,最近 Sakura 同学找我帮他配 IntelliJ ,我秀了一下技术,假装自己是老司机。 然后发现 Language Injection 这个非常好用的功能我居然没写教程(很明显,一堆人不知道这个东西), 于是我又开始写教程了。 本文多图。