Shallow in shallow out front monitoring system landing

background

Unlike Java and other back-end languages, front-end code runs on its own server, where errors can be directly captured and logged. Front-end code runs on the client, and front-end engineers cannot know when errors occur.

This is how front-end developers get client error messages before the system is applied:

As a qualified front-end engineer, serious and responsible attitude for project (technical), developed a front-end monitoring system, on the one hand, can promote the project more perfect, increases the user experience, on the other hand, the study of error trapping mechanism, can let us know about JavaScript is the language more.

architecture

  • The front-end SDK

TypeScript is used to develop the code specification, gulp is used as the code packaging and compression tool, and the code is constructed and uploaded to NPM for front-end business use.

Some main API implementations of SDK:

  1. For front-end resources, IMG, CSS, script and other error capture
window.addEventListener('error'.function (e) {
  let errorData = {
    errorType: 'resource'.msg: e.target['localName'].target: e.target['localName'].type: e.type,
    resourceUrl: e.target['href'] || e.target['currentSrc'] || e.target['src']}; },true);
Copy the code
  1. Capture of front-end syntax errors
window.onerror = function (msg, _url, line, col, error) {
  setTimeout(function () {
    col = col || (window.event && window.event['errorCharacter') | |0;
    let errorData = {
      errorType: 'grammar'.msg: error && error.stack ? error.stack.toString() : msg,
      resourceUrl: _url,
      line: line,
      col: col,
    }
  };
};
Copy the code
  1. The capture of a promise error
window.addEventListener('unhandledrejection'.function (e) {
	let  resourceUrl,
          col,
          line,
          error = e && e.reason,
          message = error.message || ' ',
          stack = error.stack || ' ',
          errs = stack.match(/ \ (. +? \) /);

    if (errs && errs.length) errs = errs[0];
    errs = errs.replace(/\w.+[js|html]/g, $1 => { resourceUrl = $1; return ' '; });
    errs = errs.split(':');
    if (errs && errs.length > 1) line = parseInt(errs[1] | |0);
    col = parseInt(errs[2] | |0);
    let errorData = {
      errorType: 'grammar'.msg: message,
      resourceUrl: resourceUrl,
      line: col,
      col: line,
      type: e.type
    }
})
Copy the code
  1. Ajax error capture

Although xhr.readyState === 4 is written in the comment, it is particularly important to identify successful but abnormal results of the interface

 _Ajax({
   onreadystatechange: function (xhr) {
      if (xhr.readyState === 4 && xhr.xhr.status === 200) {
         // The interface is successful, but the result is abnormal
      }else if(xhr.readyState === 4&& xhr.xhr.status ! = =200) {}},onerror: function (xhr) {
      ajaxResponse(xhr)
   },
   onload: function (xhr) {
      if (xhr.readyState === 4) {
          if (xhr.status < 200 || xhr.status > 300) {
              xhr.method = xhr.args.method
      	  }
      }
   },
   open: function (arg, xhr) {
      let result = { url: arg[1].split('? ') [0].method: arg[0] | |'GET'.type: 'xmlhttprequest' }
      this.args = result
   }
})

/ / ajax rewrite
function _Ajax(proxy) {
  window['_ahrealxhr'] = window['_ahrealxhr'] || XMLHttpRequest;

  //@ts-ignore
  XMLHttpRequest = function () {
    this.xhr = new window['_ahrealxhr'];
    for (var attr in this.xhr) {
       var type = "";
       try {
          type = typeof this.xhr[attr]
       } catch (e) { }
       if (type === "function") {
          this[attr] = hookfun(attr);
       } else {
          Object.defineProperty(this, attr, {
            get: getFactory(attr),
            set: setFactory(attr)
         })
       }
    }
  }

  function getFactory(attr) {
     return function () {
        var v = this.hasOwnProperty(attr + "_")?this[attr + "_"] : this.xhr[attr];
        var attrGetterHook = (proxy[attr] || {})["getter"]
        return attrGetterHook && attrGetterHook(v, this) || v
      }
  }

  function setFactory(attr) {
      return function (v) {
        var xhr = this.xhr;
        var that = this;
        var hook = proxy[attr];
        if (typeof hook === "function") {
          xhr[attr] = function () {
             proxy[attr](that) || v.apply(xhr, arguments); }}else {
          var attrSetterHook = (hook || {})["setter"];
          v = attrSetterHook && attrSetterHook(v, that) || v
          try {
             xhr[attr] = v;
          } catch (e) {
              this[attr + "_"] = v; }}}}function hookfun(fun) {
       return function () {
          var args = [].slice.call(arguments)
          if (proxy[fun] && proxy[fun].call(this, args, this.xhr)) {
             return;
          }
          return this.xhr[fun].apply(this.xhr, args); }}return window['_ahrealxhr'];
}
Copy the code
  1. Data reporting:
//1. Use the image SRC to report data
let sendData = new Image();
secdData.src = `The ${address? Data}`

/ / 2. Use the Navigator. SendBeacon
Copy the code
  • NodeJS server

Using the classic MVC structure, the framework uses KOA2, PM2 process daemon, data storage using MySQL

  • Manage Background React

Use react as the admin background

conclusion

This kind of business support service, originated from individual interest and thinking, does not have the large company resources to coordinate, also does not have the pressure from the top. I want to do the project, with more autonomy, always want to soon the first version can be online, thanks to the front of the students JGT (name pinyin abbreviation) encouragement and cooperation.

At present, the first version has been launched stably, serving many businesses of the company. There are still details to be optimized in the future, and some new ideas will be added.

If there is any mistake or not precise place, please be sure to give correction, thank you very much. If you like it or are inspired by it, welcome star Github, which is also an encouragement to the author.