spy-client 2.1.1-alpha.4 → 2.1.4

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.
Files changed (70) hide show
  1. package/README.md +9 -3
  2. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/base.css +224 -0
  3. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/basicSpec.ts.html +740 -0
  4. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/block-navigation.js +79 -0
  5. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/checkSpec.ts.html +479 -0
  6. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/favicon.png +0 -0
  7. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/headSpec.ts.html +695 -0
  8. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/index.html +171 -0
  9. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/markSpec.ts.html +284 -0
  10. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/metricSpec.ts.html +977 -0
  11. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/prettify.css +1 -0
  12. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/prettify.js +2 -0
  13. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  14. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/sorter.js +170 -0
  15. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/base.css +224 -0
  16. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/basicSpec.ts.html +740 -0
  17. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/block-navigation.js +79 -0
  18. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/checkSpec.ts.html +479 -0
  19. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/favicon.png +0 -0
  20. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/headSpec.ts.html +695 -0
  21. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/index.html +171 -0
  22. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/markSpec.ts.html +284 -0
  23. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/metricSpec.ts.html +977 -0
  24. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/prettify.css +1 -0
  25. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/prettify.js +2 -0
  26. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  27. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/sorter.js +170 -0
  28. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/base.css +224 -0
  29. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/basicSpec.ts.html +740 -0
  30. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/block-navigation.js +79 -0
  31. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/checkSpec.ts.html +479 -0
  32. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/favicon.png +0 -0
  33. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/headSpec.ts.html +695 -0
  34. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/index.html +171 -0
  35. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/markSpec.ts.html +284 -0
  36. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/metricSpec.ts.html +977 -0
  37. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.css +1 -0
  38. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.js +2 -0
  39. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  40. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sorter.js +170 -0
  41. package/dist/head/base.d.ts +12 -7
  42. package/dist/lib/interface.d.ts +4 -0
  43. package/dist/spy-client-basic.d.ts +4 -1
  44. package/dist/spy-client-basic.esm.js +80 -21
  45. package/dist/spy-client-basic.iife.js +80 -21
  46. package/dist/spy-client-basic.iife.min.js +1 -1
  47. package/dist/spy-client-basic.js +80 -21
  48. package/dist/spy-client-basic.min.js +1 -1
  49. package/dist/spy-client-basic.mjs +80 -21
  50. package/dist/spy-client.d.ts +1 -0
  51. package/dist/spy-client.esm.js +107 -31
  52. package/dist/spy-client.iife.js +107 -31
  53. package/dist/spy-client.iife.min.js +1 -1
  54. package/dist/spy-client.js +107 -31
  55. package/dist/spy-client.min.js +1 -1
  56. package/dist/spy-client.mjs +107 -31
  57. package/dist/spy-head.js +46 -34
  58. package/dist/spy-head.min.js +1 -1
  59. package/dist/spy-local-cache.js +65 -65
  60. package/dist/spy-local-cache.min.js +1 -1
  61. package/example/local-cache.html +77 -15
  62. package/package.json +4 -12
  63. package/src/head/base.ts +37 -4
  64. package/src/head/error.ts +9 -19
  65. package/src/head/whitescreen.ts +14 -14
  66. package/src/lib/huffman.ts +37 -56
  67. package/src/lib/interface.ts +5 -0
  68. package/src/spy-client-basic.ts +92 -23
  69. package/src/spy-client.ts +19 -1
  70. package/src/spy-local-cache.ts +41 -16
@@ -69,7 +69,9 @@ interface ErrorOption {
69
69
 
70
70
  const defaultLogServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif?';
71
71
 
72
- const isIos = /(iPhone|iPod|iPad)/.test(navigator.userAgent);
72
+ const ver = navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?)_/);
73
+ const isLtIos14 = ver && ver[2] && (+ver[2] < 14);
74
+
73
75
 
74
76
  function err(msg: string) {
75
77
  console.error(`[SpyClient_log]${msg}`);
@@ -91,6 +93,10 @@ function stringify(obj: any) {
91
93
  }).join('&');
92
94
  }
93
95
 
96
+ function isArray(arr: any) {
97
+ return Object.prototype.toString.call(arr) === '[object Array]';
98
+ }
99
+
94
100
  interface SpyClientInnerOption extends SpyClientOption {
95
101
  logServer: string;
96
102
  }
@@ -113,49 +119,112 @@ export default class SpyClient {
113
119
  lid: option.lid,
114
120
  check: option.check !== false,
115
121
  sample: option.sample,
122
+ localCache: option.localCache,
116
123
  logServer: option.logServer || defaultLogServer,
117
124
  };
118
125
  }
119
126
 
120
- send(query: any) {
121
- if (!this.check(query)) {
127
+ fetch(url: string, data: any) {
128
+ if (!window.fetch) {
122
129
  return;
123
130
  }
131
+ fetch(url, {
132
+ method: 'POST',
133
+ credentials: 'include',
134
+ headers: {
135
+ 'Content-Type': 'application/json',
136
+ },
137
+ body: JSON.stringify(data),
138
+ });
139
+ }
124
140
 
125
- // 当前api设置了抽样,
126
- if (typeof query.sample === 'number') {
127
- if (Math.random() > query.sample) {
128
- return;
129
- }
141
+ sendPost(data: any) {
142
+ let logItems: any[] = isArray(data) ? data : [data];
143
+ const first = logItems[0];
144
+ // 需要在页面暴漏出来pid等基本信息,方式调试查看基本信息与兼容目前的监控
145
+ const query = {
146
+ pid: first.pid,
147
+ type: first.type,
148
+ group: first.group,
149
+ };
150
+ const url = this.option.logServer + stringify(query);
151
+
152
+ if (!(
153
+ !isLtIos14
154
+ && navigator.sendBeacon
155
+ && navigator.sendBeacon(url, JSON.stringify(data))
156
+ )) {
157
+ this.fetch(url, data);
130
158
  }
131
- else if (typeof this.option.sample === 'number' && Math.random() > this.option.sample) { // 否则,用全局抽样
159
+ }
160
+
161
+ handle(logItem: any) {
162
+ if (!this.check(logItem)) {
132
163
  return;
133
164
  }
134
165
 
135
- query = assign(
166
+ logItem = assign(
136
167
  {
137
168
  pid: this.option.pid,
138
169
  lid: this.option.lid,
139
170
  ts: Date.now(),
140
171
  group: 'common',
141
172
  },
142
- query
173
+ logItem
143
174
  );
144
175
 
145
- delete query.sample;
176
+ if (this.option.localCache) {
177
+ this.option.localCache.addLog(logItem);
178
+ }
146
179
 
147
- const url = this.option.logServer + stringify(query);
180
+ // 当前api设置了抽样,
181
+ if (typeof logItem.sample === 'number') {
182
+ if (Math.random() > logItem.sample) {
183
+ return;
184
+ }
185
+ }
186
+ else if (typeof this.option.sample === 'number' && Math.random() > this.option.sample) { // 否则,用全局抽样
187
+ return;
188
+ }
148
189
 
149
- // 目前服务器端支持sendBeacon的post请求,可以优先采用,该api可以降低打点丢失率
150
- // 但是ios有些问题:在webkit浏览内核环境下,beacon requests的请求方式存在证书验证的bug.
151
- // 修复说明在如下链接中:https://bugs.webkit.org/show_bug.cgi?id=193508
152
- // 但是目前为止,在iOS12.2版本中该问题依旧存在
153
- if (!(
154
- !isIos
155
- && navigator.sendBeacon
156
- && navigator.sendBeacon(url)
157
- )) {
158
- (new Image()).src = url;
190
+ delete logItem.sample;
191
+ return logItem;
192
+ }
193
+
194
+ send(data: any, post = false) {
195
+ let logItems: any[] = isArray(data) ? data : [data];
196
+
197
+ let postData = [];
198
+ for (let logItem of logItems) {
199
+ logItem = this.handle(logItem);
200
+ if (!logItem) {
201
+ continue;
202
+ }
203
+
204
+ postData.push(logItem);
205
+
206
+ // 期望通过post方式上传日志
207
+ if (post) {
208
+ continue;
209
+ }
210
+
211
+ const url = this.option.logServer + stringify(logItem);
212
+
213
+ // 目前服务器端支持sendBeacon的post请求,可以优先采用,该api可以降低打点丢失率
214
+ // 但是ios有些问题:在webkit浏览内核环境下,beacon requests的请求方式存在证书验证的bug,发送失败但返回正确.
215
+ // 修复说明在如下链接中:https://bugs.webkit.org/show_bug.cgi?id=193508
216
+ // 但是目前为止,在iOS12.2版本中该问题依旧存在
217
+ // 2021-11-11: 发现ios 14可以送,故小于14的不发送
218
+ if (!(
219
+ !isLtIos14
220
+ && navigator.sendBeacon
221
+ && navigator.sendBeacon(url)
222
+ )) {
223
+ (new Image()).src = url;
224
+ }
225
+ }
226
+ if (post) {
227
+ this.sendPost(postData);
159
228
  }
160
229
  }
161
230
 
package/src/spy-client.ts CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  ResOption,
28
28
  BigImgOption,
29
29
  HttpResOption,
30
- SlowOption
30
+ SlowOption,
31
31
  } from './lib/interface';
32
32
 
33
33
  import FID from './module/fid';
@@ -70,6 +70,24 @@ export default class SpyClient extends SpyClientBasic {
70
70
  document.addEventListener('visibilitychange', this.visibilitychangeCB);
71
71
  window.addEventListener('beforeunload', this.leave, false);
72
72
  window.addEventListener('unload', this.leave, false);
73
+
74
+ this.handleHead();
75
+ }
76
+
77
+ handleHead() {
78
+ if (this.option.localCache) {
79
+ const spyHead = window.__spyHead;
80
+ if (spyHead && spyHead.winerrors) {
81
+ for (let index = 0; index < spyHead.winerrors.length; index++) {
82
+ const obj = spyHead.winerrors[index];
83
+ this.option.localCache.addLog(obj);
84
+ }
85
+ // Head发送的异常,也保存一份到本地,主要是JS错误和资源加载异常
86
+ spyHead.interceptor = (obj: any) => {
87
+ this.option.localCache.addLog(obj);
88
+ };
89
+ }
90
+ }
73
91
  }
74
92
 
75
93
  listenFID(cb: FIDCB) {
@@ -6,9 +6,10 @@ interface Option {
6
6
  key: string;
7
7
  maxRecordLen: number;
8
8
  interval: number;
9
- onFlush: (res: any) => void;
9
+ onFlush?: (res: any) => void;
10
+ onSave?: (res: any) => void;
11
+ onAdd?: (res: any) => boolean;
10
12
  storage: 'indexedDB' | 'localstorage' | 'empty';
11
- costTime?: (time: string) => void;
12
13
  }
13
14
 
14
15
  class Storage {
@@ -280,6 +281,10 @@ export default class SpyLocalCache {
280
281
  interval: 500,
281
282
  maxRecordLen: 30,
282
283
  onFlush: () => {},
284
+ onSave: () => {},
285
+ onAdd: () => {
286
+ return true;
287
+ },
283
288
  storage: IndexedDB.isSupport()
284
289
  ? 'indexedDB'
285
290
  : LS.isSupport()
@@ -318,6 +323,12 @@ export default class SpyLocalCache {
318
323
  }
319
324
 
320
325
  addLog(info: any) {
326
+ if (this.option.onAdd) {
327
+ if (!this.option.onAdd(info)) {
328
+ return;
329
+ }
330
+ }
331
+
321
332
  info = JSON.stringify(info);
322
333
 
323
334
  this.tmpList.push(info as string);
@@ -363,28 +374,42 @@ export default class SpyLocalCache {
363
374
  }
364
375
 
365
376
  save() {
377
+ const st = Date.now();
366
378
  this.getData((list: any[]) => {
367
379
  // 只保留最近的maxRecordLen条日志
368
380
  const reserveLen = this.option.maxRecordLen - 1;
369
381
  const originList = list.length > reserveLen ? list.slice(list.length - reserveLen, list.length) : list;
370
- let content = originList.concat(this.tmpList).join('\n');
371
- let data = this.zip(content);
372
- let codesStr = '';
373
- if (data.codes) {
374
- codesStr = JSON.stringify(data.codes);
375
- this.storage.set(this.option.key + 'Codes', codesStr);
376
- }
377
- else {
378
- this.storage.rm(this.option.key + 'Codes');
382
+ let newList = originList.concat(this.tmpList);
383
+ let content = newList.join('\n');
384
+ let error: Error | null = null;
385
+ let len = 0;
386
+ try {
387
+ let data = this.zip(content);
388
+ let codesStr = '';
389
+ if (data.codes) {
390
+ codesStr = JSON.stringify(data.codes);
391
+ this.storage.set(this.option.key + 'Codes', codesStr);
392
+ }
393
+ else {
394
+ this.storage.rm(this.option.key + 'Codes');
395
+ }
396
+
397
+ this.storage.set(this.option.key, data.result);
398
+ len = data.result.length;
379
399
  }
380
- const startTime = performance.now();
381
- this.storage.set(this.option.key, data.result);
382
- const costTime = ((performance.now() - startTime) * 100).toFixed(0);
383
- if (this.option.costTime) {
384
- this.option.costTime(costTime);
400
+ catch (e) {
401
+ error = e;
402
+ console.error(e);
385
403
  }
386
404
 
387
405
  this.tmpList = [];
406
+
407
+ this.option.onSave && this.option.onSave({
408
+ cost: Date.now() - st,
409
+ length: len / 1024,
410
+ list: newList,
411
+ error: error,
412
+ });
388
413
  });
389
414
  }
390
415