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});
})

最終成果如下:

以上是文件夾,放在了根目錄下。

下面是日志的內容:

  終於完成了,今晚加雞腿~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM