UNPKG

grz-web-eye-sdk

Version:

网页监控SDK

677 lines (638 loc) 19.4 kB
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