Monitor what? Why the surveillance?

We must be familiar with the following:

What to monitor

Front-end monitoring content

Monitoring content

website

Install dependencies

yarn add bootstrap jquery koa koa-static
Copy the code
// Server koA
let Koa = require('koa');
let path = require('path');
let Server = require('koa-static');

let app = new Koa();

app.use(Server(path.join(__dirname, 'client')));  // Service access entry
app.use(Server(path.join(__dirname, 'node_modules')));  // Static resource path
app.listen(3000, () = > {console.log('server start at 3000')});Copy the code
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, "> <meta http-equiv=" x-UA-compatible "content=" IE =edge"> <title src='/bundle.js'></script> <link rel="stylesheet" href='/bootstrap/dist/css/bootstrap.css' /> </head> <body> <div Class ="text-center text-danger H2 "> </div> <script SRC ='/jquery/dist/jquery.js'></script> </body>Copy the code

monitor

Install dependencies

yarn add @babel/core @babel/preset-env rollup rollup-plugin-babel
Copy the code
// monitor/rollup.config.js
import babel from 'rollup-plugin-babel';
export default {
    input: './index.js'.output: {
        file: '.. /website/client/bundle.js'.format: 'umd'.// both AMD and CMD support
    },
    watch: {
        exclude: 'node_modules/**',},plugins: [
        babel({
            babelrc: false.presets: [
                '@babel/preset-env']]}})Copy the code

Performance monitoring

Performance monitoring: calculate the time difference DNS parsing DOM loading using the API provided by the browser performance; We can take advantage of the performance provided by the browser

Monitoring indicators

// monitor/performance.js
// Write page performance monitoring

let processData = (p) = > {
    let data = {
        prevPage: p.fetchStart - p.navigationStart, // The length from the previous page to this page
        redirect: p.redirectEnd - p.redirectStart,  // Redirection duration
        dns: p.domainLookupEnd - p.domainLookupStart,     // Duration of DNS resolution
        connect: p.connectEnd - p.connectStart,       // The duration of the TCP connection
        send: p.responseEnd - p.requestStart,         // The time from request to response
        ttfb: p.responseStart - p.navigationStart,  // The length of the first byte received tests how fast the server is
        domready: p.domInteractive - p.domLoading,    // The dom preparation time
        whiteScreen: p.domLoading - p.navigationStart, // Blank screen duration
        dom: p.domComplete - p.domLoading,   // Dom parsing duration
        load: p.loadEventEnd - p.loadEventStart, // Execution duration of onLoad
        total: p.loadEventEnd - p.navigationStart, / / total duration
    }
    return data;
}
// DOM loading is complete
let load = (cb) = > {
    let timer;
    let check = (a)= > {
        if (performance.timing.loadEventEnd) {
            clearTimeout(timer);
            cb();
        } else {
            timer = setTimeout(check, 100)}}window.addEventListener('load', check, false);
}
// Parsing is complete
let domready = (cb) = > {
    let timer;
    let check = (a)= > {
        if (performance.timing.loadEventEnd) {
            clearTimeout(timer);
            cb();
        } else {
            timer = setTimeout(check, 100)}}window.addEventListener('DOMContentLoaded', check, false);
}

export default {
    init(cb) {
        domready((a)= > { // It is possible that the onload is not triggered.
            let performanceData = processData(performance.timing);
            cb(performanceData)
        })
        load((a)= > {
            letperformanceData = processData(performance.timing); cb(performanceData) }); }}Copy the code
// monitor/index.js
import perf from './performance';
perf.init((data) = > {
    console.log(data)
});
Copy the code

Resource monitoring

// monitor/resource.js 
let processData = (_) = > {
    let data = {
        name: _.name,
        initiatorType: _.initiatorType,
        duration: _.duration,
    }
    return data;
}
export default {
    init(cb) {
        // Use PerformanceObserver one by one
        if (window.PerformanceObserver) {
            let observer = new PerformanceObserver((list) = > {
                let data = list.getEntries();
                cb(processData(data[0]))
            })
            observer.observe({ entryTypes: ['resource']})}else {
            window.onload = (a)= > {
                let resourceData = performance.getEntriesByType('resource');
                let data = resourceData.map(_= >processData(_)) cb(data); }}}}Copy the code
// monitor/index.js
// Resource loading information
import resource from './resource';

resource.init((data) = > {
    console.log(data);
});
Copy the code

Request to monitor

// Take XHR as an example
// monitor/xhr.js
export default {
    init(cb) {
        // Send the request XHR fetch
        let xhr = window.XMLHttpRequest;
        let oldOpen = xhr.prototype.open;
        xhr.prototype.open = function (method, url, async) {
            this.info = {
                method,
                url,
                async};return oldOpen.apply(this.arguments);
        }
        let oldSend = xhr.prototype.send;
        xhr.prototype.send = function (value) {
            let start = Date.now();
            // Process the corresponding information
            let fn = (type) = >() = > {this.info.time = Date.now() - start;
                this.info.requestSize = value && value.length || 0;
                this.info.responseSize = this.responseText.length;
                this.info.type = type;
                cb(this.info);
            }
            this.addEventListener('load', fn('load'), false);  / / success
            this.addEventListener('error', fn('error'), false); / / fail
            this.addEventListener('abort', fn('abort'), false); / / termination
            return oldSend.apply(this.arguments); }}}Copy the code
// monitor/index.js
// Resource loading information
import xhr from './xhr';

xhr.init((data) = > {
    console.log(data);
});
Copy the code
// website/client/main.js
$.ajax({
    method: 'GET'.url: '/app/list'.data: {
        name: 'mmm'.age: 18}})Copy the code

Error monitoring

// monitor/errCatch.js
export default {
    404 can be implemented with window.addEventListener('error', fn, true)
    // If a promise fails, it cannot pass onError, but can be captured through unhandledrejection
    // Unhandledrejection catches unhandled Promise errors:
    init(cb) {
        window.onerror = function (msg, url, lineNo, columnNo, error) {
            console.dir(error);
            let stack = error.stack;
            let matchUrl = stack.match(/http:\/\/[^\n]*/) [0];
            let fileName = matchUrl.match(/http:\/\/(? :\S*)\.js/) [0];
            let [, row, column] = matchUrl.match(/:(\d+):(\d+)/);
            let info = {
                message: error.message,
                name: error.name, matchUrl, fileName, row, column }; cb(info); }}}Copy the code
// monitor/index.js
// Error message
import errCatch from './errCatch';

errCatch.init((data) = > {
    console.log(data);
});
Copy the code
// website/client/main.js
console.log(mmm);
Copy the code