UNPKG

spy-client

Version:

spy client

308 lines (303 loc) 11.5 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SpyClient = factory()); })(this, (function () { 'use strict'; /** * @file utils * @author kaivean */ function assign() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var __assign = Object.assign || function __assign(t) { for (var s = void 0, i = 1, n = arguments.length; i < n; i++) { // eslint-disable-next-line prefer-rest-params 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, args); } /** * @file SpyClient * @author kaivean */ var defaultLogServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif?'; // 基础版本兼容非浏览器环境 var ver = navigator && navigator.userAgent ? navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?)_/) : ''; var isLtIos14 = ver && ver[2] && (+ver[2] < 14); function err(msg) { console.error("[SpyClient_log]".concat(msg)); // throw new Error(msg); } function stringify(obj) { return Object.keys(obj).map(function (key) { var value = obj[key]; if (typeof value === 'undefined') { value = ''; } else if (typeof value !== 'string') { value = JSON.stringify(value); } return encodeURIComponent(key) + '=' + encodeURIComponent(value); }).join('&'); } function isArray(arr) { return Object.prototype.toString.call(arr) === '[object Array]'; } var SpyClient = /** @class */ (function () { function SpyClient(option) { this.sample = {}; this.markCache = {}; if (!option.pid) { throw new Error('pid is required'); } this.option = { pid: option.pid, lid: option.lid, check: option.check !== false, sample: option.sample, localCache: option.localCache, logServer: option.logServer || defaultLogServer, }; } SpyClient.prototype.handle = function (logItem) { if (!this.check(logItem)) { return; } logItem = assign({ pid: this.option.pid, lid: this.option.lid, ts: Date.now(), group: 'common', }, logItem); if (this.option.localCache) { this.option.localCache.addLog(logItem); } // 当前api设置了抽样, if (typeof logItem.sample === 'number') { if (Math.random() > logItem.sample) { return; } } else if (typeof this.option.sample === 'number' && Math.random() > this.option.sample) { // 否则,用全局抽样 return; } delete logItem.sample; return logItem; }; SpyClient.prototype.send = function (data, post) { if (post === void 0) { post = false; } var logItems = isArray(data) ? data : [data]; var postData = []; for (var _i = 0, logItems_1 = logItems; _i < logItems_1.length; _i++) { var logItem = logItems_1[_i]; logItem = this.handle(logItem); if (!logItem) { continue; } postData.push(logItem); // 期望通过post方式上传日志 if (post) { continue; } var url = this.option.logServer + stringify(logItem); this.request(url); } if (post) { this.sendPost(postData); } }; SpyClient.prototype.check = function (query) { if (!this.option.check) { return true; } var types = ['perf', 'except', 'dist', 'count']; if (types.indexOf(query.type) === -1) { err('type only is one of ' + types.join(', ')); return false; } if (query.group && query.group.length > 30) { err('group length execeeds 30'); return false; } var simpleReg = /^[a-zA-Z0-9-_]{0,30}$/; if (query.type === 'except') { if (!(typeof query.info.msg === 'string' && query.info.msg.length)) { err('info.msg field must be not empty and is String'); return false; } } else { for (var _i = 0, _a = Object.keys(query.info); _i < _a.length; _i++) { var infoKey = _a[_i]; if (!simpleReg.test(infoKey)) { err("info.".concat(infoKey, " is unexpected. ") + 'Length must be not more than 30. ' + 'Supported chars: a-zA-Z0-9-_'); return false; } var infoVal = query.info[infoKey]; if (query.type === 'dist') { if (infoVal.length > 30) { err("info.".concat(infoKey, " value length execeeds 30 when type == 'dist'")); return false; } } else if (typeof infoVal !== 'number') { err("info.".concat(infoKey, " value must be number")); return false; } } } if (query.dim) { for (var _b = 0, _c = Object.keys(query.dim); _b < _c.length; _b++) { var dimKey = _c[_b]; if (!simpleReg.test(dimKey)) { err("dim key [".concat(dimKey, "] is unexpected. ") + 'Length must be not more than 30. ' + 'Supported chars: a-zA-Z0-9-_'); return false; } var dimVal = query.dim[dimKey]; if (!/^[a-zA-Z0-9\-_\*\.\s\/#\+@\&\u4e00-\u9fa5]{0,30}$/.test(dimVal)) { err("dim.".concat(dimKey, " value [").concat(dimVal, "] is unexpected. ") + 'Length must be not more than 30. ' + 'Supported chars: a-zA-Z0-9-_*. /#+@& and Chinese'); return false; } } } return true; }; /** * * @param option 配置 */ SpyClient.prototype.sendPerf = function (option) { this.send(assign({ type: 'perf', }, option)); }; /** * * @param option 错误配置项 */ SpyClient.prototype.sendExcept = function (option) { this.send(assign({ type: 'except', }, option)); }; /** * * @param option 配置 */ SpyClient.prototype.sendDist = function (option) { this.send(assign({ type: 'dist', }, option)); }; /** * * @param option 配置 */ SpyClient.prototype.sendCount = function (option) { this.send(assign({ type: 'count', }, option)); }; /** * * @param e 错误实例 * @param option 错误配置项 */ SpyClient.prototype.sendExceptForError = function (e, option) { var newOpt = assign({}, option); newOpt.info = assign({}, option.info || {}, { msg: e.message, stack: e.stack, }); this.sendExcept(newOpt); }; SpyClient.prototype.startMark = function (sign) { this.markCache[sign] = { start: Date.now(), }; }; SpyClient.prototype.endMark = function (sign) { if (this.markCache[sign]) { this.markCache[sign].total = Date.now() - this.markCache[sign].start; return this.markCache[sign].total; } return 0; }; SpyClient.prototype.clearMark = function (sign) { if (this.markCache[sign]) { delete this.markCache[sign]; } }; SpyClient.prototype.getAllMark = function () { var ret = {}; for (var _i = 0, _a = Object.keys(this.markCache); _i < _a.length; _i++) { var sign = _a[_i]; ret[sign] = this.markCache[sign].total; } return ret; }; SpyClient.prototype.clearAllMark = function () { this.markCache = {}; }; // send(data, true) 也能以post发送,但是会有严格校验 // sendPost能以post发送,但没有校验 SpyClient.prototype.sendPost = function (data) { var logItems = isArray(data) ? data : [data]; var first = logItems[0]; // 需要在页面暴漏出来pid等基本信息,方式调试查看基本信息与兼容目前的监控 var query = { pid: first.pid, type: first.type, group: first.group, }; var url = this.option.logServer + stringify(query); this.request(url, data); }; // 有data时,意味着要用post发送请求 SpyClient.prototype.request = function (url, data) { if (!(!isLtIos14 && navigator && navigator.sendBeacon && navigator.sendBeacon(url, data ? JSON.stringify(data) : undefined))) { if (data) { this.fetch(url, data); } else { (new Image()).src = url; } } }; SpyClient.prototype.fetch = function (url, data) { if (!fetch) { err('Global fetch method doesn\'t exist'); return; } fetch(url, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); }; return SpyClient; }()); return SpyClient; }));