preface

It was difficult to locate errors after problems occurred in the company’s project launching. After studying existing error monitoring schemes, the company could only customize its own error collection scheme due to special conditions.

Based on the above background, I developed an error log collection solution – Ohbug.

Welcome to star

Monitoring error

When it comes to error catching, the first thing that comes to mind is a try catch

try {
  undefined.map(v= > v);
} catch(e) {
  console.log(e); // TypeError: Cannot read property 'map' of undefined
}
Copy the code

However, try catch has no awareness of asynchronous errors

try {
  setTimeout((a)= > {
    undefined.map(v= > v);
  }, 1000)}catch(e) {
  console.log(e); // TypeError: Cannot read property 'map' of undefined
}
Copy the code

And in practice, I can’t put a try catch on all my code, so can I catch a global error?

react componentDidCatch

React 16 provides a built-in function componentDidCatch, which is very easy to use to get React error information

componentDidCatch(error, info) {     
  console.log(error, info);
}
Copy the code

React 16 Exception/error handling

vue errorHandler

Specifies a handler that does not catch errors during rendering and viewing of the component. When this handler is called, it gets an error message and a Vue instance.

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // 'info' is Vue specific error information, such as the lifecycle hook where the error occurred
  // Only available in 2.2.0+
}
Copy the code

errorHandler

onerror vs addEventListener

For projects that do not use React or Vue, you can use onError or addEventListener to monitor global errors (the same applies to projects that use React or Vue).

Onerror or addEventListener can catch unknown errors, but what’s the difference?

window.onerror = (msg, url, row, col, error) = > {
  console.log({msg, url, row, col, error});
};
setTimeout((a)= > {
  undefined.map(v= > v);
}, 1000);
Copy the code

window.addEventListener('error', (e) => {
  console.log(e);
}, true);
Copy the code

In addition, addEventListener can catch resource loading errors and uncaught promise errors.

// Catch an uncaught promise error
window.addEventListener("unhandledrejection", e => {
  e.preventDefault();
  console.log(e);
});
Promise.reject('promiseError');
Copy the code

Ajax/FETCH error monitoring

If you want to monitor requests for failure, the above approach is definitely not desirable.

Users of Axios can configure interceptors to detect errors.

// Add request interceptor
axios.interceptors.request.use(function (config) {
    // What to do before sending the request
    return config;
  }, function (error) {
    // What to do about the request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // What to do with the response data
    return response;
  }, function (error) {
    // Do something about the response error
    return Promise.reject(error);
  });
Copy the code

Here I use the method of repackaging XMLHttpRequest/fetch object to realize the monitoring of network requests.

XMLHttpRequest

const AJAX = {
  // Record the requested URL
  reqUrl: ' '.// Record the request method
  reqMethod: ' '.// Save the native open method
  xhrOpen: window.XMLHttpRequest.prototype.open,
  // Save the native send method
  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) {
            // Error collection}}}); that.xhrSend.apply(this.arguments); }; }}; AJAX.init();Copy the code

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) {
              // Error collection
            }
            returnres; })); }; }}; FETCH.init();Copy the code

Function to be implemented

  1. Catch websocket error
  2. Setting the Collection Rate
  3. Sourcemap locates specific errors in compression code

Refer to the article

  • Front-end code abnormal monitoring actual combat
  • Js error monitoring
  • Front-end one-stop exception capture scheme (full)