@be-link/cls-logger 1.0.1-beta.21 → 1.0.1-beta.23
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/README.md +161 -11
- package/dist/ClsLoggerCore.d.ts +5 -2
- package/dist/ClsLoggerCore.d.ts.map +1 -1
- package/dist/index.esm.js +45 -21
- package/dist/index.js +45 -21
- package/dist/index.umd.js +45 -21
- package/dist/mini.esm.js +45 -21
- package/dist/mini.js +45 -21
- package/dist/types.d.ts +10 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/web.esm.js +45 -21
- package/dist/web.js +45 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,7 @@ clsLogger.init({
|
|
|
144
144
|
maxSize: 50, // 队列达到此数量立即发送,默认 20
|
|
145
145
|
intervalMs: 1000, // 定时批量发送间隔,默认 500ms
|
|
146
146
|
startupDelayMs: 3000, // 启动合并窗口,默认 0(不启用)
|
|
147
|
+
startupMaxSize: 500, // 启动窗口内的队列阈值,默认 maxSize*10(至少200)
|
|
147
148
|
useIdleCallback: true, // 使用浏览器空闲时间上报,默认 false
|
|
148
149
|
idleTimeout: 3000, // 空闲回调超时时间,默认 3000ms
|
|
149
150
|
},
|
|
@@ -224,13 +225,19 @@ clsLogger.init({
|
|
|
224
225
|
clsLogger.init({
|
|
225
226
|
batch: {
|
|
226
227
|
startupDelayMs: 3000, // 启动 3 秒内的日志合并发送
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
startupMaxSize: 500, // 启动窗口内允许更多日志积累(防止 maxSize 打断合并)
|
|
229
|
+
maxSize: 100, // 正常运行时的队列阈值
|
|
230
|
+
intervalMs: 2000, // 延长批量间隔
|
|
231
|
+
useIdleCallback: true, // 等待延迟后在浏览器空闲时上报
|
|
232
|
+
},
|
|
233
|
+
performanceMonitor: {
|
|
234
|
+
resourceTiming: false, // 关闭资源监控(首屏资源多时可大幅减少日志量)
|
|
230
235
|
},
|
|
231
236
|
});
|
|
232
237
|
```
|
|
233
238
|
|
|
239
|
+
> **说明**:`startupMaxSize` 确保启动窗口内不会因为 `maxSize` 被频繁触发而打断日志合并。
|
|
240
|
+
|
|
234
241
|
### 场景 2:减少资源监控日志
|
|
235
242
|
|
|
236
243
|
开发环境资源过多,或生产环境不需要全量资源监控:
|
|
@@ -274,31 +281,174 @@ clsLogger.init({
|
|
|
274
281
|
```ts
|
|
275
282
|
clsLogger.init({
|
|
276
283
|
batch: {
|
|
277
|
-
|
|
284
|
+
startupDelayMs: 3000, // 启动合并窗口
|
|
285
|
+
startupMaxSize: 500, // 启动窗口内的队列阈值
|
|
286
|
+
maxSize: 100, // 正常运行时的队列阈值
|
|
278
287
|
intervalMs: 2000, // 延长批量间隔
|
|
279
|
-
useIdleCallback: true, //
|
|
288
|
+
useIdleCallback: true, // 空闲时上报,不阻塞主线程
|
|
280
289
|
},
|
|
281
290
|
performanceMonitor: {
|
|
282
291
|
resourceTiming: false, // 关闭资源监控
|
|
283
292
|
},
|
|
284
293
|
requestMonitor: {
|
|
285
294
|
sampleRate: 0.1, // 请求监控采样 10%
|
|
295
|
+
ignoreUrls: [
|
|
296
|
+
/heartbeat/i, // 忽略心跳请求
|
|
297
|
+
/polling/i, // 忽略轮询请求
|
|
298
|
+
/danmaku|barrage/i, // 忽略弹幕请求
|
|
299
|
+
],
|
|
286
300
|
},
|
|
287
301
|
});
|
|
288
302
|
```
|
|
289
303
|
|
|
304
|
+
## 最佳实践
|
|
305
|
+
|
|
306
|
+
### 1. 批量配置的正确姿势
|
|
307
|
+
|
|
308
|
+
#### `useIdleCallback` 工作原理
|
|
309
|
+
|
|
310
|
+
当 `useIdleCallback: true` 时,SDK 的上报流程为:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
日志产生 → 等待 intervalMs/startupDelayMs → 等待浏览器空闲 → 发送
|
|
314
|
+
↑ 最小等待时间 ↑ 在 idleTimeout 内空闲就发送
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**关键点**:
|
|
318
|
+
|
|
319
|
+
- `intervalMs`/`startupDelayMs` 是**最小等待时间**,保证不会过早发送
|
|
320
|
+
- `idleTimeout` 是空闲等待的**最大时间**,防止浏览器一直繁忙导致日志积压
|
|
321
|
+
|
|
322
|
+
#### `startupMaxSize` 的作用
|
|
323
|
+
|
|
324
|
+
启动阶段(`startupDelayMs` 窗口内)日志量通常很大(性能指标、资源加载等),如果 `maxSize` 设置过小,会频繁触发队列满而打断合并:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
// ❌ 错误配置:startupDelayMs 会被 maxSize 打断
|
|
328
|
+
batch: {
|
|
329
|
+
startupDelayMs: 3000,
|
|
330
|
+
maxSize: 20, // 启动期间可能产生 200+ 条日志,会触发 10+ 次发送
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ✅ 正确配置:使用 startupMaxSize 保护启动窗口
|
|
334
|
+
batch: {
|
|
335
|
+
startupDelayMs: 3000,
|
|
336
|
+
maxSize: 20,
|
|
337
|
+
startupMaxSize: 500, // 启动期间允许更多日志积累
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 2. 推荐配置模板
|
|
342
|
+
|
|
343
|
+
#### 普通 H5 页面
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
clsLogger.init({
|
|
347
|
+
batch: {
|
|
348
|
+
startupDelayMs: 2000,
|
|
349
|
+
startupMaxSize: 300,
|
|
350
|
+
maxSize: 50,
|
|
351
|
+
intervalMs: 1000,
|
|
352
|
+
useIdleCallback: true,
|
|
353
|
+
idleTimeout: 3000,
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### 首屏性能敏感(电商、活动页)
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
clsLogger.init({
|
|
362
|
+
batch: {
|
|
363
|
+
startupDelayMs: 5000, // 更长的启动窗口
|
|
364
|
+
startupMaxSize: 500,
|
|
365
|
+
maxSize: 100,
|
|
366
|
+
intervalMs: 2000,
|
|
367
|
+
useIdleCallback: true,
|
|
368
|
+
idleTimeout: 5000,
|
|
369
|
+
},
|
|
370
|
+
performanceMonitor: {
|
|
371
|
+
sampleRate: 0.3, // 性能监控采样
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### 高频交互页面(直播间、游戏)
|
|
377
|
+
|
|
378
|
+
```ts
|
|
379
|
+
clsLogger.init({
|
|
380
|
+
batch: {
|
|
381
|
+
startupDelayMs: 3000,
|
|
382
|
+
startupMaxSize: 500,
|
|
383
|
+
maxSize: 100,
|
|
384
|
+
intervalMs: 3000, // 更长的间隔
|
|
385
|
+
useIdleCallback: true,
|
|
386
|
+
idleTimeout: 5000,
|
|
387
|
+
},
|
|
388
|
+
performanceMonitor: {
|
|
389
|
+
resourceTiming: false, // 关闭资源监控
|
|
390
|
+
},
|
|
391
|
+
requestMonitor: {
|
|
392
|
+
sampleRate: 0.1, // 请求监控采样
|
|
393
|
+
ignoreUrls: [/heartbeat/, /polling/, /danmaku/],
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 3. 日志量优化技巧
|
|
399
|
+
|
|
400
|
+
| 优化项 | 配置 | 效果 |
|
|
401
|
+
| ------------ | ------------------------------------------ | ------------------------- |
|
|
402
|
+
| 关闭资源监控 | `performanceMonitor.resourceTiming: false` | 减少 80%+ 的 perf 日志 |
|
|
403
|
+
| 性能采样 | `performanceMonitor.sampleRate: 0.1` | 只采集 10% 用户的性能数据 |
|
|
404
|
+
| 请求采样 | `requestMonitor.sampleRate: 0.1` | 只采集 10% 的请求日志 |
|
|
405
|
+
| 忽略高频请求 | `requestMonitor.ignoreUrls: [/heartbeat/]` | 过滤心跳等高频请求 |
|
|
406
|
+
| 错误去重 | `errorMonitor.dedupeWindowMs: 5000` | 5秒内相同错误只上报一次 |
|
|
407
|
+
|
|
408
|
+
### 4. 常见问题排查
|
|
409
|
+
|
|
410
|
+
#### 问题:首屏请求过多
|
|
411
|
+
|
|
412
|
+
**现象**:页面加载时发出 10+ 个日志请求
|
|
413
|
+
|
|
414
|
+
**排查步骤**:
|
|
415
|
+
|
|
416
|
+
1. 检查 `startupDelayMs` 是否配置
|
|
417
|
+
2. 检查 `startupMaxSize` 是否足够大(建议 300-500)
|
|
418
|
+
3. 检查 `resourceTiming` 是否需要开启(这是日志量最大的来源)
|
|
419
|
+
|
|
420
|
+
#### 问题:日志延迟过高
|
|
421
|
+
|
|
422
|
+
**现象**:日志上报明显滞后
|
|
423
|
+
|
|
424
|
+
**排查步骤**:
|
|
425
|
+
|
|
426
|
+
1. 检查 `useIdleCallback` + `idleTimeout` 配置
|
|
427
|
+
2. 检查 `intervalMs` 是否设置过大
|
|
428
|
+
3. 考虑关闭 `useIdleCallback` 或减小 `idleTimeout`
|
|
429
|
+
|
|
430
|
+
#### 问题:页面关闭丢日志
|
|
431
|
+
|
|
432
|
+
**现象**:用户快速关闭页面时日志丢失
|
|
433
|
+
|
|
434
|
+
**说明**:SDK 已通过 `sendBeacon` 处理此场景,如仍有丢失:
|
|
435
|
+
|
|
436
|
+
1. 检查日志是否在 `memoryQueue` 中(可能还未触发 flush)
|
|
437
|
+
2. 考虑对关键日志使用 `{ immediate: true }`
|
|
438
|
+
|
|
290
439
|
## 功能说明
|
|
291
440
|
|
|
292
441
|
### 1. 批量上报机制
|
|
293
442
|
|
|
294
443
|
SDK 使用内存队列批量上报日志:
|
|
295
444
|
|
|
296
|
-
| 触发条件 | 说明
|
|
297
|
-
| -------- |
|
|
298
|
-
| 队列满 | 达到 `maxSize`
|
|
299
|
-
| 定时器 | 每 `intervalMs` 毫秒发送一次
|
|
300
|
-
| 页面关闭 | `visibilitychange` + `pagehide` 触发 `sendBeacon` 发送
|
|
301
|
-
| 启动合并 | `startupDelayMs` 窗口内的日志尽量合并
|
|
445
|
+
| 触发条件 | 说明 |
|
|
446
|
+
| -------- | ------------------------------------------------------- |
|
|
447
|
+
| 队列满 | 达到 `maxSize`(启动窗口内为 `startupMaxSize`)立即发送 |
|
|
448
|
+
| 定时器 | 每 `intervalMs` 毫秒发送一次 |
|
|
449
|
+
| 页面关闭 | `visibilitychange` + `pagehide` 触发 `sendBeacon` 发送 |
|
|
450
|
+
| 启动合并 | `startupDelayMs` 窗口内的日志尽量合并 |
|
|
451
|
+
| 空闲上报 | `useIdleCallback` 开启时,等待浏览器空闲后发送 |
|
|
302
452
|
|
|
303
453
|
### 2. 即时上报 vs 批量上报
|
|
304
454
|
|
package/dist/ClsLoggerCore.d.ts
CHANGED
|
@@ -38,8 +38,10 @@ export declare abstract class ClsLoggerCore {
|
|
|
38
38
|
protected batchTimerDueAt: number | null;
|
|
39
39
|
protected initTs: number;
|
|
40
40
|
protected startupDelayMs: number;
|
|
41
|
+
protected startupMaxSize: number;
|
|
41
42
|
protected useIdleCallback: boolean;
|
|
42
43
|
protected idleTimeout: number;
|
|
44
|
+
protected pendingIdleCallback: number | null;
|
|
43
45
|
protected visibilityCleanup: (() => void) | null;
|
|
44
46
|
protected failedCacheKey: string;
|
|
45
47
|
protected failedCacheMax: number;
|
|
@@ -142,12 +144,13 @@ export declare abstract class ClsLoggerCore {
|
|
|
142
144
|
report(log: ReportLog): void;
|
|
143
145
|
/**
|
|
144
146
|
* 调度批量发送
|
|
145
|
-
* -
|
|
146
|
-
* -
|
|
147
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
148
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
147
149
|
*/
|
|
148
150
|
private scheduleFlush;
|
|
149
151
|
/**
|
|
150
152
|
* 取消已调度的批量发送
|
|
153
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
151
154
|
*/
|
|
152
155
|
private cancelScheduledFlush;
|
|
153
156
|
private getDesiredBatchFlushDueAt;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClsLoggerCore.d.ts","sourceRoot":"","sources":["../src/ClsLoggerCore.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ClsLoggerCore.d.ts","sourceRoot":"","sources":["../src/ClsLoggerCore.ts"],"names":[],"mappings":"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"}
|
package/dist/index.esm.js
CHANGED
|
@@ -178,8 +178,10 @@ class ClsLoggerCore {
|
|
|
178
178
|
this.batchTimerDueAt = null;
|
|
179
179
|
this.initTs = 0;
|
|
180
180
|
this.startupDelayMs = 0;
|
|
181
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
181
182
|
this.useIdleCallback = false;
|
|
182
183
|
this.idleTimeout = 3000;
|
|
184
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
183
185
|
this.visibilityCleanup = null;
|
|
184
186
|
// 参考文档:失败缓存 + 重试
|
|
185
187
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -252,6 +254,8 @@ class ClsLoggerCore {
|
|
|
252
254
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
253
255
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
254
256
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
257
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
258
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
255
259
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
256
260
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
257
261
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -627,11 +631,15 @@ class ClsLoggerCore {
|
|
|
627
631
|
return;
|
|
628
632
|
}
|
|
629
633
|
this.memoryQueue.push(log);
|
|
630
|
-
|
|
634
|
+
const now = Date.now();
|
|
635
|
+
// 判断是否在启动合并窗口内
|
|
636
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
637
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
638
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
639
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
631
640
|
void this.flushBatch();
|
|
632
641
|
return;
|
|
633
642
|
}
|
|
634
|
-
const now = Date.now();
|
|
635
643
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
636
644
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
637
645
|
if (!this.batchTimer) {
|
|
@@ -648,17 +656,19 @@ class ClsLoggerCore {
|
|
|
648
656
|
}
|
|
649
657
|
/**
|
|
650
658
|
* 调度批量发送
|
|
651
|
-
* -
|
|
652
|
-
* -
|
|
659
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
660
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
653
661
|
*/
|
|
654
662
|
scheduleFlush(desiredDelay) {
|
|
655
663
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
656
|
-
//
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
664
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
665
|
+
this.batchTimer = setTimeout(() => {
|
|
666
|
+
const idleId = requestIdleCallback(() => {
|
|
667
|
+
this.pendingIdleCallback = null;
|
|
668
|
+
void this.flushBatch();
|
|
669
|
+
}, { timeout: this.idleTimeout });
|
|
670
|
+
this.pendingIdleCallback = idleId;
|
|
671
|
+
}, desiredDelay);
|
|
662
672
|
}
|
|
663
673
|
else {
|
|
664
674
|
this.batchTimer = setTimeout(() => {
|
|
@@ -668,22 +678,29 @@ class ClsLoggerCore {
|
|
|
668
678
|
}
|
|
669
679
|
/**
|
|
670
680
|
* 取消已调度的批量发送
|
|
681
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
671
682
|
*/
|
|
672
683
|
cancelScheduledFlush() {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
677
|
-
cancelIdleCallback(this.batchTimer);
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
684
|
+
// 清理 setTimeout
|
|
685
|
+
if (this.batchTimer) {
|
|
686
|
+
try {
|
|
680
687
|
clearTimeout(this.batchTimer);
|
|
681
688
|
}
|
|
689
|
+
catch {
|
|
690
|
+
// ignore
|
|
691
|
+
}
|
|
692
|
+
this.batchTimer = null;
|
|
682
693
|
}
|
|
683
|
-
|
|
684
|
-
|
|
694
|
+
// 清理可能的 pendingIdleCallback
|
|
695
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
696
|
+
try {
|
|
697
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
698
|
+
}
|
|
699
|
+
catch {
|
|
700
|
+
// ignore
|
|
701
|
+
}
|
|
702
|
+
this.pendingIdleCallback = null;
|
|
685
703
|
}
|
|
686
|
-
this.batchTimer = null;
|
|
687
704
|
}
|
|
688
705
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
689
706
|
const start = this.initTs || nowTs;
|
|
@@ -896,7 +913,14 @@ class ClsLoggerCore {
|
|
|
896
913
|
// 先清空,再尝试发送
|
|
897
914
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
898
915
|
this.memoryQueue.unshift(...logs);
|
|
899
|
-
|
|
916
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
917
|
+
if (!this.batchTimer) {
|
|
918
|
+
const now = Date.now();
|
|
919
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
920
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
921
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
922
|
+
this.scheduleFlush(desiredDelay);
|
|
923
|
+
}
|
|
900
924
|
}
|
|
901
925
|
/**
|
|
902
926
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|
package/dist/index.js
CHANGED
|
@@ -182,8 +182,10 @@ class ClsLoggerCore {
|
|
|
182
182
|
this.batchTimerDueAt = null;
|
|
183
183
|
this.initTs = 0;
|
|
184
184
|
this.startupDelayMs = 0;
|
|
185
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
185
186
|
this.useIdleCallback = false;
|
|
186
187
|
this.idleTimeout = 3000;
|
|
188
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
187
189
|
this.visibilityCleanup = null;
|
|
188
190
|
// 参考文档:失败缓存 + 重试
|
|
189
191
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -256,6 +258,8 @@ class ClsLoggerCore {
|
|
|
256
258
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
257
259
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
258
260
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
261
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
262
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
259
263
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
260
264
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
261
265
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -631,11 +635,15 @@ class ClsLoggerCore {
|
|
|
631
635
|
return;
|
|
632
636
|
}
|
|
633
637
|
this.memoryQueue.push(log);
|
|
634
|
-
|
|
638
|
+
const now = Date.now();
|
|
639
|
+
// 判断是否在启动合并窗口内
|
|
640
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
641
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
642
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
643
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
635
644
|
void this.flushBatch();
|
|
636
645
|
return;
|
|
637
646
|
}
|
|
638
|
-
const now = Date.now();
|
|
639
647
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
640
648
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
641
649
|
if (!this.batchTimer) {
|
|
@@ -652,17 +660,19 @@ class ClsLoggerCore {
|
|
|
652
660
|
}
|
|
653
661
|
/**
|
|
654
662
|
* 调度批量发送
|
|
655
|
-
* -
|
|
656
|
-
* -
|
|
663
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
664
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
657
665
|
*/
|
|
658
666
|
scheduleFlush(desiredDelay) {
|
|
659
667
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
660
|
-
//
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
668
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
669
|
+
this.batchTimer = setTimeout(() => {
|
|
670
|
+
const idleId = requestIdleCallback(() => {
|
|
671
|
+
this.pendingIdleCallback = null;
|
|
672
|
+
void this.flushBatch();
|
|
673
|
+
}, { timeout: this.idleTimeout });
|
|
674
|
+
this.pendingIdleCallback = idleId;
|
|
675
|
+
}, desiredDelay);
|
|
666
676
|
}
|
|
667
677
|
else {
|
|
668
678
|
this.batchTimer = setTimeout(() => {
|
|
@@ -672,22 +682,29 @@ class ClsLoggerCore {
|
|
|
672
682
|
}
|
|
673
683
|
/**
|
|
674
684
|
* 取消已调度的批量发送
|
|
685
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
675
686
|
*/
|
|
676
687
|
cancelScheduledFlush() {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
681
|
-
cancelIdleCallback(this.batchTimer);
|
|
682
|
-
}
|
|
683
|
-
else {
|
|
688
|
+
// 清理 setTimeout
|
|
689
|
+
if (this.batchTimer) {
|
|
690
|
+
try {
|
|
684
691
|
clearTimeout(this.batchTimer);
|
|
685
692
|
}
|
|
693
|
+
catch {
|
|
694
|
+
// ignore
|
|
695
|
+
}
|
|
696
|
+
this.batchTimer = null;
|
|
686
697
|
}
|
|
687
|
-
|
|
688
|
-
|
|
698
|
+
// 清理可能的 pendingIdleCallback
|
|
699
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
700
|
+
try {
|
|
701
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
// ignore
|
|
705
|
+
}
|
|
706
|
+
this.pendingIdleCallback = null;
|
|
689
707
|
}
|
|
690
|
-
this.batchTimer = null;
|
|
691
708
|
}
|
|
692
709
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
693
710
|
const start = this.initTs || nowTs;
|
|
@@ -900,7 +917,14 @@ class ClsLoggerCore {
|
|
|
900
917
|
// 先清空,再尝试发送
|
|
901
918
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
902
919
|
this.memoryQueue.unshift(...logs);
|
|
903
|
-
|
|
920
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
921
|
+
if (!this.batchTimer) {
|
|
922
|
+
const now = Date.now();
|
|
923
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
924
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
925
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
926
|
+
this.scheduleFlush(desiredDelay);
|
|
927
|
+
}
|
|
904
928
|
}
|
|
905
929
|
/**
|
|
906
930
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|
package/dist/index.umd.js
CHANGED
|
@@ -182,8 +182,10 @@
|
|
|
182
182
|
this.batchTimerDueAt = null;
|
|
183
183
|
this.initTs = 0;
|
|
184
184
|
this.startupDelayMs = 0;
|
|
185
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
185
186
|
this.useIdleCallback = false;
|
|
186
187
|
this.idleTimeout = 3000;
|
|
188
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
187
189
|
this.visibilityCleanup = null;
|
|
188
190
|
// 参考文档:失败缓存 + 重试
|
|
189
191
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -256,6 +258,8 @@
|
|
|
256
258
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
257
259
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
258
260
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
261
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
262
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
259
263
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
260
264
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
261
265
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -631,11 +635,15 @@
|
|
|
631
635
|
return;
|
|
632
636
|
}
|
|
633
637
|
this.memoryQueue.push(log);
|
|
634
|
-
|
|
638
|
+
const now = Date.now();
|
|
639
|
+
// 判断是否在启动合并窗口内
|
|
640
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
641
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
642
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
643
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
635
644
|
void this.flushBatch();
|
|
636
645
|
return;
|
|
637
646
|
}
|
|
638
|
-
const now = Date.now();
|
|
639
647
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
640
648
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
641
649
|
if (!this.batchTimer) {
|
|
@@ -652,17 +660,19 @@
|
|
|
652
660
|
}
|
|
653
661
|
/**
|
|
654
662
|
* 调度批量发送
|
|
655
|
-
* -
|
|
656
|
-
* -
|
|
663
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
664
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
657
665
|
*/
|
|
658
666
|
scheduleFlush(desiredDelay) {
|
|
659
667
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
660
|
-
//
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
668
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
669
|
+
this.batchTimer = setTimeout(() => {
|
|
670
|
+
const idleId = requestIdleCallback(() => {
|
|
671
|
+
this.pendingIdleCallback = null;
|
|
672
|
+
void this.flushBatch();
|
|
673
|
+
}, { timeout: this.idleTimeout });
|
|
674
|
+
this.pendingIdleCallback = idleId;
|
|
675
|
+
}, desiredDelay);
|
|
666
676
|
}
|
|
667
677
|
else {
|
|
668
678
|
this.batchTimer = setTimeout(() => {
|
|
@@ -672,22 +682,29 @@
|
|
|
672
682
|
}
|
|
673
683
|
/**
|
|
674
684
|
* 取消已调度的批量发送
|
|
685
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
675
686
|
*/
|
|
676
687
|
cancelScheduledFlush() {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
681
|
-
cancelIdleCallback(this.batchTimer);
|
|
682
|
-
}
|
|
683
|
-
else {
|
|
688
|
+
// 清理 setTimeout
|
|
689
|
+
if (this.batchTimer) {
|
|
690
|
+
try {
|
|
684
691
|
clearTimeout(this.batchTimer);
|
|
685
692
|
}
|
|
693
|
+
catch {
|
|
694
|
+
// ignore
|
|
695
|
+
}
|
|
696
|
+
this.batchTimer = null;
|
|
686
697
|
}
|
|
687
|
-
|
|
688
|
-
|
|
698
|
+
// 清理可能的 pendingIdleCallback
|
|
699
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
700
|
+
try {
|
|
701
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
// ignore
|
|
705
|
+
}
|
|
706
|
+
this.pendingIdleCallback = null;
|
|
689
707
|
}
|
|
690
|
-
this.batchTimer = null;
|
|
691
708
|
}
|
|
692
709
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
693
710
|
const start = this.initTs || nowTs;
|
|
@@ -900,7 +917,14 @@
|
|
|
900
917
|
// 先清空,再尝试发送
|
|
901
918
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
902
919
|
this.memoryQueue.unshift(...logs);
|
|
903
|
-
|
|
920
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
921
|
+
if (!this.batchTimer) {
|
|
922
|
+
const now = Date.now();
|
|
923
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
924
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
925
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
926
|
+
this.scheduleFlush(desiredDelay);
|
|
927
|
+
}
|
|
904
928
|
}
|
|
905
929
|
/**
|
|
906
930
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|
package/dist/mini.esm.js
CHANGED
|
@@ -178,8 +178,10 @@ class ClsLoggerCore {
|
|
|
178
178
|
this.batchTimerDueAt = null;
|
|
179
179
|
this.initTs = 0;
|
|
180
180
|
this.startupDelayMs = 0;
|
|
181
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
181
182
|
this.useIdleCallback = false;
|
|
182
183
|
this.idleTimeout = 3000;
|
|
184
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
183
185
|
this.visibilityCleanup = null;
|
|
184
186
|
// 参考文档:失败缓存 + 重试
|
|
185
187
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -252,6 +254,8 @@ class ClsLoggerCore {
|
|
|
252
254
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
253
255
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
254
256
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
257
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
258
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
255
259
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
256
260
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
257
261
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -627,11 +631,15 @@ class ClsLoggerCore {
|
|
|
627
631
|
return;
|
|
628
632
|
}
|
|
629
633
|
this.memoryQueue.push(log);
|
|
630
|
-
|
|
634
|
+
const now = Date.now();
|
|
635
|
+
// 判断是否在启动合并窗口内
|
|
636
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
637
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
638
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
639
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
631
640
|
void this.flushBatch();
|
|
632
641
|
return;
|
|
633
642
|
}
|
|
634
|
-
const now = Date.now();
|
|
635
643
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
636
644
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
637
645
|
if (!this.batchTimer) {
|
|
@@ -648,17 +656,19 @@ class ClsLoggerCore {
|
|
|
648
656
|
}
|
|
649
657
|
/**
|
|
650
658
|
* 调度批量发送
|
|
651
|
-
* -
|
|
652
|
-
* -
|
|
659
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
660
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
653
661
|
*/
|
|
654
662
|
scheduleFlush(desiredDelay) {
|
|
655
663
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
656
|
-
//
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
664
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
665
|
+
this.batchTimer = setTimeout(() => {
|
|
666
|
+
const idleId = requestIdleCallback(() => {
|
|
667
|
+
this.pendingIdleCallback = null;
|
|
668
|
+
void this.flushBatch();
|
|
669
|
+
}, { timeout: this.idleTimeout });
|
|
670
|
+
this.pendingIdleCallback = idleId;
|
|
671
|
+
}, desiredDelay);
|
|
662
672
|
}
|
|
663
673
|
else {
|
|
664
674
|
this.batchTimer = setTimeout(() => {
|
|
@@ -668,22 +678,29 @@ class ClsLoggerCore {
|
|
|
668
678
|
}
|
|
669
679
|
/**
|
|
670
680
|
* 取消已调度的批量发送
|
|
681
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
671
682
|
*/
|
|
672
683
|
cancelScheduledFlush() {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
677
|
-
cancelIdleCallback(this.batchTimer);
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
684
|
+
// 清理 setTimeout
|
|
685
|
+
if (this.batchTimer) {
|
|
686
|
+
try {
|
|
680
687
|
clearTimeout(this.batchTimer);
|
|
681
688
|
}
|
|
689
|
+
catch {
|
|
690
|
+
// ignore
|
|
691
|
+
}
|
|
692
|
+
this.batchTimer = null;
|
|
682
693
|
}
|
|
683
|
-
|
|
684
|
-
|
|
694
|
+
// 清理可能的 pendingIdleCallback
|
|
695
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
696
|
+
try {
|
|
697
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
698
|
+
}
|
|
699
|
+
catch {
|
|
700
|
+
// ignore
|
|
701
|
+
}
|
|
702
|
+
this.pendingIdleCallback = null;
|
|
685
703
|
}
|
|
686
|
-
this.batchTimer = null;
|
|
687
704
|
}
|
|
688
705
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
689
706
|
const start = this.initTs || nowTs;
|
|
@@ -896,7 +913,14 @@ class ClsLoggerCore {
|
|
|
896
913
|
// 先清空,再尝试发送
|
|
897
914
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
898
915
|
this.memoryQueue.unshift(...logs);
|
|
899
|
-
|
|
916
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
917
|
+
if (!this.batchTimer) {
|
|
918
|
+
const now = Date.now();
|
|
919
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
920
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
921
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
922
|
+
this.scheduleFlush(desiredDelay);
|
|
923
|
+
}
|
|
900
924
|
}
|
|
901
925
|
/**
|
|
902
926
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|
package/dist/mini.js
CHANGED
|
@@ -201,8 +201,10 @@ class ClsLoggerCore {
|
|
|
201
201
|
this.batchTimerDueAt = null;
|
|
202
202
|
this.initTs = 0;
|
|
203
203
|
this.startupDelayMs = 0;
|
|
204
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
204
205
|
this.useIdleCallback = false;
|
|
205
206
|
this.idleTimeout = 3000;
|
|
207
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
206
208
|
this.visibilityCleanup = null;
|
|
207
209
|
// 参考文档:失败缓存 + 重试
|
|
208
210
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -275,6 +277,8 @@ class ClsLoggerCore {
|
|
|
275
277
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
276
278
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
277
279
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
280
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
281
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
278
282
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
279
283
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
280
284
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -650,11 +654,15 @@ class ClsLoggerCore {
|
|
|
650
654
|
return;
|
|
651
655
|
}
|
|
652
656
|
this.memoryQueue.push(log);
|
|
653
|
-
|
|
657
|
+
const now = Date.now();
|
|
658
|
+
// 判断是否在启动合并窗口内
|
|
659
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
660
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
661
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
662
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
654
663
|
void this.flushBatch();
|
|
655
664
|
return;
|
|
656
665
|
}
|
|
657
|
-
const now = Date.now();
|
|
658
666
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
659
667
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
660
668
|
if (!this.batchTimer) {
|
|
@@ -671,17 +679,19 @@ class ClsLoggerCore {
|
|
|
671
679
|
}
|
|
672
680
|
/**
|
|
673
681
|
* 调度批量发送
|
|
674
|
-
* -
|
|
675
|
-
* -
|
|
682
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
683
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
676
684
|
*/
|
|
677
685
|
scheduleFlush(desiredDelay) {
|
|
678
686
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
679
|
-
//
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
687
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
688
|
+
this.batchTimer = setTimeout(() => {
|
|
689
|
+
const idleId = requestIdleCallback(() => {
|
|
690
|
+
this.pendingIdleCallback = null;
|
|
691
|
+
void this.flushBatch();
|
|
692
|
+
}, { timeout: this.idleTimeout });
|
|
693
|
+
this.pendingIdleCallback = idleId;
|
|
694
|
+
}, desiredDelay);
|
|
685
695
|
}
|
|
686
696
|
else {
|
|
687
697
|
this.batchTimer = setTimeout(() => {
|
|
@@ -691,22 +701,29 @@ class ClsLoggerCore {
|
|
|
691
701
|
}
|
|
692
702
|
/**
|
|
693
703
|
* 取消已调度的批量发送
|
|
704
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
694
705
|
*/
|
|
695
706
|
cancelScheduledFlush() {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
700
|
-
cancelIdleCallback(this.batchTimer);
|
|
701
|
-
}
|
|
702
|
-
else {
|
|
707
|
+
// 清理 setTimeout
|
|
708
|
+
if (this.batchTimer) {
|
|
709
|
+
try {
|
|
703
710
|
clearTimeout(this.batchTimer);
|
|
704
711
|
}
|
|
712
|
+
catch {
|
|
713
|
+
// ignore
|
|
714
|
+
}
|
|
715
|
+
this.batchTimer = null;
|
|
705
716
|
}
|
|
706
|
-
|
|
707
|
-
|
|
717
|
+
// 清理可能的 pendingIdleCallback
|
|
718
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
719
|
+
try {
|
|
720
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
721
|
+
}
|
|
722
|
+
catch {
|
|
723
|
+
// ignore
|
|
724
|
+
}
|
|
725
|
+
this.pendingIdleCallback = null;
|
|
708
726
|
}
|
|
709
|
-
this.batchTimer = null;
|
|
710
727
|
}
|
|
711
728
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
712
729
|
const start = this.initTs || nowTs;
|
|
@@ -919,7 +936,14 @@ class ClsLoggerCore {
|
|
|
919
936
|
// 先清空,再尝试发送
|
|
920
937
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
921
938
|
this.memoryQueue.unshift(...logs);
|
|
922
|
-
|
|
939
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
940
|
+
if (!this.batchTimer) {
|
|
941
|
+
const now = Date.now();
|
|
942
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
943
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
944
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
945
|
+
this.scheduleFlush(desiredDelay);
|
|
946
|
+
}
|
|
923
947
|
}
|
|
924
948
|
/**
|
|
925
949
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|
package/dist/types.d.ts
CHANGED
|
@@ -29,13 +29,20 @@ export interface BatchOptions {
|
|
|
29
29
|
/**
|
|
30
30
|
* 启动阶段合并窗口(ms)
|
|
31
31
|
* - 目的:减少初始化/首屏阶段(perf/resource 等日志密集期)被 intervalMs 拆成多次上报
|
|
32
|
-
* - 行为:在该窗口内尽量延迟 flush
|
|
32
|
+
* - 行为:在该窗口内尽量延迟 flush 到窗口结束
|
|
33
33
|
* - 默认:0(不开启)
|
|
34
34
|
*/
|
|
35
35
|
startupDelayMs?: number;
|
|
36
|
+
/**
|
|
37
|
+
* 启动阶段的 maxSize(启动窗口内生效)
|
|
38
|
+
* - 目的:防止启动期间日志密集导致 maxSize 被频繁触发而打断 startupDelayMs
|
|
39
|
+
* - 行为:在 startupDelayMs 窗口内使用此值作为队列阈值
|
|
40
|
+
* - 默认:maxSize * 10(若未设置则为 200)
|
|
41
|
+
*/
|
|
42
|
+
startupMaxSize?: number;
|
|
36
43
|
/**
|
|
37
44
|
* 是否使用浏览器空闲时间上报
|
|
38
|
-
* -
|
|
45
|
+
* - 开启后会先等待 intervalMs/startupDelayMs,然后在浏览器空闲时执行发送
|
|
39
46
|
* - 配合 idleTimeout 使用,保证即使浏览器繁忙也能在超时后发送
|
|
40
47
|
* - 默认:false
|
|
41
48
|
*/
|
|
@@ -43,7 +50,7 @@ export interface BatchOptions {
|
|
|
43
50
|
/**
|
|
44
51
|
* 空闲回调超时时间(ms)
|
|
45
52
|
* - 当 useIdleCallback 为 true 时生效
|
|
46
|
-
* -
|
|
53
|
+
* - 在等待空闲期间,即使浏览器繁忙,也会在此时间后强制执行
|
|
47
54
|
* - 默认:3000
|
|
48
55
|
*/
|
|
49
56
|
idleTimeout?: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/web.esm.js
CHANGED
|
@@ -179,8 +179,10 @@ class ClsLoggerCore {
|
|
|
179
179
|
this.batchTimerDueAt = null;
|
|
180
180
|
this.initTs = 0;
|
|
181
181
|
this.startupDelayMs = 0;
|
|
182
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
182
183
|
this.useIdleCallback = false;
|
|
183
184
|
this.idleTimeout = 3000;
|
|
185
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
184
186
|
this.visibilityCleanup = null;
|
|
185
187
|
// 参考文档:失败缓存 + 重试
|
|
186
188
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -253,6 +255,8 @@ class ClsLoggerCore {
|
|
|
253
255
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
254
256
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
255
257
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
258
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
259
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
256
260
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
257
261
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
258
262
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -628,11 +632,15 @@ class ClsLoggerCore {
|
|
|
628
632
|
return;
|
|
629
633
|
}
|
|
630
634
|
this.memoryQueue.push(log);
|
|
631
|
-
|
|
635
|
+
const now = Date.now();
|
|
636
|
+
// 判断是否在启动合并窗口内
|
|
637
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
638
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
639
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
640
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
632
641
|
void this.flushBatch();
|
|
633
642
|
return;
|
|
634
643
|
}
|
|
635
|
-
const now = Date.now();
|
|
636
644
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
637
645
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
638
646
|
if (!this.batchTimer) {
|
|
@@ -649,17 +657,19 @@ class ClsLoggerCore {
|
|
|
649
657
|
}
|
|
650
658
|
/**
|
|
651
659
|
* 调度批量发送
|
|
652
|
-
* -
|
|
653
|
-
* -
|
|
660
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
661
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
654
662
|
*/
|
|
655
663
|
scheduleFlush(desiredDelay) {
|
|
656
664
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
657
|
-
//
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
665
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
666
|
+
this.batchTimer = setTimeout(() => {
|
|
667
|
+
const idleId = requestIdleCallback(() => {
|
|
668
|
+
this.pendingIdleCallback = null;
|
|
669
|
+
void this.flushBatch();
|
|
670
|
+
}, { timeout: this.idleTimeout });
|
|
671
|
+
this.pendingIdleCallback = idleId;
|
|
672
|
+
}, desiredDelay);
|
|
663
673
|
}
|
|
664
674
|
else {
|
|
665
675
|
this.batchTimer = setTimeout(() => {
|
|
@@ -669,22 +679,29 @@ class ClsLoggerCore {
|
|
|
669
679
|
}
|
|
670
680
|
/**
|
|
671
681
|
* 取消已调度的批量发送
|
|
682
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
672
683
|
*/
|
|
673
684
|
cancelScheduledFlush() {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
678
|
-
cancelIdleCallback(this.batchTimer);
|
|
679
|
-
}
|
|
680
|
-
else {
|
|
685
|
+
// 清理 setTimeout
|
|
686
|
+
if (this.batchTimer) {
|
|
687
|
+
try {
|
|
681
688
|
clearTimeout(this.batchTimer);
|
|
682
689
|
}
|
|
690
|
+
catch {
|
|
691
|
+
// ignore
|
|
692
|
+
}
|
|
693
|
+
this.batchTimer = null;
|
|
683
694
|
}
|
|
684
|
-
|
|
685
|
-
|
|
695
|
+
// 清理可能的 pendingIdleCallback
|
|
696
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
697
|
+
try {
|
|
698
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
699
|
+
}
|
|
700
|
+
catch {
|
|
701
|
+
// ignore
|
|
702
|
+
}
|
|
703
|
+
this.pendingIdleCallback = null;
|
|
686
704
|
}
|
|
687
|
-
this.batchTimer = null;
|
|
688
705
|
}
|
|
689
706
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
690
707
|
const start = this.initTs || nowTs;
|
|
@@ -897,7 +914,14 @@ class ClsLoggerCore {
|
|
|
897
914
|
// 先清空,再尝试发送
|
|
898
915
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
899
916
|
this.memoryQueue.unshift(...logs);
|
|
900
|
-
|
|
917
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
918
|
+
if (!this.batchTimer) {
|
|
919
|
+
const now = Date.now();
|
|
920
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
921
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
922
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
923
|
+
this.scheduleFlush(desiredDelay);
|
|
924
|
+
}
|
|
901
925
|
}
|
|
902
926
|
/**
|
|
903
927
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|
package/dist/web.js
CHANGED
|
@@ -202,8 +202,10 @@ class ClsLoggerCore {
|
|
|
202
202
|
this.batchTimerDueAt = null;
|
|
203
203
|
this.initTs = 0;
|
|
204
204
|
this.startupDelayMs = 0;
|
|
205
|
+
this.startupMaxSize = 0; // 启动窗口内的 maxSize,0 表示使用默认计算值
|
|
205
206
|
this.useIdleCallback = false;
|
|
206
207
|
this.idleTimeout = 3000;
|
|
208
|
+
this.pendingIdleCallback = null; // requestIdleCallback 的 id
|
|
207
209
|
this.visibilityCleanup = null;
|
|
208
210
|
// 参考文档:失败缓存 + 重试
|
|
209
211
|
this.failedCacheKey = 'cls_failed_logs';
|
|
@@ -276,6 +278,8 @@ class ClsLoggerCore {
|
|
|
276
278
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
277
279
|
this.useIdleCallback = options.batch?.useIdleCallback ?? this.useIdleCallback;
|
|
278
280
|
this.idleTimeout = options.batch?.idleTimeout ?? this.idleTimeout;
|
|
281
|
+
// startupMaxSize:启动窗口内的队列阈值,默认为 maxSize * 10(至少 200)
|
|
282
|
+
this.startupMaxSize = options.batch?.startupMaxSize ?? Math.max(this.batchMaxSize * 10, 200);
|
|
279
283
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
280
284
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
281
285
|
// 预热(避免首条日志触发 import/初始化开销)
|
|
@@ -651,11 +655,15 @@ class ClsLoggerCore {
|
|
|
651
655
|
return;
|
|
652
656
|
}
|
|
653
657
|
this.memoryQueue.push(log);
|
|
654
|
-
|
|
658
|
+
const now = Date.now();
|
|
659
|
+
// 判断是否在启动合并窗口内
|
|
660
|
+
const inStartupWindow = this.startupDelayMs > 0 && now - this.initTs < this.startupDelayMs;
|
|
661
|
+
// 启动窗口内使用 startupMaxSize,正常情况使用 batchMaxSize
|
|
662
|
+
const effectiveMaxSize = inStartupWindow ? this.startupMaxSize : this.batchMaxSize;
|
|
663
|
+
if (this.memoryQueue.length >= effectiveMaxSize) {
|
|
655
664
|
void this.flushBatch();
|
|
656
665
|
return;
|
|
657
666
|
}
|
|
658
|
-
const now = Date.now();
|
|
659
667
|
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
660
668
|
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
661
669
|
if (!this.batchTimer) {
|
|
@@ -672,17 +680,19 @@ class ClsLoggerCore {
|
|
|
672
680
|
}
|
|
673
681
|
/**
|
|
674
682
|
* 调度批量发送
|
|
675
|
-
* -
|
|
676
|
-
* -
|
|
683
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
684
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
677
685
|
*/
|
|
678
686
|
scheduleFlush(desiredDelay) {
|
|
679
687
|
if (this.useIdleCallback && typeof requestIdleCallback !== 'undefined') {
|
|
680
|
-
//
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
688
|
+
// 先 setTimeout 保证最小延迟,再 requestIdleCallback 在空闲时执行
|
|
689
|
+
this.batchTimer = setTimeout(() => {
|
|
690
|
+
const idleId = requestIdleCallback(() => {
|
|
691
|
+
this.pendingIdleCallback = null;
|
|
692
|
+
void this.flushBatch();
|
|
693
|
+
}, { timeout: this.idleTimeout });
|
|
694
|
+
this.pendingIdleCallback = idleId;
|
|
695
|
+
}, desiredDelay);
|
|
686
696
|
}
|
|
687
697
|
else {
|
|
688
698
|
this.batchTimer = setTimeout(() => {
|
|
@@ -692,22 +702,29 @@ class ClsLoggerCore {
|
|
|
692
702
|
}
|
|
693
703
|
/**
|
|
694
704
|
* 取消已调度的批量发送
|
|
705
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
695
706
|
*/
|
|
696
707
|
cancelScheduledFlush() {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
if (this.useIdleCallback && typeof cancelIdleCallback !== 'undefined') {
|
|
701
|
-
cancelIdleCallback(this.batchTimer);
|
|
702
|
-
}
|
|
703
|
-
else {
|
|
708
|
+
// 清理 setTimeout
|
|
709
|
+
if (this.batchTimer) {
|
|
710
|
+
try {
|
|
704
711
|
clearTimeout(this.batchTimer);
|
|
705
712
|
}
|
|
713
|
+
catch {
|
|
714
|
+
// ignore
|
|
715
|
+
}
|
|
716
|
+
this.batchTimer = null;
|
|
706
717
|
}
|
|
707
|
-
|
|
708
|
-
|
|
718
|
+
// 清理可能的 pendingIdleCallback
|
|
719
|
+
if (this.pendingIdleCallback !== null && typeof cancelIdleCallback !== 'undefined') {
|
|
720
|
+
try {
|
|
721
|
+
cancelIdleCallback(this.pendingIdleCallback);
|
|
722
|
+
}
|
|
723
|
+
catch {
|
|
724
|
+
// ignore
|
|
725
|
+
}
|
|
726
|
+
this.pendingIdleCallback = null;
|
|
709
727
|
}
|
|
710
|
-
this.batchTimer = null;
|
|
711
728
|
}
|
|
712
729
|
getDesiredBatchFlushDueAt(nowTs) {
|
|
713
730
|
const start = this.initTs || nowTs;
|
|
@@ -920,7 +937,14 @@ class ClsLoggerCore {
|
|
|
920
937
|
// 先清空,再尝试发送
|
|
921
938
|
writeStringStorage(this.failedCacheKey, JSON.stringify([]));
|
|
922
939
|
this.memoryQueue.unshift(...logs);
|
|
923
|
-
|
|
940
|
+
// 触发定时器而非直接 flush,以尊重 startupDelayMs 配置
|
|
941
|
+
if (!this.batchTimer) {
|
|
942
|
+
const now = Date.now();
|
|
943
|
+
const desiredDueAt = this.getDesiredBatchFlushDueAt(now);
|
|
944
|
+
const desiredDelay = Math.max(0, desiredDueAt - now);
|
|
945
|
+
this.batchTimerDueAt = desiredDueAt;
|
|
946
|
+
this.scheduleFlush(desiredDelay);
|
|
947
|
+
}
|
|
924
948
|
}
|
|
925
949
|
/**
|
|
926
950
|
* 统计/计数类日志:按字段展开上报(若 data 为空默认 1)
|