preface
As the company’s business grew, so did the front-end projects. Sometimes a customer feedback a problem, need to spend a lot of time to check. Error information is not the first time to obtain, how much will bring losses to the company. At this point, we need a bug collection mechanism to find problems in the code in advance and deal with them before the customer feedback. Or when receiving customer feedback, we can find the corresponding error stack to help us quickly locate and solve the problem. The following mainly introduces vue and wechat small program error collection methods.
Error collection method
Vue error collection
Vue provides a global configuration errorHandler to collect errors that occur while Vue is running. API cn.vuejs.org/v2/api/#err…
Usage:
Vue.config.errorHandler = function (err, vm, info) {
// handle error
// 'err' is the js error stack information, you can get the specific JS error location.
/ / ` vm ` vue instance
// 'info' is Vue specific error information, such as the lifecycle hook where the error occurred
// Only available in 2.2.0+
}
Copy the code
Of course, once we get the vUE instance, we can easily get the vUE component name, custom properties and so on (free play here).
Here’s how to get the component name: (source: fundebug)
function formatComponentName(vm) {
if (vm.$root === vm) return 'root';
var name = vm._isVue
? (vm.$options && vm.$options.name) ||
(vm.$options && vm.$options._componentTag)
: vm.name;
return (
(name ? 'component <' + name + '>' : 'anonymous component') +
(vm._isVue && vm.$options && vm.$options.__file
? ' at ' + (vm.$options && vm.$options.__file)
: ' ')); }Copy the code
At this point our code can be rewritten like this:
Vue.config.errorHandler = function(err, vm, info) {
if (vm) {
var componentName = formatComponentName(vm);
// Invoke the error log collection interface
} else {
// Invoke the error log collection interface}};Copy the code
Now that you know how to collect error information, you can simply wrap it up and apply it to your project. (Of course, you also need an interface for storing and displaying error messages. There are some mature logging frameworks on the web, such as ELK.)
Create a new file, debug.js
let debugConfig = {
Vue: null.// Project name
entryName: 'entryName'.// Script version
scriptVersion: '1.0'./ / environment
releaseStage: 'pro'
},
debug = {
notifyWarn({ message, metaData }) {
let type = 'caught',
severity = 'warn';
_logReport({ type, severity, message, metaData });
},
notifyError({ type = 'caught', error, message, metaData, lineNumber, columnNumber, fileName }){
let severity = 'error'; _logReport({ type, severity, error, metaData, message, lineNumber, columnNumber, fileName }); }};// Logs are reported
function _logReport({ type, severity, error, metaData, message, lineNumber, columnNumber, fileName }) {
let { silentDev, Vue } = debugConfig;
message = message || error && error.message || ' ';
// We can do a grayscale control here
let { entryName, releaseStage, severity, scriptVersion } = debugConfig,
name = error && error.name || 'error',
stacktrace = error && error.stack || ' ',
time = Date.now(),
title = document.title,
url = window.location.href,
client = {
userAgent: window.navigator.userAgent,
height: window.screen.height,
width: window.screen.width,
referrer: window.document.referrer
},
pageLevel = 'p4';
// Here you can rank your pages
pageLevel = 'p0';//getPageLevel();
// The HTTP request here uses vue-resource, which can be adjusted to suit your situation
Vue.http.post(logReportUrl, {
entryName,
scriptVersion,
message,
metaData,
name,
releaseStage,
severity,
stacktrace,
time,
title,
type,
url,
client,
lineNumber,
columnNumber,
fileName,
pageLevel// Page level
});
}
export default function(Vue, option = {}){
debugConfig = Object.assign(debugConfig, { Vue, ... option });// If you want to avoid catching error messages in the development environment, you can add environment judgment here
function formatComponentName(vm) {
if (vm.$root === vm) return 'root';
let name = vm._isVue
? (vm.$options && vm.$options.name) ||
(vm.$options && vm.$options._componentTag)
: vm.name;
return (
(name ? 'component <' + name + '>' : 'anonymous component') +
(vm._isVue && vm.$options && vm.$options.__file
? ' at ' + (vm.$options && vm.$options.__file)
: ' ')); } Vue.config.errorHandler =function(err, vm, info) {
if (vm) {
let componentName = formatComponentName(vm);
let propsData = vm.$options && vm.$options.propsData;
debug.notifyError({
error: err,
metaData: {
componentName,
propsData,
info,
userToken: { userId: 1 }//metaData stores additional data, such as user information}}); }else {
debug.notifyError({
error: err,
metaData: {
userToken: { userId: 1 }//metaData stores additional data, such as user information}}); }};window.onerror = function(msg, url, lineNo, columnNo, error) {
debug.notifyError({
type: 'uncaught',
error,
metaData: {
userToken: { userId: 1 }//metaData stores additional data, such as user information
},
message: msg,
lineNumber: lineNo,
columnNumber: columnNo,
fileName: url }); }}// Finally we throw debug out for call elsewhere
export { debug }
Copy the code
You can also catch exceptions like promises, network requests, images, and so on. Here recommend a more complete article, we can go to see juejin.cn/post/684490…
Initialization:
// Error log collection import debug from'./debug'; Vue. Use (debug, {entryName:'webmall' });
Copy the code
If you want to report an error yourself, you can do so by:
import { debug } from './debug';
debug.notifyError({ messag: 'An error has occurred' });
Copy the code
Wechat applets error collection
It is also convenient for wechat applet to collect error information. It only needs to implement onError method in the object passed in when calling App function. Address: document developers.weixin.qq.com/miniprogram…
Usage:
App({
onError (msg) {
console.log(msg);// MSG is an error message}})Copy the code
If you want to make your code more portable you can do this:
// Store the App temporarily
let _App = App;
function HookParams(_appParams, eventName, eventFn) {
if (_appParams[eventName]) {
let _eventFn = _appParams[eventName];
// If the onError function already exists in the argument, keep and add the error collection
_appParams[eventName] = function (error) {
eventFn.call(this, error, eventName);
return _eventFn.call.apply(_eventFn, [this].concat(Array.prototype.slice.call(arguments)))}}else {
// If the onError function does not exist, it is easier to define one and add the error collection
_appParams[eventName] = function (error) {
eventFn.call(this, error, eventName)
}
}
}
function onErrorFn(error, eventName) {
// Collection error
}
App = function (_appParams) {
HookParams(_appParams, "onError", onErrorFn);
_App(_appParams);
};
Copy the code
The principle is actually very simple, by rewriting the App function, and then through Hook means to deal with the incoming parameters.
Again, now that we know how to collect errors, we can simply wrap up our code.
Create a new file, debug.js
function HookParams(_appParams, eventName, eventFn) {
if (_appParams[eventName]) {
let _eventFn = _appParams[eventName];
_appParams[eventName] = function (error) {
eventFn.call(this, error, eventName);
return _eventFn.call.apply(_eventFn, [this].concat(Array.prototype.slice.call(arguments)))}}else {
_appParams[eventName] = function (error) {
eventFn.call(this, error, eventName)
}
}
}
function objToParam(options = {}) {
let params = ' ';
for (let key in options) {
params += '&' + key + '=' + options[key];
}
return params.substring(1);
}
function onErrorFn(error, eventName) {
_logReport(error);
}
// Store the App temporarily
let _App = App;
App = function (_appParams) {
HookParams(_appParams, "onError", onErrorFn);
_App(_appParams);
};
//config
let debugConfig = {
entryName: 'entryName'.releaseStage: 'pro'.scriptVersion: '1.0'.client: {}}// Obtain device information
wx.getSystemInfo({
success: function (res) { debugConfig.client = res; }});/ / assembled postData
function getPostData(error = ' ') {
let {
entryName,
releaseStage,
scriptVersion,
client
} = debugConfig,
curPage = getCurrentPages()[getCurrentPages().length - 1],
url = ' ',
urlParams = ' ',
name = 'error',
postData = "postData",
metaData = {},
pageLevel = 'p0';
/ / processing the url
if (curPage) {
url = curPage.route;
// Here you grade the page according to the actual project
pageLevel = 'p0'; //getPageLevel(url);
urlParams = objToParam(curPage.options);
if (urlParams) {
url += '? ' + urlParams;
}
}
name = error.split('\n') [0] | |'error';
metaData = {
userToken: getHeaders()
}
try {
postData = {
data: JSON.stringify({
entryName,
type: 'caught',
scriptVersion,
releaseStage,
name,
stacktrace: error,
time: Date.now(),
client,
url,
metaData,
pageLevel,
serviceLevel
})
};
} catch (e) {
console.error(e);
}
return postData;
}
// Control error sending
function _logReport(error) {
// grayscale control automatically add
wx.request({
header: {
'content-type': 'application/x-www-form-urlencoded'
},
method: 'POST'.url: logReportUrl,
data: getPostData(error)
});
}
let debug = {
init(option = {}) {
debugConfig = Object.assign({}, debugConfig, option);
},
notifyError(error) {
_logReport(error)
}
}
module.exports = debug;
Copy the code
Modify the app. Js:
import debug from './utils/debug.js';
/ / initialization
debug.init({
entryName: 'mall-wxapp'.scriptVersion: '2.6.3'
})
Copy the code
Manual error reporting
import debug from './utils/debug.js';
debug.notifyError('Error ~');
Copy the code
Applets have a few special points to look at:
1. Get device information from wx.getSystemInfo. Of course, you can also get user information from wx.getUserInfo.
2, small program complete links need to be self-assembled through the page options property.
reference
Collect field reference
{"entryName":" project name ", "ScriptVersion ":"1.0",// scriptVersion" message":"aler is not defined",// error description "metaData":{// custom field "componentName":"anonymous" Component at/Users/taoxinhua/git/webmall/SRC/components/app. Vue ", / / component name "info", "created the hooks", / / the vue error message "UserToken ":{// User login information "user_id": 1}}, "name" : "ReferenceError," name "releaseStage" / / error: "local", / / an error environment pre | beta | local "stacktrace" : "ReferenceError: aler is not defined at VueComponent.created (webpack-internal:///370:32:9) at callHook (webpack-internal:///1:2666:21) at VueComponent.Vue._init (webpack-internal:///1:4227:5) at new VueComponent (webpack-internal:///1:4397:12) at createComponentInstanceForVnode (webpack-internal:///1:3679:10) at init (webpack-internal:///1:3496:45) at createComponent (webpack-internal:///1:5148:9) at createElm (webpack-internal:///1:5091:9) at Vue$3.patch [as __patch__] (webpack-internal:// 1:5607:9) at Vue$3.vue. _update (webpack-internal:// 1:2415:19)",// Error stack "Time ":1544437068009,// Client time when an error occurs "title":" page title",// Page title" type":"caught",// Refer to fundebug for the error type "Url" : "http://localhost:3200/test", / / page address "client" : {/ / client information "userAgent" : "Mozilla / 5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", "height":800, "Width" : 1280, "the referrer" : "http://localhost:3200/test"}, "pageLevel" : "p4" / / level of a page fault, convenient query bug} and prioritize the main pageCopy the code
Easier to use log collection system
If your system is small and you want to use it for free, try Fundebug.
conclusion
Front-end error collection is relatively simple, how to make good use of these collected errors need to slowly consider themselves. If there is anything wrong with the article, please point it out in the comments section.