grz-web-eye-sdk
Version:
网页监控SDK
677 lines (638 loc) • 19.4 kB
JavaScript
var monitor = (function (exports) {
'use strict';
var config = {
url: 'http://127.0.0.1:8080/api',
projectName: 'webEyeSDK',
userId: '123456',
isImgUpload: true,
batchSize: 5 //批量上报数量
};
function setConfig(options) {
for (var key in options) {
if (options[key]) {
config[key] = options[key];
}
}
}
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
t && (r = t);
var n = 0,
F = function () {};
return {
s: F,
n: function () {
return n >= r.length ? {
done: true
} : {
done: false,
value: r[n++]
};
},
e: function (r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = true,
u = false;
return {
s: function () {
t = t.call(r);
},
n: function () {
var r = t.next();
return a = r.done, r;
},
e: function (r) {
u = true, o = r;
},
f: function () {
try {
a || null == t.return || t.return();
} finally {
if (u) throw o;
}
}
};
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: true,
configurable: true,
writable: true
}) : e[r] = t, e;
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r);
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function deepClone(obj) {
var map = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new WeakMap();
if (_typeof(obj) !== 'object' || obj === null) {
return obj;
}
if (map.has(obj)) {
return map.get(obj);
}
var newObj = obj instanceof Array ? [] : {};
map.set(obj, newObj);
for (var key in obj) {
newObj[key] = deepClone(obj[key], map);
}
return newObj;
}
function generateUniqueId() {
return 'id-' + Date.now() + '-' + Math.random().toString(36).substring(2, 9);
}
//缓存数据
var cache = [];
function getCache() {
return deepClone(cache); //深拷贝:防止数据被修改
}
function addCache(data) {
cache.push(data);
}
function clearCache() {
cache.length = 0;
}
var originalProto$1 = XMLHttpRequest.prototype;
var originalOpen$1 = originalProto$1.open;
var originalSend$1 = originalProto$1.send;
function report(data) {
if (!config.url) {
console.error('请配置上传url地址');
return;
}
var reportData = JSON.stringify({
data: data,
id: generateUniqueId()
});
//如果配置了图片上传,则优先使用图片上传
if (config.isImgUpload) {
imgRequest(reportData);
} else {
//如果浏览器支持navigator.sendBeacon,则使用navigator.sendBeacon发送数据
if (window.navigator.sendBeacon) {
beaconRequest(reportData);
} else {
//如果浏览器不支持navigator.sendBeacon,则使用xhr发送数据
xhrRequest(reportData);
}
}
}
//批量进行上报
function batchReport(data) {
addCache(data);
var cache = getCache();
console.log('cache', cache);
if (cache.length > config.batchSize) {
report(cache);
clearCache();
}
}
//发送图片数据
function imgRequest(data) {
var img = new Image();
// 图片请求不会阻塞页面加载,可以异步发送数据,encodeURIComponent 编码
img.src = "".concat(config.url, "?data=").concat(encodeURIComponent(JSON.stringify(data)));
}
function xhrRequest(data) {
if (window.requestIdleCallback) {
window.requestIdleCallback(function () {
var xhr = new XMLHttpRequest();
originalOpen$1.call(xhr, 'post', config.url);
originalSend$1.call(xhr, JSON.stringify(data));
}, {
timeout: 3000
});
} else {
setTimeout(function () {
var xhr = new XMLHttpRequest();
originalOpen$1.call(xhr, 'post', config.url);
originalSend$1.call(xhr, JSON.stringify(data));
});
}
}
function beaconRequest(data) {
//如果支持requestIdleCallback,则使用requestIdleCallback发送,否则使用setTimeout发送
if (window.requestIdleCallback) {
window.requestIdleCallback(function () {
window.navigator.sendBeacon(config.url, data);
}, {
timeout: 3000
}); //这个timeout是指超时时间,如果3s内还没有空闲,就必须发送了
} else {
setTimeout(function () {
window.navigator.sendBeacon(config.url, data);
});
}
}
var originalProto = XMLHttpRequest.prototype;
var originalOpen = originalProto.open;
var originalSend = originalProto.send;
function overwirteOpenAndSend() {
originalProto.open = function newOpen() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
this.url = args[1];
this.method = args[0];
originalOpen.apply(this, args);
};
originalProto.send = function newSend() {
var _this = this;
this.startTime = Date.now();
var _onLoaded = function onLoaded() {
_this.endTime = Date.now();
_this.duration = _this.endTime - _this.startTime;
var url = _this.url,
method = _this.method,
startTime = _this.startTime,
endTime = _this.endTime,
duration = _this.duration,
status = _this.status;
var reportData = {
type: 'performance',
subType: 'xhr',
startTime: startTime,
endTime: endTime,
duration: duration,
status: status,
url: url,
method: method,
success: status >= 200 && status < 300
};
// 上报 todo
batchReport(reportData);
_this.removeEventListener('loadend', _onLoaded, true);
};
this.addEventListener('loadend', _onLoaded, true);
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
originalSend.apply(this, args);
};
}
function xhr$1() {
overwirteOpenAndSend();
}
function xhr() {
window.addEventListener('pageshow', function (event) {
requestAnimationFrame(function () {
['load'].forEach(function (type) {
var reportData = {
type: 'performance',
subType: type,
pageUrl: window.location.href,
startTime: performance.now() - event.timeStamp
};
// 上报 todo
batchReport(reportData);
});
});
}, true);
}
//统计静态资源加载时间
function observerEntries() {
if (document.readyState === 'complete') {
observeEvent();
} else {
var _onLoad = function onLoad() {
observeEvent();
window.removeEventListener('load', _onLoad, true); //第三个参数为true是捕获阶段
};
window.addEventListener('load', _onLoad, true); //第三个参数为true捕获阶段
}
}
function observeEvent() {
var entryHandler = function entryHandler(list) {
var datas = list.getEntries();
var _iterator = _createForOfIteratorHelper(datas),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var entry = _step.value;
if (observer) {
observer.disconnect();
}
var reportData = {
name: entry.name,
type: "performance",
subType: entry.entryType,
//类型
sourceType: entry.initiatorType,
//资源类型
duration: entry.duration,
//加载时间
dns: entry.domainLookupEnd - entry.domainLookupStart,
//dns解析时间
tcp: entry.connectEnd - entry.connectStart,
//tcp连接时间
redirect: entry.redirectEnd - entry.redirectStart,
//重定向时间
ttfb: entry.responseStart,
//首字节时间
protocol: entry.nextHopProtocol,
//请求协议
responseBodySize: entry.encodedBodySize,
//响应内容大小
responseHeaderSize: entry.transferSize - entry.encodedBodySize,
//响应头大小
transferSize: entry.transferSize,
//请求内容大小
resourceSize: entry.decodedBodySize,
//资源解压后大小
startTime: performance.now() //开始时间
};
// 上报 todo
batchReport(reportData);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
var observer = new PerformanceObserver(entryHandler);
observer.observe({
type: "resource",
buffered: true
});
}
function observerFCP() {
var entryHandler = function entryHandler(list) {
var datas = list.getEntries();
var _iterator = _createForOfIteratorHelper(datas),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var entry = _step.value;
if (entry.name === "first-contentful-paint") {
observer.disconnect();
var json = entry.toJSON();
var reportData = _objectSpread2(_objectSpread2({}, json), {}, {
type: "performance",
subType: json.name,
pageUrl: window.location.href
});
// 上报 todo
batchReport(reportData);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
//统计FCP事件
var observer = new PerformanceObserver(entryHandler);
// 监听所有类型为paint的性能条目,buffered:true 确保观察到所以的paint事件
observer.observe({
type: "paint",
buffered: true
});
}
function observerLCP() {
var entryHandler = function entryHandler(list) {
if (observer) {
observer.disconnect();
}
var datas = list.getEntries();
var _iterator = _createForOfIteratorHelper(datas),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var entry = _step.value;
var json = entry.toJSON();
var reportData = _objectSpread2(_objectSpread2({}, json), {}, {
type: "performance",
subType: json.entryType,
pageUrl: window.location.href
});
// 上报 todo
batchReport(reportData);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
//统计LCP事件
var observer = new PerformanceObserver(entryHandler);
// 监听所有类型为paint的性能条目,buffered:true 确保观察到所以的paint事件
observer.observe({
type: "largest-contentful-paint",
buffered: true
});
}
function observerFP() {
var entryHandler = function entryHandler(list) {
var datas = list.getEntries();
var _iterator = _createForOfIteratorHelper(datas),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var entry = _step.value;
if (entry.name === "first-paint") {
observer.disconnect();
var json = entry.toJSON();
var reportData = _objectSpread2(_objectSpread2({}, json), {}, {
type: "performance",
subType: json.name,
pageUrl: window.location.href
});
// 上报 todo
batchReport(reportData);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
//统计FP事件
var observer = new PerformanceObserver(entryHandler);
// 监听所有类型为paint的性能条目,buffered:true 确保观察到所以的paint事件
observer.observe({
type: "paint",
buffered: true
});
}
function performance$1() {
xhr$1();
xhr();
observerEntries();
observerFCP();
observerLCP();
observerFP();
}
function onClick() {
['mousedown', 'touchstart'].forEach(function (eventType) {
window.addEventListener(eventType, function (e) {
var target = e.target;
if (target.tagName) {
var reportData = {
type: 'behavior',
subType: 'click',
target: target.tagName,
startTime: e.timeStamp,
innerHTML: target.innerHTML,
outerHTML: target.outerHTML,
eventType: eventType,
path: e.path
};
batchReport(reportData);
}
});
});
}
function pageChange() {
var oldUrl = '';
window.addEventListener('hashchange', function (e) {
var newUrl = e.newURL;
var reportData = {
type: 'behavior',
subType: 'pageChange',
from: oldUrl,
to: newUrl,
uuid: generateUniqueId(),
startTime: performance.now()
};
batchReport(reportData);
oldUrl = newUrl;
}, true);
var from = '';
window.addEventListener('popstate', function (event) {
var to = window.location.href;
var reportData = {
from: from,
to: to,
type: 'behavior',
subType: 'popstate',
startTime: performance.now(),
uuid: generateUniqueId()
};
batchReport(reportData);
from = to;
}, true);
}
function pv() {
var reportData = {
type: 'behavior',
subType: 'pv',
startTime: performance.now(),
pageUrl: window.location.href,
referrer: document.referrer,
uuid: generateUniqueId()
};
batchReport(reportData);
}
function behavior() {
pv();
pageChange();
onClick();
}
function error() {
// 捕获资源加载失败的错误 js css img 等
window.addEventListener('error', function (e) {
var target = e.target;
if (!target) {
return;
}
if (target.src || target.href) {
var url = target.src || target.href;
var reportData = {
type: 'error',
subType: 'resource',
pageUrl: window.location.href,
url: url,
html: target.outerHTML,
path: e.path
};
// 上报 todo
batchReport(reportData);
}
}, true);
//捕获js错误
window.onerror = function (msg, url, lineno, colno, error) {
var reportData = {
type: 'error',
subType: 'js',
msg: msg,
url: url,
lineno: lineno,
colno: colno,
stack: error === null || error === void 0 ? void 0 : error.stack,
pageUrl: window.location.href,
startTime: performance.now()
};
// 上报 todo
batchReport(reportData);
};
//捕获promise错误
window.addEventListener('unhandledrejection', function (e) {
var _e$reason;
var reportData = {
type: 'error',
subType: 'promise',
msg: (_e$reason = e.reason) === null || _e$reason === void 0 ? void 0 : _e$reason.stack,
pageUrl: window.location.href,
startTime: performance.now()
};
// 上报 todo
batchReport(reportData);
}, true);
}
window.__webEyeSDK__ = {
version: '1.0.0'
};
//针对vue的错误捕获
function install(Vue, options) {
if (__webEyeSDK__.vue) {
return;
}
__webEyeSDK__.vue = true;
setConfig(options);
// 捕获vue错误,通过Vue.config.errorHandler捕获 //装饰器模式
var handler = Vue.config.errorHandler;
Vue.config.errorHandler = function (err, vm, info) {
var reportData = {
info: info,
error: err.stack,
type: 'vue',
subType: 'error',
startTime: window.performance.now(),
pageUrl: window.location.href
};
console.log('vue error', reportData);
batchReport(reportData);
if (handler) {
handler.call(this, err, vm, info);
}
};
}
function init(options) {
setConfig(options);
performance$1();
behavior();
// 如果不是Vue项目或者明确指定要捕获所有错误,才启用通用错误捕获
if (!window.__webEyeSDK__.vue || options.captureAllErrors) {
error();
}
}
var webEyeSDK = {
install: install,
performance: performance$1,
behavior: behavior,
error: error,
init: init
};
exports.default = webEyeSDK;
exports.init = init;
exports.install = install;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({});
//# sourceMappingURL=monitor.js.map