UNPKG

keep-observers

Version:

This is a monitoring service applied to the web side Support Elasticsearch+kiban The middleware extension interface is provided by means of plug-in service compositionkeep-observers

934 lines (728 loc) 25.9 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("@util/index")); else if(typeof define === 'function' && define.amd) define(["@util/index"], factory); else { var a = typeof exports === 'object' ? factory(require("@util/index")) : factory(root["@util/index"]); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(this, function(__WEBPACK_EXTERNAL_MODULE__util_index__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./src/services/monitor/network/index.ts"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./src/services/monitor/network/api.ts": /*!*********************************************!*\ !*** ./src/services/monitor/network/api.ts ***! \*********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* 停止捕获 */ exports.stopObserver = function () { this.isCatch = false; }; /* 开始捕获 */ exports.startObserver = function () { this.isCatch = true; }; /* 取消拦截 */ exports.cancelPatch = function () { //这种方式会和angular 6的zone 等polyfills.js产生冲突 window.XMLHttpRequest.prototype.open = this._open; window.XMLHttpRequest.prototype.send = this._send; window.XMLHttpRequest.prototype.setRequestHeader = this._setRequestHeader; window.fetch = this._fetch; this._open = null; this._send = null; this._setRequestHeader = null; this._fetch = null; }; /***/ }), /***/ "./src/services/monitor/network/defaultConfig.ts": /*!*******************************************************!*\ !*** ./src/services/monitor/network/defaultConfig.ts ***! \*******************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* observer newwork 实例默认配置数据 */ exports["default"] = { //默认超时时间 20S; timeout: 20000, //屏蔽URL ignoreRequestList: [], //是否捕获响应内容 isCatchResponseContent: true, //是否自动开始上报 automaticStart: true }; /***/ }), /***/ "./src/services/monitor/network/handle.ts": /*!************************************************!*\ !*** ./src/services/monitor/network/handle.ts ***! \************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __importStar = this && this.__importStar || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) { if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; } result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var index_1 = __webpack_require__(/*! @util/index */ "@util/index"); var networkTool = __importStar(__webpack_require__(/*! ./tool */ "./src/services/monitor/network/tool.ts")); /* 初始化ajax请求监控 在这里替换window.XMLHttpRequest变量进行监控 */ exports._init = function () { //拦截Ajax以及fetch this._patchXMLAjax(); this._patchFetch(); }; /* 拦截XML AJax信息 */ exports._patchXMLAjax = function () { var _self = this; var isCatchResponseContent = _self._config.isCatchResponseContent; var _XMLHttp = window.XMLHttpRequest; //不支持 ajax 不进行监控 if (!_XMLHttp) { return false; } _self._open = window.XMLHttpRequest.prototype.open; _self._send = window.XMLHttpRequest.prototype.send; _self._setRequestHeader = window.XMLHttpRequest.prototype.setRequestHeader; //拦截原生open window.XMLHttpRequest.prototype.open = function (method, url) { var XML = this; var args = index_1.Tools.toArray(arguments); //定时器 var timer = null; //获取请求唯一ID var id = index_1.Tools.getUniqueID(); //获取方法 var method = args[0]; //获取url var url = args[1]; //保存下 在send中使用 XML._url = url; XML._method = method; XML._id = id; //保存下请求头 在拦截请求头处使用 XML._setHead = {}; XML._setHead[id] = {}; //拦截处理响应回调 var _onreadystatechange = XML.onreadystatechange || function () {}; // start onreadystatechange var onreadystatechange = function onreadystatechange() { var item = _self.networkList[id] ? _self.networkList[id] : false; //如果不存在 可能略过了send 会导致丢失部分数据 if (!item) { item = {}; //保存请求方法 item.method = method; var _a = networkTool.handleReqUrl(XML._url), url_1 = _a.url, params = _a.params; //处理请求url和params item.url = url_1; item.params = params; } //更新状态 item.status = 0; if (XML.readyState > 1) { item.status = XML.status; } item.responseType = XML.responseType; //判断请求状态 if (XML.readyState == 0) { // 未开始 if (!item.startTime) { item.startTime = +new Date(); } } else if (XML.readyState == 1) { // 打开 if (!item.startTime) { item.startTime = +new Date(); } } else if (XML.readyState == 2) {// 发送 } else if (XML.readyState == 3) {//loading } else if (XML.readyState == 4) { //结束超时捕获 _self._handleTimeout(id); //处理响应头 item.responseHead = {}; var header = XML.getAllResponseHeaders() || '', headerArr = header.split("\n"); //提取数据 for (var i = 0; i < headerArr.length; i++) { var line = headerArr[i]; if (!line) { continue; } var arr = line.split(': '); var key = arr[0], value = arr.slice(1).join(': '); item.responseHead[key] = value; } //完成 clearInterval(timer); item.endTime = +new Date(), item.costTime = item.endTime - (item.startTime || item.endTime); item.response = isCatchResponseContent ? XML.response : 'no-catch-responseContent'; //请求结束完成 setTimeout(function () { //是否是超时接口 超时的接口不做处理 if (!_self.timeoutRequest[id]) { _self._handleDoneXML(id); } }); } else { clearInterval(timer); } //如果这个接口已经超时处理了 那么不记录 if (!_self.timeoutRequest[id]) { _self.networkList[id] = item; } return _onreadystatechange.apply(XML, arguments); }; XML.onreadystatechange = onreadystatechange; //end onreadystatechange //防止第三方库更改状态 //定时查看请求状态 var preState = -1; timer = setInterval(function () { if (preState != XML.readyState) { preState = XML.readyState; onreadystatechange.call(XML); } }, 10); return _self._open.apply(XML, args); }; //拦截原始设置请求头 window.XMLHttpRequest.prototype.setRequestHeader = function (header) { var XML = this; var args = index_1.Tools.toArray(arguments); if (XML._id && XML._setHead) { var setHead = XML._setHead[XML._id]; var key = args[0] ? args[0] : 'unkownRequestHead'; var value = args[1] ? args[1] : ''; setHead[key] = value; XML._setHead[XML._id] = setHead; } return _self._setRequestHeader.apply(XML, args); }; //拦截原生send window.XMLHttpRequest.prototype.send = function () { var XML = this; var id = XML._id; var method = XML._method.toUpperCase(); var requestHead = XML._setHead[id]; var url = XML._url; var args = [].slice.call(arguments), data = args[0], saveData = ''; //监听列表中创建一条请求 if (!_self.networkList[id]) { _self.networkList[id] = {}; } //type ajax _self.networkList[id].type = 'ajax'; //保存请求方法 _self.networkList[id].method = method; var _a = networkTool.handleReqUrl(url), url = _a.url, params = _a.params; //处理请求url和params _self.networkList[id].url = url; _self.networkList[id].params = params; //保存自定义请求头 if (requestHead) { _self.networkList[id].requestHead = index_1.Tools.extend({}, requestHead); delete XML._setHead[id]; } //如果是data存在 if (data && index_1.Tools.isString(data)) { saveData = data; } _self.networkList[id].body = saveData; //发送 _self._handleSendXML(id); //开启定时器 判断接口是否超时 _self._handleTimeout(id); return _self._send.apply(XML, args); }; }; /* 拦截fetch信息 */ exports._patchFetch = function () { if (!window.fetch) { return false; } var _self = this; var isCatchResponseContent = _self._config.isCatchResponseContent; _self._fetch = window.fetch; //https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/fetch#%E5%8F%82%E6%95%B0 window.fetch = function (input, init) { if (init === void 0) { init = undefined; } var fetchSelf = this; var args = arguments; var id = index_1.Tools.getUniqueID(); if (!_self.networkList[id]) { _self.networkList[id] = {}; } var _a = networkTool.handleReqUrl(input.toString()), url = _a.url, params = _a.params; //处理请求url和params _self.networkList[id].type = 'fetch'; _self.networkList[id].url = url; _self.networkList[id].status = 0; _self.networkList[id].params = params; if (init && !index_1.Tools.isEmptyObject(init)) { _self.networkList[id].method = init.method ? init.method.toUpperCase() : 'GET'; _self.networkList[id].body = init.body ? index_1.Tools.objectStringify(init.body) : ''; _self.networkList[id].requestHead = init.headers ? init.headers : undefined; } else { _self.networkList[id].method = 'GET'; _self.networkList[id].body = ''; _self.networkList[id].requestHead = undefined; } _self._handleSendXML(id); return new Promise(function (resolve, reject) { var promise; var startTime = new Date().getTime(); var handleResponse = function handleResponse(response, content) { _self.networkList[id].costTime = new Date().getTime() - startTime; _self.networkList[id].response = isCatchResponseContent ? content : 'no-catch-responseContent'; _self.networkList[id].status = response ? response.status : 0 || 0; var headers = index_1.Tools.toArray(response.headers.keys()); if (!index_1.Tools.isEmptyArray(headers)) { _self.networkList[id].responseHead = {}; headers.forEach(function (key) { _self.networkList[id].responseHead[key] = response.headers.get(key); }); } else { _self.networkList[id].responseHead = undefined; } _self.networkList[id].responseType = response.type; setTimeout(function () { //是否是超时接口 超时的接口不做处理 if (!_self.timeoutRequest[id]) { _self._handleDoneXML(id); } }); }; try { _self.networkList[id].startTime = startTime; //开启定时器 判断接口是否超时 _self._handleTimeout(id); promise = _self._fetch.apply(fetchSelf, args); } catch (error) { _self.networkList[id].costTime = new Date().getTime() - startTime; _self.networkList[id].response = 'fetch error:' + error; _self.networkList[id].responseHead = ''; _self.networkList[id].responseType = 'error'; setTimeout(function () { _self._handleDoneXML(id); }); reject(error); return; } promise.then(function (response) { resolve(response.clone()); //结束超时捕获 _self._handleTimeout(id); //stream only if (response.ok) { response.text().then(function (content) { handleResponse(response, content); }, function (err) { handleResponse(response, 'fetch response.text() error:' + err); }); } else { handleResponse(response, 'fetch error:' + response.statusText); } }, function (error) { //结束超时捕获 _self._handleTimeout(id); _self.networkList[id].costTime = new Date().getTime() - startTime; _self.networkList[id].response = 'fetch error:' + error; _self.networkList[id].responseHead = ''; _self.networkList[id].responseType = 'error'; setTimeout(function () { //是否是超时接口 超时的接口不做处理 if (!_self.timeoutRequest[id]) { _self._handleDoneXML(id); } }); reject(error); }); }); }; }; /* 处理接口请求超时 */ exports._handleTimeout = function (id) { var _self = this; var timeout = _self._config.timeout; var isTimeout = _self.timeoutRequest[id] ? _self.timeoutRequest[id] : false; var time = _self.timeout[id] ? _self.timeout[id] : false; var item = _self.networkList[id]; //如果不存在 不做处理 if (!item || isTimeout) { return false; } if (!time) { //如果没有那么创建检测超时定时器 time = setTimeout(function () { //接口返回超时 item.isTimeout = true; item.timeout = timeout; item.isError = true; item.errorContent = 'ajax request timeout,time:' + timeout + '(ms)'; item.response = item.response || 'ajax request timeout,time:' + timeout + '(ms)'; //这里直接完成添加到超时列表 停止后续处理 _self._handleDoneXML(id); _self.timeoutRequest[id] = true; }, timeout); } else { //如果存在 则说明已经回调 取消超时定时器 clearTimeout(time); } }; /* 处理请求完成的数据 @id:拦截请求唯一ID */ exports._handleDoneXML = function (id) { var _self = this; var ajaxItem = index_1.Tools.extend({}, _self.networkList[id]); //空的对象不做处理 if (index_1.Tools.isEmptyObject(ajaxItem)) { return false; } ajaxItem.statusType = 'response'; /****** 这里开始处理数据 *****/ //判断当前请求数据url是否需要屏蔽 if (!this.isCatch || !_self._handleJudgeDisbale(ajaxItem)) { delete _self.networkList[id]; return false; } //判断状态码是否出错 var status = ajaxItem.status; if (!networkTool.validateStatus(status) && !ajaxItem.isError) { ajaxItem.isError = true; ajaxItem.response = ajaxItem.response || 'ajax request error! error statusCode:' + (status || 0); ajaxItem.errorContent = 'ajax request error! error statusCode:' + (status || 0); } //通知上传 _self.sendMessage({ type: "monitor", typeName: 'network', data: ajaxItem, isError: ajaxItem.isTimeout || ajaxItem.isError ? true : false }); //上报后删除记录 delete _self.networkList[id]; }; /* 处理发送的请求 @id:拦截请求唯一ID */ exports._handleSendXML = function (id) { var _self = this; var ajaxItem = index_1.Tools.extend({}, _self.networkList[id]); //空的对象不做处理 if (index_1.Tools.isEmptyObject(ajaxItem)) { return false; } ajaxItem.statusType = 'request'; //判断当前请求数据url是否需要屏蔽 if (!this.isCatch || !_self._handleJudgeDisbale(ajaxItem)) { delete _self.networkList[id]; return false; } //通知上传 _self.sendMessage({ type: "monitor", typeName: 'network', data: ajaxItem }); }; /* 判断该请求是否是屏蔽请求 params ajaxInfo :即将上报的数据 return 忽略返回 false; 不忽略返回 true */ exports._handleJudgeDisbale = function (ajaxInfo) { var ignoreRequestList = this._config.ignoreRequestList; //判断是否是是屏蔽url if (ignoreRequestList && !index_1.Tools.isEmptyArray(ignoreRequestList)) { var url = ajaxInfo.url; var unReport = false; ignoreRequestList.forEach(function (item) { if (url.indexOf(item) > -1) { unReport = true; return false; } }); if (unReport) { return false; } } return true; }; /***/ }), /***/ "./src/services/monitor/network/index.ts": /*!***********************************************!*\ !*** ./src/services/monitor/network/index.ts ***! \***********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var __extends = this && this.__extends || function () { var _extendStatics = function extendStatics(d, b) { _extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; } || function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) d[p] = b[p]; } }; return _extendStatics(d, b); }; return function (d, b) { _extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; }(); var __assign = this && this.__assign || function () { __assign = Object.assign || function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } } return t; }; return __assign.apply(this, arguments); }; var __importDefault = this && this.__importDefault || function (mod) { return mod && mod.__esModule ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var defaultConfig_1 = __importDefault(__webpack_require__(/*! ./defaultConfig */ "./src/services/monitor/network/defaultConfig.ts")); var index_1 = __webpack_require__(/*! @util/index */ "@util/index"); var api_1 = __webpack_require__(/*! ./api */ "./src/services/monitor/network/api.ts"); var handle_1 = __webpack_require__(/*! ./handle */ "./src/services/monitor/network/handle.ts"); // 获取系统信息 var KeepObserverNetwork = /** @class */ function (_super) { __extends(KeepObserverNetwork, _super); //构造函数 function KeepObserverNetwork(config) { if (config === void 0) { config = {}; } var _this = _super.call(this, config) || this; //method _this.stopObserver = api_1.stopObserver.bind(_this); _this.startObserver = api_1.startObserver.bind(_this); _this.cancelPatch = api_1.cancelPatch.bind(_this); _this._init = handle_1._init.bind(_this); _this._patchXMLAjax = handle_1._patchXMLAjax.bind(_this); _this._patchFetch = handle_1._patchFetch.bind(_this); _this._handleTimeout = handle_1._handleTimeout.bind(_this); _this._handleDoneXML = handle_1._handleDoneXML.bind(_this); _this._handleSendXML = handle_1._handleSendXML.bind(_this); _this._handleJudgeDisbale = handle_1._handleJudgeDisbale.bind(_this); //存混合配置 var _a = config, _b = _a.networkCustom, networkCustom = _b === void 0 ? false : _b, _c = _a.reportCustom, reportCustom = _c === void 0 ? false : _c; var reportUrl = reportCustom && reportCustom.reportUrl ? reportCustom.reportUrl : []; var networkConfig = index_1.Tools.extend({ reportUrl: reportUrl }, networkCustom || config); _this._config = index_1.Tools.extend(__assign({}, defaultConfig_1["default"]), networkConfig); _this._config.ignoreRequestList = _this._config.ignoreRequestList.concat(reportUrl); //kabanaApm serverUrl if (_this._config.serverUrl) { _this._config.ignoreRequestList.push(_this._config.serverUrl); } //是否开启捕获 _this.isCatch = false; //监控的数据列表 _this.networkList = {}; //辅助捕获超时 _this.timeout = {}; _this.timeoutRequest = {}; // 发送消息 _this.sendMessage = function () { return index_1.consoleTools.warnError('sendMessage is not active, apply receive sendPipeMessage fail '); }; // 开启网络拦截监控 _this._init(); return _this; } //提供一个挂载入口 KeepObserverNetwork.prototype.apply = function (_a) { var sendMessage = _a.sendMessage; var automaticStart = this._config.automaticStart; this.sendMessage = sendMessage; //开启捕获 if (automaticStart) { this.startObserver(); } return { networkStop: this.stopObserver, networkStart: this.startObserver, networkCancelPatch: this.cancelPatch }; }; return KeepObserverNetwork; }(index_1.KeepObserverPublic); exports["default"] = KeepObserverNetwork; /***/ }), /***/ "./src/services/monitor/network/tool.ts": /*!**********************************************!*\ !*** ./src/services/monitor/network/tool.ts ***! \**********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* 处理URL 分离base url 和params @return { url: string params: object or string('') } */ var __values = this && this.__values || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; if (m) return m.call(o); return { next: function next() { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; }; Object.defineProperty(exports, "__esModule", { value: true }); function handleReqUrl(url) { var e_1, _a; //处理下解码URL url = window.decodeURIComponent(url); var params = ''; var baseUrl = ''; //判断URL后面是否存在参数 if (url.indexOf('?') === -1) { baseUrl = url; } else { var query = url.indexOf('?'); baseUrl = url.substring(0, query); query = url.substring(query + 1, url.length); params = {}; query = query.split('&'); // => ['b=c', 'd=?e'] try { for (var query_1 = __values(query), query_1_1 = query_1.next(); !query_1_1.done; query_1_1 = query_1.next()) { var q = query_1_1.value; q = q.split('='); params[q[0]] = q[1]; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (query_1_1 && !query_1_1.done && (_a = query_1["return"])) _a.call(query_1); } finally { if (e_1) throw e_1.error; } } } return { url: baseUrl, params: params }; } exports.handleReqUrl = handleReqUrl; /* 检查状态码是否正确 */ function validateStatus(status) { return status >= 200 && status < 300; } exports.validateStatus = validateStatus; /***/ }), /***/ "@util/index": /*!******************************!*\ !*** external "@util/index" ***! \******************************/ /*! no static exports found */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__util_index__; /***/ }) /******/ }); });