前端錯誤日誌收集方案

前言

公司的項目上線出現問題後難以定位錯誤,研究過現存的錯誤監控方案,受限於特殊條件只能定製本身的錯誤收集方案。javascript

基於以上背景我擼出來一個錯誤日誌收集方案 - Ohbugphp

歡迎各位大佬 star ~css

監控錯誤

提及錯誤的捕獲,首先想到的是 try catch ,經過 catch 捕獲到錯誤後進一步作出處理html

try {
  undefined.map(v => v);
} catch(e) {
  console.log(e); // TypeError: Cannot read property 'map' of undefined
}
複製代碼

然而 try catch 對於異步產生的錯誤毫無感知前端

try {
  setTimeout(() => {
    undefined.map(v => v);
  }, 1000)
} catch(e) {
  console.log(e); // TypeError: Cannot read property 'map' of undefined
}
複製代碼

而且在實際工做中我也不可能給全部代碼加上 try catch,因此可否捕獲全局的錯誤呢?vue

react componentDidCatch

React 16 提供了一個內置函數 componentDidCatch,使用它能夠很是簡單的獲取到 react 下的錯誤信息java

componentDidCatch(error, info) {     
  console.log(error, info);
}
複製代碼

React 16 的異常/錯誤處理react

vue errorHandler

指定組件的渲染和觀察期間未捕獲錯誤的處理函數。這個處理函數被調用時,可獲取錯誤信息和 Vue 實例。ios

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的錯誤信息,好比錯誤所在的生命週期鉤子
  // 只在 2.2.0+ 可用
}
複製代碼

errorHandlerc++

onerror vs addEventListener

對於沒有使用 react 或 vue 的項目能夠經過 onerroraddEventListener 監控全局錯誤(固然使用 react 或 vue 的項目一樣能夠)

onerroraddEventListener 均可以捕獲到一些未知的錯誤,然而這兩個有什麼區別呢?

window.onerror = (msg, url, row, col, error) => {
  console.log({msg, url, row, col, error});
};
setTimeout(() => {
  undefined.map(v => v);
}, 1000);
複製代碼

onerror

window.addEventListener('error', (e) => {
  console.log(e);
}, true);
複製代碼

addEventListener

除此以外,addEventListener 還能夠捕獲資源加載錯誤、未 catch 的 promise 錯誤。

img

// 捕獲未 catch 的 promise 錯誤
window.addEventListener("unhandledrejection", e => {
  e.preventDefault();
  console.log(e);
});
Promise.reject('promiseError');
複製代碼

promise

ajax/fetch 錯誤監控

想要監控請求失敗,上面的方法確定是不可取的了。

使用 axios 的小夥伴能夠經過配置攔截器實現錯誤的監控。

// 添加請求攔截器
axios.interceptors.request.use(function (config) {
    // 在發送請求以前作些什麼
    return config;
  }, function (error) {
    // 對請求錯誤作些什麼
    return Promise.reject(error);
  });

// 添加響應攔截器
axios.interceptors.response.use(function (response) {
    // 對響應數據作點什麼
    return response;
  }, function (error) {
    // 對響應錯誤作點什麼
    return Promise.reject(error);
  });
複製代碼

這裏我採用了從新封裝 XMLHttpRequest/fetch 對象的方法實現對網絡請求的監控。

XMLHttpRequest

const AJAX = {
  // 記錄請求的 url
  reqUrl: '',
  // 記錄請求的方法
  reqMethod: '',
  // 保存原生的 open 方法
  xhrOpen: window.XMLHttpRequest.prototype.open,
  // 保存原生的 send 方法
  xhrSend: window.XMLHttpRequest.prototype.send,
  init() {
    const that = this;

    window.XMLHttpRequest.prototype.open = function () {
      that.reqUrl = arguments[1];
      that.reqMethod = arguments[0];
      that.xhrOpen.apply(this, arguments);
    };

    window.XMLHttpRequest.prototype.send = function () {
      this.addEventListener('readystatechange', function () {
        if (this.readyState === 4) {
          if (!this.status || this.status >= 400) {
            // 錯誤收集
          }
        }
      });

      that.xhrSend.apply(this, arguments);
    };
  },
};
AJAX.init();
複製代碼

fetch

const FETCH = {
  backup: window.fetch,
  init() {
    window.fetch = function (url, conf) {
      return (
        FETCH.backup.apply(this, arguments)
          .then((res) => {
            if (!res.status || res.status >= 400) {
              // 錯誤收集
            }
            return res;
          })
      );
    };
  },
};
FETCH.init();
複製代碼

待實現功能

  1. 捕獲websocket錯誤
  2. 設置採集率
  3. sourcemap定位壓縮代碼具體錯誤位置

參考文章

相關文章
相關標籤/搜索