предисловие
С развитием бизнеса компании появляется все больше фронтенд-проектов. Иногда требуется много времени, чтобы исследовать проблему, о которой говорят клиенты. Если неверная информация не может быть получена с первого раза, это в какой-то степени принесет компании убытки. В настоящее время нам нужен набор механизмов сбора ошибок, чтобы заблаговременно обнаруживать проблемы в коде и решать проблемы заранее, до получения отзывов от клиентов. Или, получая отзывы клиентов, вы можете найти соответствующий стек ошибок, чтобы помочь нам быстро найти и решить проблему. Далее в основном представлен метод сбора ошибок апплетов Vue и WeChat.
метод сбора ошибок
Коллекция ошибок Vue
Vue предоставляет глобальную конфигурацию errorHandler для сбора ошибок, возникающих при работе Vue. подробно APITalent.v UE JS.org/V2/API/#two…
Применение:
Vue.config.errorHandler = function (err, vm, info) {
// handle error
//`err`是js错误栈信息,可以获取到具体的js报错位置。
//`vm` vue实例
//`info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
// 只在 2.2.0+ 可用
}
Конечно, после получения экземпляра, соответствующего Vue, мы можем легко получить имя компонента и пользовательские атрибуты, соответствующие Vue (вы можете свободно играть здесь).
Вот как получить имя компонента: (источник: 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)
: '')
);
}
На данный момент наш код можно переписать так:
Vue.config.errorHandler = function(err, vm, info) {
if (vm) {
var componentName = formatComponentName(vm);
//调用错误日志收集接口
} else {
//调用错误日志收集接口
}
};
Зная, как собирать информацию об ошибках, вам достаточно просто обернуть ее и применить к проекту. (Конечно, вам также нужен интерфейс для сохранения информации об ошибках и интерфейс для отображения информации об ошибках. В Интернете также есть несколько зрелых фреймворков для обработки журналов, например: ELK)
создать новый файлdebug.js
let debugConfig = {
Vue: null,
//项目名称
entryName: 'entryName',
//脚本版本
scriptVersion: '1.0',
// 环境
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 });
}
};
// 日志上报
function _logReport({ type, severity, error, metaData, message, lineNumber, columnNumber, fileName }) {
let { silentDev, Vue } = debugConfig;
message = message || error && error.message || '';
//这里可以做一个灰度控制
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';
//此处可以给你的页面进行分级
pageLevel = 'p0';//getPageLevel();
//此处http请求使用的是vue-resource,可以根据各自的情况进行调整
Vue.http.post(logReportUrl, {
entryName,
scriptVersion,
message,
metaData,
name,
releaseStage,
severity,
stacktrace,
time,
title,
type,
url,
client,
lineNumber,
columnNumber,
fileName,
pageLevel//页面等级
});
}
export default function(Vue, option = {}){
debugConfig = Object.assign(debugConfig, { Vue, ...option });
//如果你想在开发环境不去捕获错误信息 可以在此处加上环境判断
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可以存一些额外数据,比如:用户信息等
}
});
} else {
debug.notifyError({
error: err,
metaData: {
userToken: { userId: 1 }//metaData可以存一些额外数据,比如:用户信息等
}
});
}
};
window.onerror = function(msg, url, lineNo, columnNo, error) {
debug.notifyError({
type: 'uncaught',
error,
metaData: {
userToken: { userId: 1 }//metaData可以存一些额外数据,比如:用户信息等
},
message: msg,
lineNumber: lineNo,
columnNumber: columnNo,
fileName: url
});
}
}
//最后我们把debug抛到外面供其他地方调用
export { debug }
Конечно, вы также можете перехватывать исключения, такие как промисы, сетевые запросы, изображения и т. д. Здесь рекомендуется относительно полная статья, можете проверить самиnuggets.capable/post/684490…
инициализация:
//错误日志收集
import debug from './debug';
//初始化错误处理
Vue.use(ngmmdebug, { entryName: 'webmall' });
Если вы хотите сообщить об ошибке самостоятельно, вы можете пройти через:
import { debug } from './debug';
debug.notifyError({ messag: '发生错误了' });
Коллекция ошибок программы WeChat Mini
Апплету WeChat также удобно собирать информацию об ошибках, нужно лишь реализовать метод onError в объекте, передаваемом при вызове функции App. Адрес документа:Developers.wechat.qq.com/mini Программа ...
Применение:
App({
onError (msg) {
console.log(msg);//msg就是报错信息
}
})
Если вы хотите сделать код более переносимым, вы можете сделать это:
//将App暂存起来
let _App = App;
function HookParams(_appParams, eventName, eventFn) {
if (_appParams[eventName]) {
let _eventFn = _appParams[eventName];
//如果参数中已经存在onError函数,则保留并且添加错误收集
_appParams[eventName] = function (error) {
eventFn.call(this, error, eventName);
return _eventFn.call.apply(_eventFn, [this].concat(Array.prototype.slice.call(arguments)))
}
} else {
//如果参数中不存在onError函数,那比较简单直接定义一个,并且加入错误收集
_appParams[eventName] = function (error) {
eventFn.call(this, error, eventName)
}
}
}
function onErrorFn(error, eventName) {
//收集错误
}
App = function (_appParams) {
HookParams(_appParams, "onError", onErrorFn);
_App(_appParams);
};
Принцип на самом деле очень простой, нужно переписать функцию App, а затем обработать входящие параметры с помощью Hook.
Опять же, теперь, когда мы знаем, как собирать ошибки, нам просто нужно обернуть наш код.
создать новый файл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);
}
// 将App暂存起来
let _App = App;
App = function (_appParams) {
HookParams(_appParams, "onError", onErrorFn);
_App(_appParams);
};
//config
let debugConfig = {
entryName: 'entryName',
releaseStage: 'pro',
scriptVersion: '1.0',
client: {}
}
//获取设备信息
wx.getSystemInfo({
success: function (res) {
debugConfig.client = res;
}
});
//拼装postData
function getPostData(error = '') {
let {
entryName,
releaseStage,
scriptVersion,
client
} = debugConfig,
curPage = getCurrentPages()[getCurrentPages().length - 1],
url = '',
urlParams = '',
name = 'error',
postData = "postData",
metaData = {},
pageLevel = 'p0';
//处理url
if (curPage) {
url = curPage.route;
//此处自己根据实际项目给页面定级
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;
}
//控制错误的发送
function _logReport(error) {
//灰度控制自行加
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;
Измените app.js:
import ngmmdebug from './utils/ngmmdebug.js';
//初始化
ngmmdebug.init({
entryName: 'mall-wxapp',
scriptVersion: '2.6.3'
})
Сообщать об ошибках вручную
import ngmmdebug from './utils/ngmmdebug.js';
ngmmdebug.notifyError('发生错误了~');
Есть несколько особых моментов апплета, на которые вы можете обратить внимание:
1. Пройтиwx.getSystemInfo
Получить информацию об устройстве, конечно, вы также можете передатьwx.getUserInfo
Получить информацию о пользователе и т. д.
2. Полную ссылку апплета нужно собрать самому через атрибут page options.
Ссылаться на
Соберите ссылку на поле
{
"entryName":"项目名称",
"scriptVersion":"1.0",//脚本版本
"message":"aler is not defined",//错误描述
"metaData":{//自定义字段
"componentName":"anonymous component at /Users/taoxinhua/git/webmall/src/components/app.vue",//组件名称
"info":"created hook",//vue报错信息
"userToken":{//用户登录信息
"user_id": 1
}
},
"name":"ReferenceError",//错误名称
"releaseStage":"local",//报错环境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)",//错误栈
"time":1544437068009,//发生错误时的客户端时间
"title":"年糕妈妈优选",//页面标题
"type":"caught",//错误类型参考fundebug
"url":"http://localhost:3200/test",//页面地址
"client":{//客户端信息
"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,
"referrer":"http://localhost:3200/test"
},
"pageLevel":"p4"//页面错误级别,方便查询和优先处理重要页面的bug
}
Улучшенная система сбора логов
Если ваша система относительно небольшая и вы хотите использовать ее бесплатно, вы можете попробоватьfundebug.
Суммировать
Собирать ошибки во внешнем интерфейсе относительно просто, и как эффективно использовать эти собранные ошибки, нужно медленно обдумывать. Если в тексте что-то не так, вы можете указать на это в разделе комментариев.
подпись
by:Tao