monitors-own-js
Version:
monitor-js 是一个轻量级前端错误监控上报插件 基于monitor-js增加部分功能
205 lines (195 loc) • 6.54 kB
JavaScript
'use strict'
import QS from 'querystring'
import EventEmitter from './EmitEvent.js'
import Device from 'browser-device-js'
export default class Monitor extends EventEmitter {
constructor(params = {}) {
super()
let { exclude = [], match = [], url, filterTag, autoPush = true, ...prop } = params;
this.config = prop;
this.exclude = exclude;
this.match = match;
this.url = url;
this.autoPush = autoPush;
this.plugins = [];
this.filterTag = filterTag;
this.attrName = "action"
}
initEvent() {
this.windowError();
this.domEvent();
}
setConfig(config = {}) {
this.config = { ...this.config, ...config }
return this
}
addPlugin(func) {
this.plugins.push(func)
return this;
}
captureException(data, callback) {
let params =QS.stringify({
...data,
actions: JSON.stringify(data.actions)
})
let script = document.createElement('script');
script.src = `${this.url}?_t=${+new Date()}&${params}`;
document.body.appendChild(script);
script.parentNode.removeChild(script);
}
getCurrInfo() {
if (!this.device)
this.device = new Device().getDevice();
return {
...this.device,
reportTime: this.dateFormat(new Date(), "yyyy-MM-dd hh:mm:sss"),
url: window.location.href,
...this.config
}
}
dateFormat(date, fmt) {
var o = {
"M+": date.getMonth() + 1, //月份
"d+": date.getDate(), //日
"H+": date.getHours(), //小时
"h+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
install() {
let i = 0;
while (i < this.plugins.length) {
this.plugins[i].call(this)
i++;
}
this.initEvent();
this.emit('onInstall')
return this
}
pushException(obj = {}) {
if (this.isDomainfilter()) return
if (this.isErrorfilter(obj.details)) return;
let data = {
...this.getCurrInfo(),
actions: this.getStorageAction(),
...obj,
}
delete data.browserVer
this.emit('captureBefore', data)
if (!this.autoPush) {
return
}
setTimeout(() => {
this.captureException(data)
}, 0);
}
isErrorfilter(msg) {
msg = msg.toString();
return this.exclude.filter((ex) => {
return msg.indexOf(ex) !== -1
}).length > 0 ? true : false;
}
isDomainfilter() {
let href = window.location.href;
return this.match.filter((ex) => {
return href.indexOf(ex) !== -1
}).length >= 0 ? false : true;
}
windowError() {
const _error = console.error;
console.error = (error) => {
this.pushException({
route: window.location.href,
details:error,
errorDetails: error && error.stack,
})
_error.call(console,error)
};
window.onerror = (msg, url, line, col, error) => {
let details = `${msg} line:${line}`;
this.pushException({
route: url,
details,
errorDetails: error && error.stack,
})
}
}
getStorageAction() {
let _actions = sessionStorage.getItem('_actions');
if (!_actions) return [];
try {
return JSON.parse(_actions) || [];
} catch (e) {
return [];
}
}
setStorageAction(_actions) {
let MAX = 8;
if (typeof _actions === 'string') {
sessionStorage.setItem('_actions', _actions);
return
}
if (_actions instanceof Array && _actions.length > MAX) {
_actions.shift();
}
try {
sessionStorage.setItem('_actions', JSON.stringify(_actions));
} catch (e) {
}
}
domEvent() {
window.addEventListener('click', (e) => {
e = e || window.event;
let _actions = this.getStorageAction();
let currHtml = this.getCurrHtml(e);
if (!currHtml) return
_actions.push({
type: e.type,
target: currHtml,
time: this.dateFormat(new Date(), "yyyy-MM-dd hh:mm:sss")
})
this.setStorageAction(_actions)
});
}
getCurrHtml(e) {
const target = e.srcElement ? e.srcElement : e.target;
let { localName, id, className, innerText = '' } = target;
const filterTag = this.filterTag || function (tag) {
return ['body', 'html'].indexOf(tag) === -1
}
if (!filterTag(localName)) return ''
let action = target.getAttribute(this.attrName)
if (action && (action.indexOf("{") !== -1 && action.indexOf("}") !== -1)) {
try {
let point = JSON.parse(action)
this.emit('onPointClick', point)
} catch (e) {
this.emit('onPointClick', {
value: action
})
}
}
innerText = innerText.replace(/\s/g, '').substring(0, 20);
id = id && `id="${id}"` || '';
className = className && `className="${className}"` || '';
action = action && `action="${action}"` || '';
innerText = innerText.replace(/\s/g, '').substring(0, 20);
return `<${localName} ${action} ${id} ${className}>${innerText}</${localName}>`;
}
setAttrName(name) {
if (typeof name !== "string") {
throw new Error("name type string!")
}
this.attrName = name
}
getAttrName() {
return this.attrName;
}
}