How to build the front end abnormal monitoring system

Time:2021-5-29

What is an exception

It means that users cannot get the expected results when using the application. Different anomalies have different degrees of consequences, which may cause users’ displeasure, or even the product can not be used, so that users lose their recognition of the product.

Why handle exceptions

  • Enhance user experience
  • Remote location problem
  • Unable to reproduce the problem, especially the mobile terminal, for various reasons, such as system version, model, etc

What’s wrong with the front end

abnormal frequency
JavaScript exception (syntax error, code error) often
Static resource loading exception (IMG, JS, CSS) occasionally
Ajax request exception occasionally
Promise exception less
Iframe exception less

How to catch exception

try-catch

Try catch can only catch synchronous running errors, but not syntax and asynchronous errors.

1. Synchronization error

try {
    kill;
} catch(err) {
    console.error('try: ', err);
}

result:try: ReferenceError: kill is not defined

2. Unable to catch syntax error

try {
    let name = '1;
} catch(err) {
    console.error('try: ', err);
}

result:Unterminated string constant

The compiler can prevent running syntax errors.

3. Unable to catch asynchronous error

try {
    setTimeout(() => {
        undefined.map(v => v);
    }, 1000);
} catch(err) {
    console.error('try: ', err);
}

result:Uncaught TypeError: Cannot read property 'map' of undefined

window.onerror

When JavaScript runtime errors (including syntax errors) occur, window will trigger an error event of the erroreevent interface and execute window. Onerror(). If the function returns true, the default event handler is prevented from executing.

1. Synchronization error

/**
*@ param {string} message error message
*@ param {string} source error file
*@ param {number} lineno line number
*@ param {number} colno column number
*@ param {object} error object
*/
window.onerror = (message, source, lineno, colno, error) => {
    Console. Error ('catch exception: ', message, source, lineno, colno, error');
    return true;
};

kill;

Results: uncaught referenceerror: kill is not defined

2. Unable to catch syntax error

/**
*@ param {string} message error message
*@ param {string} source error file
*@ param {number} lineno line number
*@ param {number} colno column number
*@ param {object} error object
*/
window.onerror = (message, source, lineno, colno, error) => {
    Console. Error ('catch exception: ', message, source, lineno, colno, error');
    return true;
};

let name = '1;

result:Unterminated string constant

The compiler can prevent running syntax errors.

3. Asynchronous error

/**
*@ param {string} message error message
*@ param {string} source error file
*@ param {number} lineno line number
*@ param {number} colno column number
*@ param {object} error object
*/
window.onerror = (message, source, lineno, colno, error) => {
    Console. Error ('catch exception: ', message, source, lineno, colno, error');
    return true;
};

setTimeout(() => {
    undefined.map(v => v);
}, 1000);

result:Catch exception: uncaught typeerror: cannot read property 'map' of undefined

window.addEventListener(‘error’)

When a resource (e.g<img>or<script>)If the loading fails, the element loading the resource will trigger an error event of the event interface and execute the onerror() handler on the element. These error events do not bubble up to the window, but (at least in Firefox) can be captured by a single window. Addeventlistener.

<script>
window.addEventListener('error', (err) => {
    Console. Error ('catch exception: ', error');
}, true);
</script>
<img />

result:Catch exception: Event  { isTrusted: true, type: "error", target: img, currentTarget: Window, eventPhase: 1,  …}

window.addEventListener(‘unhandledrejection’)

When the project is rejected and there is no reject processor, the unhandledresection event will be triggered; This can happen in windows, but it can also happen in workers. This is useful for debugging fallback error handling.

window.addEventListener("unhandledrejection", (err) => {
    err.preventDefault();
    Console. Error ('catch exception: ', error');
});

Promise.reject('promise');

result:Catch exception: Project rejection event  { isTrusted: true, promise: Promise, reason: "promise", type: "unhandledrejection", target: Window,  …}

Vue

Vue.config.errorHandler = (err, vm, info) => {
  Console. Error ('catch exception: ', error, VM, info');
}

React

React 16 provides a built-in functioncomponentDidCatchIt is very easy to get theReactError message under.

componentDidCatch(error, info) {
    Console. Error ('catch exception: ', error, info');
}

However, it is not recommendedErrorBoundary

JavaScript errors in the user interface should not destroy the entire application. In order to solve this problem for react users, react 16 introduces a new concept of “error boundary”.

newly buildErrorBoundary.jsxComponents:

import React from 'react';
import { Result, Button } from 'antd';

class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false, info: '' };
    }
  
    static getDerivedStateFromError(error) {
        return { hasError: true };
    }

    componentDidCatch(error, info) {
        this.setState({
            info: error + ''
        });
    }
  
    render() {
        if (this.state.hasError) {
            //You can render any custom degraded UI
            return (
                <Result
                    status="500"
                   
                    subTitle={this.state.info}
                    extra={<Button type="primary">Report feedback</Button>}
                />
            );
        }
  
        return this.props.children; 
    }
}

export default ErrorBoundary;

use:

<ErrorBoundary>
    <App />
</ErrorBoundary>

be careful

Error bounds do not catch errors in the following areas:

  • Event handler
  • Asynchronous code (such as setTimeout or requestanimationframe callbacks)
  • Server side rendering
  • An error raised in the error boundary itself rather than its children

iframe

Due to the “same origin policy” set by the browser, the iframe exception can not be handled very gracefully. Besides the basic properties (such as its width and height), a lot of information can not be obtained from the iframe.

<script>
    document.getElementById("myiframe").onload = () => {
        const self = document.getElementById('myiframe');
        
        try {
            (self.contentWindow || self.contentDocument).location.href;
        } catch(err) {
            Console.log ('catch exception: '+ err');
        }
    };
</script>

<iframe id="myiframe" frameBorder="0" />

Sentry

The industry is a very excellent abnormal monitoring products, the author is also using this, complete documentation.

What information needs to be reported

  • Error ID
  • User ID
  • user name
  • User IP
  • equipment
  • error message
  • Tourist device
  • System version
  • Application version
  • model
  • time stamp
  • Exception level (error, warning, info)

Abnormal Report

1. Ajax sends data
2. Creating img tags dynamically

If the amount of abnormal data is large and the server load is high, adjust the sending frequency (consider storing the abnormal information in the client, setting the time threshold, and reporting) or set the collection rate (the collection rate should be set according to the actual situation, random number or some user characteristics are good choices).

flow chart

How to build the front end abnormal monitoring system

Blog

Welcome to my blog

reference

  • How to handle the front end exception gracefully?
  • React
  • MDN
  • Vue