spy-client
Version:
spy client
308 lines (303 loc) • 11.5 kB
JavaScript
(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;
}));