How to build a front-end exception monitoring system

what is abnormal

It means that when users use the application, they cannot get the expected results. Different anomalies have different consequences, ranging from causing dissatisfaction to the user, to causing the product to be unusable and causing the user to lose recognition of the product.

Why handle exceptions

  • Enhance user experience
  • remote location problem
  • The problem cannot be reproduced, especially on the mobile side, for various reasons, it may be the system version, model, etc.

What are the exceptions in the front end

abnormal frequency
JavaScript exceptions (syntax errors, code errors) often
Static resource loading exception (img, js, css) Occasionally
Ajax request exception Occasionally
promise exception less
iframe exception less

How to catch exceptions

try-catch

try-catchOnly synchronous runtime errors can be caught, but syntax and asynchronous errors cannot be caught.

1. Synchronous operation error

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

result:try: ReferenceError: kill is not defined

2. Unable to catch syntax errors

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

result:Unterminated string constant

The compiler is able to prevent syntax errors from running.

3. Unable to catch asynchronous errors

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 JavaScripta runtime error (including a syntax error) occurs, an event of the interface windowis fired , and if the function returns , the default event handler function is prevented from being executed.ErrorEventerrorwindow.onerror()true

1. Synchronous operation error

/**
* @param {String}  message   错误信息
* @param {String}  source    出错文件
* @param {Number}  lineno    行号
* @param {Number}  colno     列号
* @param {Object}  error     error对象
*/
window.onerror = (message, source, lineno, colno, error) => {
    console.error('捕获异常:', message, source, lineno, colno, error);
    return true;
};

kill;

Result: Exception caught:Uncaught ReferenceError: kill is not defined

2. Unable to catch syntax errors

/**
* @param {String}  message   错误信息
* @param {String}  source    出错文件
* @param {Number}  lineno    行号
* @param {Number}  colno     列号
* @param {Object}  error     error对象
*/
window.onerror = (message, source, lineno, colno, error) => {
    console.error('捕获异常:', message, source, lineno, colno, error);
    return true;
};

let name = '1;

result:Unterminated string constant

The compiler is able to prevent syntax errors from running.

3. Asynchronous errors

/**
* @param {String}  message   错误信息
* @param {String}  source    出错文件
* @param {Number}  lineno    行号
* @param {Number}  colno     列号
* @param {Object}  error     error对象
*/
window.onerror = (message, source, lineno, colno, error) => {
    console.error('捕获异常:', message, source, lineno, colno, error);
    return true;
};

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

Result: 捕获异常: Uncaught TypeError: Cannot read property 'map' of undefined`

window.addEventListener(‘error’)

When a resource (such as <img>or <script>) fails to load, the element that loaded the resource will trigger an event Eventof the interface , and execute the processing function erroron the element . onerror()These errorevents do not bubble up window, but (at least in Firefox) can be caught by a windowsingle addEventListener.

<script>
window.addEventListener('error', (err) => {
    console.error('捕获异常:', err);
}, true);
</script>
<img src="./test.jpg" />

result:捕获异常:Event {isTrusted: true, type: "error", target: img, currentTarget: Window, eventPhase: 1, …}

window.addEventListener(‘unhandledrejection’)

The event is fired when a is called and has no handlers ; Promisethis rejectcan happen under , but it can also happen inside . This is useful for debugging fallback error handling.rejectunhandledrejectionwindowWorker

window.addEventListener("unhandledrejection", (err) => {
    err.preventDefault();
    console.error('捕获异常:', err);
});

Promise.reject('promise');

result:捕获异常:PromiseRejectionEvent {isTrusted: true, promise: Promise, reason: "promise", type: "unhandledrejection", target: Window, …}

Vue

Vue.config.errorHandler = (err, vm, info) => {
  console.error('捕获异常:', err, vm, info);
}

React

React16, provides a built-in function componentDidCatch, which can be used to get the error message under very simply React.

componentDidCatch(error, info) {
    console.error('捕获异常:', error, info);
}

However, it is recommendedErrorBoundary

Bugs in the user interface JavaScriptshould not break the entire application. To Reactsolve this problem for users, React16a new concept of "error boundaries" is introduced.

New ErrorBoundary.jsxcomponent:

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) {
            // 你可以渲染任何自定义的降级 UI
            return (
                <Result
                    status="500"
                    title="500"
                    subTitle={this.state.info}
                    extra={<Button type="primary">Report feedback</Button>}
                />
            );
        }

        return this.props.children;
    }
}

export default ErrorBoundary;

use:

<ErrorBoundary>
    <App />
</ErrorBoundary>

Notice

Error boundaries do not catch errors in:

  • event handler
  • Asynchronous code (such as setTimeoutor requestAnimationFramecallbacks)
  • server-side rendering
  • Errors raised within the error boundary itself (rather than its children)

iframe

Due to the "same-origin policy" set by the browser, exceptions cannot be handled very gracefully iframe, and except for basic properties (such as its width and height), it is impossible to iframeobtain a lot of information from .

<script>
    document.getElementById("myiframe").onload = () => {
        const self = document.getElementById('myiframe');

        try {
            (self.contentWindow || self.contentDocument).location.href;
        } catch(err) {
            console.log('捕获异常:' + err);
        }
    };
</script>

<iframe id="myiframe" src="https://nibuzhidao.com" frameBorder="0" />

Sentry

It is a very excellent monitoring exception product in the industry, which is also used by the author, with complete documentation.

What information needs to be reported

  • error id
  • user id
  • username
  • User IP
  • equipment
  • error message
  • browser
  • system version
  • App version
  • model
  • timestamp
  • Exception level (error, warning, info)

Exception reporting

1. Ajax sends data

2. Dynamically create img tags

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

flow chart

Abnormal monitoring flow chart

References

blog

Welcome to follow my blog

Guess you like

Origin blog.csdn.net/weixin_42439919/article/details/107136424