spy-client 2.1.14 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +7 -4
- package/AGENTS.md +132 -0
- package/README.md +29 -18
- package/dist/head/base.d.ts +27 -25
- package/dist/head/error.d.ts +6 -6
- package/dist/head/observer.d.ts +5 -5
- package/dist/head/whitescreen.d.ts +6 -6
- package/dist/lib/data.d.ts +6 -6
- package/dist/lib/huffman.d.ts +9 -9
- package/dist/lib/interface.d.ts +209 -209
- package/dist/lib/spyHeadInterface.d.ts +36 -28
- package/dist/lib/util.d.ts +22 -22
- package/dist/module/fid.d.ts +15 -15
- package/dist/module/layoutShift.d.ts +18 -18
- package/dist/module/lcp.d.ts +17 -17
- package/dist/module/longtask.d.ts +46 -46
- package/dist/module/memory.d.ts +11 -11
- package/dist/module/navigatorInfo.d.ts +9 -9
- package/dist/module/resource.d.ts +39 -39
- package/dist/module/timing.d.ts +11 -11
- package/dist/module/tti.d.ts +19 -19
- package/dist/spy-client-basic.d.ts +118 -104
- package/dist/spy-client-basic.esm.js +298 -294
- package/dist/spy-client-basic.iife.js +298 -294
- package/dist/spy-client-basic.iife.min.js +1 -1
- package/dist/spy-client-basic.js +298 -294
- package/dist/spy-client-basic.min.js +1 -1
- package/dist/spy-client-basic.mjs +298 -294
- package/dist/spy-client.d.ts +32 -32
- package/dist/spy-client.esm.js +1430 -1419
- package/dist/spy-client.iife.js +1430 -1419
- package/dist/spy-client.iife.min.js +1 -1
- package/dist/spy-client.js +1430 -1419
- package/dist/spy-client.min.js +1 -1
- package/dist/spy-client.mjs +1430 -1419
- package/dist/spy-head.d.ts +6 -6
- package/dist/spy-head.js +359 -355
- package/dist/spy-head.min.js +1 -1
- package/dist/spy-local-cache.d.ts +18 -18
- package/dist/spy-local-cache.js +718 -711
- package/dist/spy-local-cache.min.js +1 -1
- package/package.json +26 -73
- package/test-results/.last-run.json +4 -0
- package/karma.conf.js +0 -111
package/dist/spy-head.js
CHANGED
|
@@ -4,371 +4,375 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.__spyHead = factory());
|
|
5
5
|
})(this, (function () { 'use strict';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* @file utils
|
|
9
|
-
* @author kaivean
|
|
10
|
-
*/
|
|
11
|
-
function getUrlInfoFromURL(url) {
|
|
12
|
-
if (URL && url) {
|
|
13
|
-
try {
|
|
14
|
-
var obj = new URL(url);
|
|
15
|
-
if (obj.host !== undefined) {
|
|
16
|
-
return {
|
|
17
|
-
protocol: obj.protocol,
|
|
18
|
-
host: obj.host,
|
|
19
|
-
pathname: obj.pathname,
|
|
20
|
-
ext: '',
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
console.error(e);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
function getUrlInfo(url) {
|
|
31
|
-
var info = getUrlInfoFromURL(url);
|
|
32
|
-
if (!info) {
|
|
33
|
-
var parser = document.createElement('a');
|
|
34
|
-
parser.href = url;
|
|
35
|
-
info = {
|
|
36
|
-
protocol: parser.protocol,
|
|
37
|
-
host: parser.host || location.host,
|
|
38
|
-
pathname: parser.pathname,
|
|
39
|
-
ext: '',
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
var split = info.pathname.split('.');
|
|
43
|
-
info.ext = split[split.length - 1];
|
|
44
|
-
return info;
|
|
45
|
-
}
|
|
46
|
-
function f(n) {
|
|
47
|
-
return +n.toFixed(1);
|
|
48
|
-
}
|
|
49
|
-
function getResTiming(t) {
|
|
50
|
-
return {
|
|
51
|
-
wait: f(t.domainLookupStart - (t.navigationStart || t.fetchStart || t.startTime)),
|
|
52
|
-
dns: f(t.domainLookupEnd - t.domainLookupStart),
|
|
53
|
-
connect: f(t.connectEnd - t.connectStart),
|
|
54
|
-
req: f(t.responseStart - t.requestStart),
|
|
55
|
-
res: f(t.responseEnd - t.responseStart),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function getxpath(el) {
|
|
59
|
-
if (!el) {
|
|
60
|
-
return { xpath: '' };
|
|
61
|
-
}
|
|
62
|
-
var xpath = [];
|
|
63
|
-
while (el && el.nodeType === 1 && el !== el.parentNode) {
|
|
64
|
-
var t = el.tagName.toLowerCase();
|
|
65
|
-
if (el.getAttribute('id')) {
|
|
66
|
-
t += '[#' + el.getAttribute('id') + ']';
|
|
67
|
-
}
|
|
68
|
-
else if (el.classList && el.classList.length) {
|
|
69
|
-
t += '[.' + el.classList[el.classList.length - 1] + ']';
|
|
70
|
-
}
|
|
71
|
-
xpath.push(t);
|
|
72
|
-
if (el === document.body) {
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
el = el.parentNode; // 修复缺陷检查
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
xpath: xpath.join('<'),
|
|
79
|
-
};
|
|
7
|
+
/**
|
|
8
|
+
* @file utils
|
|
9
|
+
* @author kaivean
|
|
10
|
+
*/
|
|
11
|
+
function getUrlInfoFromURL(url) {
|
|
12
|
+
if (URL && url) {
|
|
13
|
+
try {
|
|
14
|
+
var obj = new URL(url);
|
|
15
|
+
if (obj.host !== undefined) {
|
|
16
|
+
return {
|
|
17
|
+
protocol: obj.protocol,
|
|
18
|
+
host: obj.host,
|
|
19
|
+
pathname: obj.pathname,
|
|
20
|
+
ext: '',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
console.error(e);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
function getUrlInfo(url) {
|
|
31
|
+
var info = getUrlInfoFromURL(url);
|
|
32
|
+
if (!info) {
|
|
33
|
+
var parser = document.createElement('a');
|
|
34
|
+
parser.href = url;
|
|
35
|
+
info = {
|
|
36
|
+
protocol: parser.protocol,
|
|
37
|
+
host: parser.host || location.host,
|
|
38
|
+
pathname: parser.pathname,
|
|
39
|
+
ext: '',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var split = info.pathname.split('.');
|
|
43
|
+
info.ext = split[split.length - 1];
|
|
44
|
+
return info;
|
|
45
|
+
}
|
|
46
|
+
function f(n) {
|
|
47
|
+
return +n.toFixed(1);
|
|
48
|
+
}
|
|
49
|
+
function getResTiming(t) {
|
|
50
|
+
return {
|
|
51
|
+
wait: f(t.domainLookupStart - (t.navigationStart || t.fetchStart || t.startTime)),
|
|
52
|
+
dns: f(t.domainLookupEnd - t.domainLookupStart),
|
|
53
|
+
connect: f(t.connectEnd - t.connectStart),
|
|
54
|
+
req: f(t.responseStart - t.requestStart),
|
|
55
|
+
res: f(t.responseEnd - t.responseStart),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function getxpath(el) {
|
|
59
|
+
if (!el) {
|
|
60
|
+
return { xpath: '' };
|
|
61
|
+
}
|
|
62
|
+
var xpath = [];
|
|
63
|
+
while (el && el.nodeType === 1 && el !== el.parentNode) {
|
|
64
|
+
var t = el.tagName.toLowerCase();
|
|
65
|
+
if (el.getAttribute('id')) {
|
|
66
|
+
t += '[#' + el.getAttribute('id') + ']';
|
|
67
|
+
}
|
|
68
|
+
else if (el.classList && el.classList.length) {
|
|
69
|
+
t += '[.' + el.classList[el.classList.length - 1] + ']';
|
|
70
|
+
}
|
|
71
|
+
xpath.push(t);
|
|
72
|
+
if (el === document.body) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
el = el.parentNode; // 修复缺陷检查
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
xpath: xpath.join('<'),
|
|
79
|
+
};
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
/**
|
|
83
|
-
* @file 资源、JS、白屏监控的基础
|
|
84
|
-
* @author kaivean
|
|
85
|
-
*/
|
|
86
|
-
var spyHead = {
|
|
87
|
-
conf: {},
|
|
88
|
-
winerrors: [],
|
|
89
|
-
errorDestroy: function () { },
|
|
90
|
-
observerDestroy: function () { },
|
|
91
|
-
entryMap: {},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
82
|
+
/**
|
|
83
|
+
* @file 资源、JS、白屏监控的基础
|
|
84
|
+
* @author kaivean
|
|
85
|
+
*/
|
|
86
|
+
var spyHead = {
|
|
87
|
+
conf: {},
|
|
88
|
+
winerrors: [],
|
|
89
|
+
errorDestroy: function () { },
|
|
90
|
+
observerDestroy: function () { },
|
|
91
|
+
entryMap: {},
|
|
92
|
+
interceptor: undefined,
|
|
93
|
+
init: function (conf) {
|
|
94
|
+
this.conf = conf;
|
|
95
|
+
},
|
|
96
|
+
update: function (conf) {
|
|
97
|
+
this.conf = Object.assign(this.conf, conf || {});
|
|
98
|
+
},
|
|
99
|
+
addError: function (obj) {
|
|
100
|
+
// 有些错误一下出现很多次,都聚合都一个错误,加上次数
|
|
101
|
+
if (this.winerrors.length > 0) {
|
|
102
|
+
var lastObj = this.winerrors[this.winerrors.length - 1];
|
|
103
|
+
if (obj.info.msg === lastObj.info.msg) {
|
|
104
|
+
lastObj.info.count += (lastObj.info.count || 0);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (this.winerrors.length < 1000) {
|
|
109
|
+
this.winerrors.push(obj);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
send: function (obj, isSend, logServer) {
|
|
113
|
+
var conf = this.conf;
|
|
114
|
+
obj.type = obj.type || 'except';
|
|
115
|
+
obj.pid = conf.pid;
|
|
116
|
+
obj.lid = conf.lid;
|
|
117
|
+
obj.ts = Date.now();
|
|
118
|
+
this.addError(obj);
|
|
119
|
+
this.interceptor && this.interceptor(obj);
|
|
120
|
+
if (isSend === false) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
logServer = logServer || conf.logServer;
|
|
124
|
+
var logUrl = "".concat(logServer, "?pid=").concat(obj.pid, "&lid=").concat(obj.lid, "&ts=").concat(obj.ts)
|
|
125
|
+
+ "&type=".concat(obj.type, "&group=").concat(obj.group, "&info=").concat(encodeURIComponent(JSON.stringify(obj.info)));
|
|
126
|
+
if (obj.dim) {
|
|
127
|
+
logUrl += '&dim=' + encodeURIComponent(JSON.stringify(obj.dim));
|
|
128
|
+
}
|
|
129
|
+
var img = new Image();
|
|
130
|
+
img.src = logUrl;
|
|
131
|
+
img.onload = img.onerror = function () {
|
|
132
|
+
img = null;
|
|
133
|
+
};
|
|
134
|
+
},
|
|
131
135
|
};
|
|
132
136
|
|
|
133
|
-
/**
|
|
134
|
-
* @file 资源和JS错误监控
|
|
135
|
-
* @author kaivean
|
|
136
|
-
*/
|
|
137
|
-
function init$2(conf) {
|
|
138
|
-
var resourceError = conf.resourceError || {};
|
|
139
|
-
var jsError = conf.jsError || {};
|
|
140
|
-
var isSendJserror = Math.random() < (jsError.sample ? jsError.sample : 0);
|
|
141
|
-
var isSendResource = Math.random() < (resourceError.sample ? resourceError.sample : 0);
|
|
142
|
-
var winerrors = spyHead.winerrors;
|
|
143
|
-
var resourceErrorCount = 0;
|
|
144
|
-
function spyListenError(event) {
|
|
145
|
-
try {
|
|
146
|
-
var el = event.target;
|
|
147
|
-
var obj = { info: {}, dim: {}, group: '' };
|
|
148
|
-
var info = obj.info;
|
|
149
|
-
var srcElement = event.srcElement;
|
|
150
|
-
// 设备信息
|
|
151
|
-
|
|
152
|
-
info.downlink = dataConnection.downlink; // 网站下载速度 M/s
|
|
153
|
-
info.effectiveType = dataConnection.effectiveType; // 网络类型
|
|
154
|
-
info.rtt = dataConnection.rtt; // 网络往返时间 ms
|
|
155
|
-
info.deviceMemory = navigator.deviceMemory || 0;
|
|
156
|
-
info.hardwareConcurrency = navigator.hardwareConcurrency || 0;
|
|
157
|
-
// JS错误
|
|
158
|
-
if (srcElement === window) {
|
|
159
|
-
obj.group = jsError.group;
|
|
160
|
-
// 异常信息
|
|
161
|
-
// promise错误从reason取
|
|
162
|
-
var error = (event.error || event.reason) || {};
|
|
163
|
-
// promise错误从error.message取
|
|
164
|
-
info.msg = event.message || error.message || '';
|
|
165
|
-
info.file = event.filename;
|
|
166
|
-
info.ln = event.lineno;
|
|
167
|
-
info.col = event.colno;
|
|
168
|
-
info.stack = (error.stack || '').split('\n').slice(0, 3).join('\n');
|
|
169
|
-
// 针对esl的MODULE_TIMEOUT处理
|
|
170
|
-
if (info.msg.indexOf('MODULE_TIMEOUT') !== -1) {
|
|
171
|
-
var matches = info.msg.match(/^.*Hang:(.*); Miss:(.*)/);
|
|
172
|
-
if (matches && matches[2]) {
|
|
173
|
-
info.msg = 'MODULE_TIMEOUT for miss:' + (matches[2]);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// 历史错误
|
|
177
|
-
var historys = [];
|
|
178
|
-
for (var index = 0; index < winerrors.length; index++) {
|
|
179
|
-
var item = winerrors[index];
|
|
180
|
-
var prefix = item.info.count > 1 ? "(".concat(item.info.count, ")") : '';
|
|
181
|
-
historys.push(prefix + item.info.msg);
|
|
182
|
-
}
|
|
183
|
-
info.hisErrors = historys.join('----');
|
|
184
|
-
var allow = true;
|
|
185
|
-
if (jsError.handler) {
|
|
186
|
-
allow = jsError.handler(obj);
|
|
187
|
-
}
|
|
188
|
-
if (allow !== false) {
|
|
189
|
-
spyHead.send(obj, isSendJserror);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// 资源错误
|
|
193
|
-
else {
|
|
194
|
-
obj.group = resourceError.group;
|
|
195
|
-
obj.dim.type = srcElement.tagName.toLowerCase();
|
|
196
|
-
var url = srcElement.src || srcElement.href || '';
|
|
197
|
-
// 日志本身失败,要忽略
|
|
198
|
-
if (url.indexOf('/mwb2.gif?') > -1) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
info.msg = url || 'unknown load eror';
|
|
202
|
-
obj.dim.host = getUrlInfo(url).host;
|
|
203
|
-
if (el && el.tagName === 'IMG') {
|
|
204
|
-
info.xpath = getxpath(el).xpath;
|
|
205
|
-
}
|
|
206
|
-
if (resourceErrorCount) {
|
|
207
|
-
info.hisErrCount = resourceErrorCount;
|
|
208
|
-
}
|
|
209
|
-
var allow = true;
|
|
210
|
-
if (resourceError.handler) {
|
|
211
|
-
allow = resourceError.handler(obj);
|
|
212
|
-
}
|
|
213
|
-
if (allow !== false) {
|
|
214
|
-
spyHead.send(obj, isSendResource);
|
|
215
|
-
}
|
|
216
|
-
resourceErrorCount++;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch (e) {
|
|
220
|
-
console.error(e);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
window.addEventListener('error', spyListenError, true);
|
|
224
|
-
// Promise未处理拒绝监控
|
|
225
|
-
window.addEventListener('unhandledrejection', spyListenError, true);
|
|
226
|
-
spyHead.errorDestroy = function () {
|
|
227
|
-
window.removeEventListener('error', spyListenError, true);
|
|
228
|
-
window.removeEventListener('unhandledrejection', spyListenError, true);
|
|
229
|
-
spyHead.winerrors = [];
|
|
230
|
-
};
|
|
137
|
+
/**
|
|
138
|
+
* @file 资源和JS错误监控
|
|
139
|
+
* @author kaivean
|
|
140
|
+
*/
|
|
141
|
+
function init$2(conf) {
|
|
142
|
+
var resourceError = conf.resourceError || {};
|
|
143
|
+
var jsError = conf.jsError || {};
|
|
144
|
+
var isSendJserror = Math.random() < (jsError.sample ? jsError.sample : 0);
|
|
145
|
+
var isSendResource = Math.random() < (resourceError.sample ? resourceError.sample : 0);
|
|
146
|
+
var winerrors = spyHead.winerrors;
|
|
147
|
+
var resourceErrorCount = 0;
|
|
148
|
+
function spyListenError(event) {
|
|
149
|
+
try {
|
|
150
|
+
var el = event.target;
|
|
151
|
+
var obj = { info: {}, dim: {}, group: '' };
|
|
152
|
+
var info = obj.info;
|
|
153
|
+
var srcElement = event.srcElement;
|
|
154
|
+
// 设备信息
|
|
155
|
+
// const dataConnection = navigator.connection || {};
|
|
156
|
+
// info.downlink = dataConnection.downlink; // 网站下载速度 M/s
|
|
157
|
+
// info.effectiveType = dataConnection.effectiveType; // 网络类型
|
|
158
|
+
// info.rtt = dataConnection.rtt; // 网络往返时间 ms
|
|
159
|
+
// info.deviceMemory = navigator.deviceMemory || 0;
|
|
160
|
+
// info.hardwareConcurrency = navigator.hardwareConcurrency || 0;
|
|
161
|
+
// JS错误
|
|
162
|
+
if (srcElement === window) {
|
|
163
|
+
obj.group = jsError.group;
|
|
164
|
+
// 异常信息
|
|
165
|
+
// promise错误从reason取
|
|
166
|
+
var error = (event.error || event.reason) || {};
|
|
167
|
+
// promise错误从error.message取
|
|
168
|
+
info.msg = event.message || error.message || '';
|
|
169
|
+
info.file = event.filename;
|
|
170
|
+
info.ln = event.lineno;
|
|
171
|
+
info.col = event.colno;
|
|
172
|
+
info.stack = (error.stack || '').split('\n').slice(0, 3).join('\n');
|
|
173
|
+
// 针对esl的MODULE_TIMEOUT处理
|
|
174
|
+
if (info.msg.indexOf('MODULE_TIMEOUT') !== -1) {
|
|
175
|
+
var matches = info.msg.match(/^.*Hang:(.*); Miss:(.*)/);
|
|
176
|
+
if (matches && matches[2]) {
|
|
177
|
+
info.msg = 'MODULE_TIMEOUT for miss:' + (matches[2]);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// 历史错误
|
|
181
|
+
var historys = [];
|
|
182
|
+
for (var index = 0; index < winerrors.length; index++) {
|
|
183
|
+
var item = winerrors[index];
|
|
184
|
+
var prefix = item.info.count > 1 ? "(".concat(item.info.count, ")") : '';
|
|
185
|
+
historys.push(prefix + item.info.msg);
|
|
186
|
+
}
|
|
187
|
+
info.hisErrors = historys.join('----');
|
|
188
|
+
var allow = true;
|
|
189
|
+
if (jsError.handler) {
|
|
190
|
+
allow = jsError.handler(obj);
|
|
191
|
+
}
|
|
192
|
+
if (allow !== false) {
|
|
193
|
+
spyHead.send(obj, isSendJserror);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// 资源错误
|
|
197
|
+
else {
|
|
198
|
+
obj.group = resourceError.group;
|
|
199
|
+
obj.dim.type = srcElement.tagName.toLowerCase();
|
|
200
|
+
var url = srcElement.src || srcElement.href || '';
|
|
201
|
+
// 日志本身失败,要忽略
|
|
202
|
+
if (url.indexOf('/mwb2.gif?') > -1) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
info.msg = url || 'unknown load eror';
|
|
206
|
+
obj.dim.host = getUrlInfo(url).host;
|
|
207
|
+
if (el && el.tagName === 'IMG') {
|
|
208
|
+
info.xpath = getxpath(el).xpath;
|
|
209
|
+
}
|
|
210
|
+
if (resourceErrorCount) {
|
|
211
|
+
info.hisErrCount = resourceErrorCount;
|
|
212
|
+
}
|
|
213
|
+
var allow = true;
|
|
214
|
+
if (resourceError.handler) {
|
|
215
|
+
allow = resourceError.handler(obj);
|
|
216
|
+
}
|
|
217
|
+
if (allow !== false) {
|
|
218
|
+
spyHead.send(obj, isSendResource);
|
|
219
|
+
}
|
|
220
|
+
resourceErrorCount++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (e) {
|
|
224
|
+
console.error(e);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
window.addEventListener('error', spyListenError, true);
|
|
228
|
+
// Promise未处理拒绝监控
|
|
229
|
+
window.addEventListener('unhandledrejection', spyListenError, true);
|
|
230
|
+
spyHead.errorDestroy = function () {
|
|
231
|
+
window.removeEventListener('error', spyListenError, true);
|
|
232
|
+
window.removeEventListener('unhandledrejection', spyListenError, true);
|
|
233
|
+
spyHead.winerrors = [];
|
|
234
|
+
};
|
|
231
235
|
}
|
|
232
236
|
|
|
233
|
-
/**
|
|
234
|
-
* @file PerformanceObserver指标采集
|
|
235
|
-
* @author kaivean
|
|
236
|
-
*/
|
|
237
|
-
function init$1() {
|
|
238
|
-
// Longtask监控
|
|
239
|
-
if (window.PerformanceObserver) {
|
|
240
|
-
var observer_1 = new window.PerformanceObserver(function spyObserveLongtask(list) {
|
|
241
|
-
var entryMap = spyHead.entryMap;
|
|
242
|
-
var entries = list.getEntries();
|
|
243
|
-
for (var i = 0; i < entries.length; i++) {
|
|
244
|
-
var entry = entries[i];
|
|
245
|
-
if (!entryMap[entry.entryType]) {
|
|
246
|
-
entryMap[entry.entryType] = [];
|
|
247
|
-
}
|
|
248
|
-
entryMap[entry.entryType].push(entry);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
spyHead.observerDestroy = function () {
|
|
252
|
-
observer_1.disconnect();
|
|
253
|
-
};
|
|
254
|
-
// 在ios下,没有一个类似的监控项是支持的,就抛错,chrome会console warn
|
|
255
|
-
try {
|
|
256
|
-
observer_1.observe({ entryTypes: [
|
|
257
|
-
'longtask',
|
|
258
|
-
'layout-shift',
|
|
259
|
-
'first-input',
|
|
260
|
-
'largest-contentful-paint',
|
|
261
|
-
] });
|
|
262
|
-
}
|
|
263
|
-
catch (e) { }
|
|
264
|
-
}
|
|
237
|
+
/**
|
|
238
|
+
* @file PerformanceObserver指标采集
|
|
239
|
+
* @author kaivean
|
|
240
|
+
*/
|
|
241
|
+
function init$1() {
|
|
242
|
+
// Longtask监控
|
|
243
|
+
if (window.PerformanceObserver) {
|
|
244
|
+
var observer_1 = new window.PerformanceObserver(function spyObserveLongtask(list) {
|
|
245
|
+
var entryMap = spyHead.entryMap;
|
|
246
|
+
var entries = list.getEntries();
|
|
247
|
+
for (var i = 0; i < entries.length; i++) {
|
|
248
|
+
var entry = entries[i];
|
|
249
|
+
if (!entryMap[entry.entryType]) {
|
|
250
|
+
entryMap[entry.entryType] = [];
|
|
251
|
+
}
|
|
252
|
+
entryMap[entry.entryType].push(entry);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
spyHead.observerDestroy = function () {
|
|
256
|
+
observer_1.disconnect();
|
|
257
|
+
};
|
|
258
|
+
// 在ios下,没有一个类似的监控项是支持的,就抛错,chrome会console warn
|
|
259
|
+
try {
|
|
260
|
+
observer_1.observe({ entryTypes: [
|
|
261
|
+
'longtask',
|
|
262
|
+
'layout-shift',
|
|
263
|
+
'first-input',
|
|
264
|
+
'largest-contentful-paint',
|
|
265
|
+
] });
|
|
266
|
+
}
|
|
267
|
+
catch (e) { }
|
|
268
|
+
}
|
|
265
269
|
}
|
|
266
270
|
|
|
267
|
-
/**
|
|
268
|
-
* @file 白屏监控
|
|
269
|
-
* @author kaivean
|
|
270
|
-
*/
|
|
271
|
-
function init(conf) {
|
|
272
|
-
var whiteScreenError = conf.whiteScreenError || {};
|
|
273
|
-
var handler = whiteScreenError.handler;
|
|
274
|
-
var selector = whiteScreenError.selector;
|
|
275
|
-
var subSelector = whiteScreenError.subSelector;
|
|
276
|
-
var timeout = whiteScreenError.timeout || 6000;
|
|
277
|
-
var isSend = Math.random() < (whiteScreenError.sample ? whiteScreenError.sample : 0);
|
|
278
|
-
// 补充白屏信息:期间的网络时间
|
|
279
|
-
function getNetTime() {
|
|
280
|
-
if (!window.performance) {
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
var pf = getResTiming(window.performance.timing);
|
|
284
|
-
var netStr = "&wait=".concat(pf.wait)
|
|
285
|
-
+ "&dns=".concat(pf.dns)
|
|
286
|
-
+ "&connect=".concat(pf.connect)
|
|
287
|
-
+ "&requestTime=".concat(pf.req)
|
|
288
|
-
+ "&resoneTime=".concat(pf.res);
|
|
289
|
-
return netStr;
|
|
290
|
-
}
|
|
291
|
-
// 补充白屏信息:期间发生的JS Error 和 资源 Error
|
|
292
|
-
function getHisError() {
|
|
293
|
-
if (!(spyHead.winerrors)) {
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
var errors = spyHead.winerrors;
|
|
297
|
-
var historys = [];
|
|
298
|
-
for (var i = 0; i < errors.length; i++) {
|
|
299
|
-
var stack = (errors[i].info.stack || '').split('\n')[0];
|
|
300
|
-
historys.push("(".concat(i, ")").concat(stack || errors[i].info.msg));
|
|
301
|
-
}
|
|
302
|
-
return historys.join(';;');
|
|
303
|
-
}
|
|
304
|
-
// 补充白屏信息: 设备信息
|
|
305
|
-
function getDeviceInfo() {
|
|
306
|
-
var ret = {};
|
|
307
|
-
// 设备信息
|
|
308
|
-
var dataConnection = navigator.connection || {};
|
|
309
|
-
ret.downlink = dataConnection.downlink; // 网站下载速度 M/s
|
|
310
|
-
ret.effectiveType = dataConnection.effectiveType; // 网络类型
|
|
311
|
-
ret.rtt = dataConnection.rtt; // 网络往返时间 ms
|
|
312
|
-
ret.deviceMemory = navigator.deviceMemory || 0;
|
|
313
|
-
ret.hardwareConcurrency = navigator.hardwareConcurrency || 0;
|
|
314
|
-
return ret;
|
|
315
|
-
}
|
|
316
|
-
function isWhiteScreen() {
|
|
317
|
-
var ele = document.querySelector(selector);
|
|
318
|
-
if (!ele) {
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
var sub = ele.querySelector(subSelector);
|
|
322
|
-
if (!sub) {
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
if (ele.clientHeight < (window.innerHeight * 2 / 3)) {
|
|
326
|
-
return true;
|
|
327
|
-
}
|
|
328
|
-
return false;
|
|
329
|
-
}
|
|
330
|
-
if (selector) {
|
|
331
|
-
setTimeout(function () {
|
|
332
|
-
if (isWhiteScreen()) {
|
|
333
|
-
var obj = {
|
|
334
|
-
group: whiteScreenError.group,
|
|
335
|
-
info: {
|
|
336
|
-
msg: '',
|
|
337
|
-
netTime: getNetTime(),
|
|
338
|
-
hisErrors: getHisError(),
|
|
339
|
-
deviceInfo: getDeviceInfo(),
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
obj.info.msg = 'WhiteScren Error';
|
|
343
|
-
var allow = true;
|
|
344
|
-
if (handler) {
|
|
345
|
-
allow = handler(obj);
|
|
346
|
-
}
|
|
347
|
-
if (allow !== false && obj.info.msg) {
|
|
348
|
-
spyHead && spyHead.send(obj, isSend);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}, timeout);
|
|
352
|
-
}
|
|
271
|
+
/**
|
|
272
|
+
* @file 白屏监控
|
|
273
|
+
* @author kaivean
|
|
274
|
+
*/
|
|
275
|
+
function init(conf) {
|
|
276
|
+
var whiteScreenError = conf.whiteScreenError || {};
|
|
277
|
+
var handler = whiteScreenError.handler;
|
|
278
|
+
var selector = whiteScreenError.selector;
|
|
279
|
+
var subSelector = whiteScreenError.subSelector;
|
|
280
|
+
var timeout = whiteScreenError.timeout || 6000;
|
|
281
|
+
var isSend = Math.random() < (whiteScreenError.sample ? whiteScreenError.sample : 0);
|
|
282
|
+
// 补充白屏信息:期间的网络时间
|
|
283
|
+
function getNetTime() {
|
|
284
|
+
if (!window.performance) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
var pf = getResTiming(window.performance.timing);
|
|
288
|
+
var netStr = "&wait=".concat(pf.wait)
|
|
289
|
+
+ "&dns=".concat(pf.dns)
|
|
290
|
+
+ "&connect=".concat(pf.connect)
|
|
291
|
+
+ "&requestTime=".concat(pf.req)
|
|
292
|
+
+ "&resoneTime=".concat(pf.res);
|
|
293
|
+
return netStr;
|
|
294
|
+
}
|
|
295
|
+
// 补充白屏信息:期间发生的JS Error 和 资源 Error
|
|
296
|
+
function getHisError() {
|
|
297
|
+
if (!(spyHead.winerrors)) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
var errors = spyHead.winerrors;
|
|
301
|
+
var historys = [];
|
|
302
|
+
for (var i = 0; i < errors.length; i++) {
|
|
303
|
+
var stack = (errors[i].info.stack || '').split('\n')[0];
|
|
304
|
+
historys.push("(".concat(i, ")").concat(stack || errors[i].info.msg));
|
|
305
|
+
}
|
|
306
|
+
return historys.join(';;');
|
|
307
|
+
}
|
|
308
|
+
// 补充白屏信息: 设备信息
|
|
309
|
+
function getDeviceInfo() {
|
|
310
|
+
var ret = {};
|
|
311
|
+
// 设备信息
|
|
312
|
+
var dataConnection = navigator.connection || {};
|
|
313
|
+
ret.downlink = dataConnection.downlink; // 网站下载速度 M/s
|
|
314
|
+
ret.effectiveType = dataConnection.effectiveType; // 网络类型
|
|
315
|
+
ret.rtt = dataConnection.rtt; // 网络往返时间 ms
|
|
316
|
+
ret.deviceMemory = navigator.deviceMemory || 0;
|
|
317
|
+
ret.hardwareConcurrency = navigator.hardwareConcurrency || 0;
|
|
318
|
+
return ret;
|
|
319
|
+
}
|
|
320
|
+
function isWhiteScreen() {
|
|
321
|
+
var ele = document.querySelector(selector);
|
|
322
|
+
if (!ele) {
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
var sub = ele.querySelector(subSelector);
|
|
326
|
+
if (!sub) {
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
if (ele.clientHeight < (window.innerHeight * 2 / 3)) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
if (selector) {
|
|
335
|
+
setTimeout(function () {
|
|
336
|
+
if (isWhiteScreen()) {
|
|
337
|
+
var obj = {
|
|
338
|
+
group: whiteScreenError.group,
|
|
339
|
+
info: {
|
|
340
|
+
msg: '',
|
|
341
|
+
netTime: getNetTime(),
|
|
342
|
+
hisErrors: getHisError(),
|
|
343
|
+
deviceInfo: getDeviceInfo(),
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
obj.info.msg = 'WhiteScren Error';
|
|
347
|
+
var allow = true;
|
|
348
|
+
if (handler) {
|
|
349
|
+
allow = handler(obj);
|
|
350
|
+
}
|
|
351
|
+
if (allow !== false && obj.info.msg) {
|
|
352
|
+
spyHead && spyHead.send(obj, isSend);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}, timeout);
|
|
356
|
+
}
|
|
353
357
|
}
|
|
354
358
|
|
|
355
|
-
/**
|
|
356
|
-
* @file SpyClient
|
|
357
|
-
* @author kaivean
|
|
358
|
-
*/
|
|
359
|
-
spyHead.init = function (conf) {
|
|
360
|
-
if (!conf.logServer) {
|
|
361
|
-
conf.logServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif';
|
|
362
|
-
}
|
|
363
|
-
this.conf = conf;
|
|
364
|
-
init$2(conf);
|
|
365
|
-
init$1();
|
|
366
|
-
init(conf);
|
|
367
|
-
};
|
|
368
|
-
// 兼容全局变量定义的初始化方式
|
|
369
|
-
if (window.__spyclientConf) {
|
|
370
|
-
spyHead.init(window.__spyclientConf);
|
|
371
|
-
}
|
|
359
|
+
/**
|
|
360
|
+
* @file SpyClient
|
|
361
|
+
* @author kaivean
|
|
362
|
+
*/
|
|
363
|
+
spyHead.init = function (conf) {
|
|
364
|
+
if (!conf.logServer) {
|
|
365
|
+
conf.logServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif';
|
|
366
|
+
}
|
|
367
|
+
this.conf = conf;
|
|
368
|
+
init$2(conf);
|
|
369
|
+
init$1();
|
|
370
|
+
init(conf);
|
|
371
|
+
};
|
|
372
|
+
// 兼容全局变量定义的初始化方式
|
|
373
|
+
if (window.__spyclientConf) {
|
|
374
|
+
spyHead.init(window.__spyclientConf);
|
|
375
|
+
}
|
|
372
376
|
window.__spyHead = window.__spyHead || spyHead;
|
|
373
377
|
|
|
374
378
|
return spyHead;
|