@antglobal/rlog-sdk 0.0.1755855517-dev.17 → 0.0.1755855517-dev.18

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 (43) hide show
  1. package/README.md +203 -483
  2. package/dist/esm/index.d.ts +1 -2
  3. package/dist/esm/index.d.ts.map +1 -1
  4. package/dist/esm/index.js +36 -18
  5. package/dist/esm/lib/config.js +1 -1
  6. package/dist/esm/lib/error-trigger.d.ts.map +1 -1
  7. package/dist/esm/lib/error-trigger.js +5 -4
  8. package/dist/esm/lib/error.d.ts.map +1 -1
  9. package/dist/esm/lib/error.js +61 -50
  10. package/dist/esm/lib/init.d.ts.map +1 -1
  11. package/dist/esm/lib/init.js +43 -15
  12. package/dist/esm/lib/net.d.ts.map +1 -1
  13. package/dist/esm/lib/net.js +195 -160
  14. package/dist/esm/lib/router-monitor.d.ts.map +1 -1
  15. package/dist/esm/lib/router-monitor.js +18 -11
  16. package/dist/esm/lib/rrweb.d.ts.map +1 -1
  17. package/dist/esm/lib/rrweb.js +12 -8
  18. package/dist/esm/lib/upload-worker-manager.d.ts.map +1 -1
  19. package/dist/esm/lib/upload-worker-manager.js +59 -42
  20. package/dist/esm/lib/uploader.d.ts.map +1 -1
  21. package/dist/esm/lib/uploader.js +54 -50
  22. package/dist/lib/index.d.ts +1 -2
  23. package/dist/lib/index.d.ts.map +1 -1
  24. package/dist/lib/index.js +41 -17
  25. package/dist/lib/lib/config.js +1 -1
  26. package/dist/lib/lib/error-trigger.d.ts.map +1 -1
  27. package/dist/lib/lib/error-trigger.js +5 -4
  28. package/dist/lib/lib/error.d.ts.map +1 -1
  29. package/dist/lib/lib/error.js +61 -50
  30. package/dist/lib/lib/init.d.ts.map +1 -1
  31. package/dist/lib/lib/init.js +43 -15
  32. package/dist/lib/lib/net.d.ts.map +1 -1
  33. package/dist/lib/lib/net.js +195 -160
  34. package/dist/lib/lib/router-monitor.d.ts.map +1 -1
  35. package/dist/lib/lib/router-monitor.js +18 -11
  36. package/dist/lib/lib/rrweb.d.ts.map +1 -1
  37. package/dist/lib/lib/rrweb.js +12 -8
  38. package/dist/lib/lib/upload-worker-manager.d.ts.map +1 -1
  39. package/dist/lib/lib/upload-worker-manager.js +59 -42
  40. package/dist/lib/lib/uploader.d.ts.map +1 -1
  41. package/dist/lib/lib/uploader.js +54 -50
  42. package/dist/rlog-sdk.min.js +1 -1
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -1,525 +1,245 @@
1
- # rlog-sdk 性能与安全设计文档
1
+ # @antglobal/rlog-sdk
2
2
 
3
- ## 动态配置功能
3
+ 基于 [rrweb](https://github.com/rrweb-io/rrweb) 的用户行为录制与上报 SDK,用于 Web 应用的会话回放、错误追踪和行为分析。
4
4
 
5
- ### 1. CDN 配置支持
6
- SDK 现在支持从 CDN 获取动态配置,可以实时调整以下参数:
7
- - 采集总开关
8
- - Canvas 录制采样率
9
- - 数据上传时间间隔
5
+ ## 特性
10
6
 
11
- ### 2. 配置参数说明
12
- CDN 配置文件应为 JSON 格式,包含以下字段:
7
+ - **全量录制** — 持续录制用户操作,定时上传
8
+ - **错误模式录制** 仅在发生错误时上传前后时间窗口内的录制数据
9
+ - **多 Tab 隔离** — 每个标签页独立 Session,分布式锁保证数据安全
10
+ - **存储自动降级** — IndexedDB > LocalStorage > Memory
11
+ - **网络监控** — 拦截 XHR/Fetch,记录请求响应,支持黑白名单过滤
12
+ - **路由监控** — 监听 History API 和 Hash 变化,记录页面停留时间
13
+ - **Console 录制** — 可选的 console 输出捕获(rrweb 插件)
14
+ - **上传重试** — 失败自动重试,超过阈值停止录制并派发事件
15
+ - **Web Worker 上传** — 后台线程上传,不阻塞主线程
16
+ - **只采集不上报** — 可动态切换的 consume-only 模式
17
+ - **自定义事件** — 支持注入业务自定义事件到录制流
18
+ - **错误上报** — 全局 JS 错误和资源加载错误自动捕获
13
19
 
14
- #### 基础配置
15
- ```json
16
- {
17
- "enable": true, // 采集总开关
18
- "uploadInterval": 2000, // 数据上传时间间隔 (毫秒)
19
- "configUpdateInterval": 300000, // 配置更新时间间隔 (毫秒),默认 5 分钟
20
- "checkoutEveryNms": 5000, // 每N毫秒做一次全量快照,默认 5 秒
21
- "captureMode": "full", // 采集模式: 'full' 全量采集(默认) | 'error' 错误采集
22
- "packEvents": false, // 是否使用rrweb的packFn压缩事件数据,默认false
23
- "clearStorageBeforeRecord": true, // 是否在开始录制前清空存储数据,默认true
24
- "http": false, // 是否开启接口请求抓取,默认false
25
- "maxRetryCount": 3, // 上传失败最大重试次数,默认3次
26
- "consumeOnly": false, // 只采集不上报模式,默认false
27
- "urlParamsToCache": [], // 需要从URL中缓存和上报的参数名称列表
28
-
29
- // 事件采样配置
30
- "sampling": {
31
- "canvas": 15, // Canvas 采样率 (帧/秒),默认 15
32
- "mousemove": 50, // 鼠标移动事件采样间隔 (毫秒),false表示不录制
33
- "scroll": 100, // 滚动事件防抖间隔 (毫秒)
34
- "input": "last" // 输入事件录制时机: 'all' 全部 | 'last' 只记录最终值
35
- },
36
-
37
- // rrweb 相关 CSS 类名配置
38
- "ignoreClass": "rr-ignore", // 忽略采集的CSS类名
39
- "blockClass": "rr-block", // 阻塞采集的CSS类名
40
- "maskTextClass": "rr-mask", // 文本遮罩的CSS类名
41
-
42
- // 错误采集模式配置 (仅在 captureMode='error' 时生效)
43
- "errorCapture": {
44
- "beforeDuration": 30000, // 错误发生前录制时长 (毫秒),默认 30000
45
- "afterDuration": 30000, // 错误发生后继续录制时长 (毫秒),默认 30000
46
- "httpErrorThreshold": 400 // HTTP 错误状态码阈值,>= 该值视为错误,默认 400
47
- }
48
- }
49
- ```
20
+ ## 安装
50
21
 
51
- #### Console录制插件配置
52
- ```json
53
- {
54
- "console": {
55
- "enable": true, // 是否启用console录制,默认false
56
- "level": ["log", "warn", "error", "info"], // 需要录制的console方法,默认['log', 'warn', 'error', 'info']
57
- "lengthThreshold": 1000, // 最大录制条数,默认1000
58
- "stringifyOptions": {
59
- "stringLengthLimit": 500, // 单个值能转化的最大字符串长度,默认不限制
60
- "numOfKeysLimit": 50, // 被序列化的js对象能够包含的最大key数量,默认50
61
- "depthOfLimit": 4 // 对象能够拥有的最大深度(层数),默认4
62
- }
63
- }
64
- }
22
+ ```bash
23
+ npm install @antglobal/rlog-sdk
65
24
  ```
66
25
 
67
- #### 路由监控配置
68
- ```json
69
- {
70
- "routerMonitor": {
71
- "enable": false, // 是否启用路由监控,默认false
72
- "trackHashChange": true, // 是否监听hash变化,默认true
73
- "trackHistoryChange": true, // 是否监听History API变化,默认true
74
- "trackPageStayTime": true, // 是否计算页面停留时间,默认true
75
- "ignoreRoutes": [] // 需要忽略的路由列表
76
- }
77
- }
78
- ```
26
+ ## 快速开始
79
27
 
80
- **支持的console方法级别**:
81
- - `assert`, `clear`, `count`, `countReset`
82
- - `debug`, `dir`, `dirxml`, `error`
83
- - `group`, `groupCollapsed`, `groupEnd`, `info`
84
- - `log`, `table`, `time`, `timeEnd`, `timeLog`, `trace`, `warn`
28
+ ```typescript
29
+ import { init } from '@antglobal/rlog-sdk';
85
30
 
86
- ### 3. 使用方式
87
- ```javascript
88
- // 初始化时传入 CDN 配置 URL
89
- Rlog.init({
31
+ const rlog = init({
32
+ serv: 'https://your-server.com/api/rlog/record',
90
33
  appId: 'your-app-id',
91
- serv: 'your-upload-server',
92
- cdnConfigUrl: 'https://your-cdn.com/rlog-config.json'
34
+ cdnConfigUrl: 'https://your-cdn.com/rlog-config.json', // 可选,远程动态配置
93
35
  });
94
- ```
95
36
 
96
- ## 请求头注入功能
37
+ // 停止录制
38
+ rlog.cancel();
97
39
 
98
- ### 1. 功能说明
99
- SDK 支持在所有 XMLHttpRequest 和 fetch 请求中自动注入全局自定义请求头,方便添加认证信息、跟踪标识等。
40
+ // 停止录制并清除本地数据
41
+ rlog.cancel({ clearData: true });
42
+ ```
100
43
 
101
- ### 2. 使用方式
102
- ```javascript
103
- // 设置全局自定义请求头
104
- Rlog.setCustomHeaders({
105
- 'Authorization': 'Bearer your-token',
106
- 'X-Request-Id': 'unique-request-id',
107
- 'X-Client-Version': '1.0.0'
108
- });
44
+ ## API
109
45
 
110
- // 设置白名单URL(只有这些URL的请求会被监控和注入请求头)
111
- Rlog.setWhiteListUrls([
112
- 'https://api.your-app.com',
113
- 'https://analytics.your-app.com'
114
- ]);
115
- ```
46
+ ### 核心
116
47
 
117
- ### 3. 实现原理
118
- - 拦截 XMLHttpRequest 和 fetch API
119
- - 在发送请求前自动添加自定义请求头
120
- - 只对白名单中的 URL 注入请求头
121
- - 监控请求结果并记录成功/失败事件
122
-
123
- ## 代码结构优化
124
-
125
- ### 1. 入口文件精简
126
- 入口文件 [`src/index.ts`](src/index.ts) 已经优化得更加精简,只包含必要的导入和导出:
127
- - 导入核心初始化函数
128
- - 导出初始化接口
129
- - 导出自定义事件接口
130
-
131
- ### 2. 模块化设计
132
- 项目现在采用更好的模块化设计,按功能域清晰划分:
133
-
134
- #### 核心模块
135
- - [`src/lib/init.ts`](src/lib/init.ts): 初始化逻辑,负责SDK的启动和配置
136
- - [`src/lib/config.ts`](src/lib/config.ts): 配置管理,支持CDN动态配置
137
- - [`src/lib/rrweb.ts`](src/lib/rrweb.ts): 录制功能,集成rrweb录制器
138
-
139
- #### 数据管理模块
140
- - [`src/lib/storage-manager.ts`](src/lib/storage-manager.ts): 存储管理,统一处理数据存储
141
- - [`src/lib/drive/`](src/lib/drive/): 存储驱动层
142
- - [`indexeddb-adapt.ts`](src/lib/drive/indexeddb-adapt.ts): IndexedDB存储适配器
143
- - [`localstorage-adapt.ts`](src/lib/drive/localstorage-adapt.ts): LocalStorage存储适配器
144
- - [`memory-adapt.ts`](src/lib/drive/memory-adapt.ts): 内存存储适配器
145
- - [`storage-interface.ts`](src/lib/drive/storage-interface.ts): 存储接口定义
146
-
147
- #### 网络通信模块
148
- - [`src/lib/uploader.ts`](src/lib/uploader.ts): 数据上传逻辑,包含重试机制
149
- - [`src/lib/request.ts`](src/lib/request.ts): 网络请求工具,封装HTTP请求
150
- - [`src/lib/net.ts`](src/lib/net.ts): 网络监控,拦截和记录网络请求
151
-
152
- #### 功能扩展模块
153
- - [`src/lib/router-monitor.ts`](src/lib/router-monitor.ts): 路由监控,跟踪页面路由变化
154
- - [`src/lib/api.ts`](src/lib/api.ts): API接口,提供外部调用接口
155
- - [`src/lib/utils.ts`](src/lib/utils.ts): 工具函数,通用工具方法
156
- - [`src/lib/error.ts`](src/lib/error.ts): 错误处理,统一的错误捕获和处理
157
-
158
- #### 架构特点
159
- - **分层架构**: 驱动层、服务层、接口层清晰分离
160
- - **插件化设计**: 各模块可独立启用/禁用
161
- - **高内聚低耦合**: 模块间通过明确定义的接口交互
162
- - **可扩展性**: 易于添加新的存储驱动或功能模块
163
-
164
- ## 请求工具
165
-
166
- ### 1. 工具说明
167
- 项目中封装了兼容性更好的请求工具 [`src/lib/request.ts`](src/lib/request.ts),提供以下功能:
168
- - 兼容性更好的 HTTP 请求(基于 XMLHttpRequest)
169
- - 支持 GET/POST 方法
170
- - 支持超时设置
171
- - 统一的错误处理
172
-
173
- ### 2. 使用方式
174
- ```typescript
175
- import { get, post, request } from './lib/request';
48
+ | 方法 | 说明 |
49
+ |------|------|
50
+ | `init({ serv, appId, cdnConfigUrl? })` | 初始化 SDK,返回 `{ cancel }` |
51
+ | `cancelRecord(options?)` | 停止录制(推荐使用 `rlog.cancel()`) |
52
+ | `addCustomEvent(tag, payload)` | 添加自定义事件到录制流 |
53
+ | `reportError(error)` | 手动上报错误(Error 对象或字符串) |
176
54
 
177
- // GET 请求
178
- const response = await get('https://api.example.com/data');
55
+ ### 网络配置
179
56
 
180
- // POST 请求
181
- const response = await post('https://api.example.com/data', { key: 'value' });
57
+ | 方法 | 说明 |
58
+ |------|------|
59
+ | `setCustomHeaders(headers)` | 设置全局自定义请求头(注入到 XHR/Fetch) |
60
+ | `getCustomHeaders()` | 获取当前自定义请求头 |
61
+ | `setWhiteListUrls(urls)` | 设置白名单 URL(仅监控这些请求) |
62
+ | `getWhiteListUrls()` | 获取白名单 |
63
+ | `setBlackListUrls(urls)` | 设置黑名单 URL(排除这些请求) |
64
+ | `getBlackListUrls()` | 获取黑名单 |
182
65
 
183
- // 自定义请求
184
- const response = await request('https://api.example.com/data', {
185
- method: 'POST',
186
- headers: { 'Content-Type': 'application/json' },
187
- body: JSON.stringify({ key: 'value' }),
188
- timeout: 5000
189
- });
190
- ```
66
+ > 黑名单优先于白名单。白名单为空时监控所有非黑名单请求。
191
67
 
192
- ## 性能优化方案
193
-
194
- ### 1. Canvas录制动态采样
195
- **自适应采样算法**:
196
- ```ts
197
- class SamplingController {
198
- // 设备性能评估
199
- static getSamplingRate(): number {
200
- const isMobile = /Mobi/.test(navigator.userAgent);
201
- const deviceMemory = (navigator as any).deviceMemory || 4;
202
-
203
- // 动态计算采样率:
204
- // 1. 根据设备类型选择基准值
205
- // 2. 根据内存大小动态调整(4GB基准,每增加1GB降低1帧)
206
- // 3. 最低不低于5帧保证录制可用性
207
- const baseRate = isMobile ? 8 : 15;
208
- const memoryFactor = Math.max(0, 4 - (deviceMemory - 4));
209
-
210
- return Math.max(5, baseRate - memoryFactor);
211
- }
212
-
213
- // 实时性能监控(每5秒检测一次)
214
- static startPerformanceMonitor() {
215
- setInterval(() => {
216
- const fps = this.calculateFPS();
217
- if (fps < 15) { // 低性能预警
218
- this.throttleRecording();
219
- } else if (fps > 25) { // 高性能提升
220
- this.boostSampling();
221
- }
222
- }, 5000);
223
- }
224
- }
68
+ ### 路由监控
225
69
 
226
- // 在rrweb初始化时应用
227
- rrweb.record({
228
- sampling: {
229
- canvas: SamplingController.getSamplingRate()
230
- }
231
- });
232
- ```
70
+ | 方法 | 说明 |
71
+ |------|------|
72
+ | `updateRouterConfig(config)` | 更新路由监控配置 |
73
+ | `getCurrentRouteInfo()` | 获取当前路由信息 |
74
+ | `manualRouteChange(newRoute, prevRoute?)` | 手动触发路由变化事件 |
75
+ | `stopRouterMonitor()` | 停止路由监控 |
233
76
 
234
- **性能指标**:
235
- | 指标 | 目标值 | 监控方式 |
236
- |------|-------|---------|
237
- | FPS | ≥15 | requestAnimationFrame |
238
- | 内存占用 | ≤15MB | performance.memory |
239
- | CPU使用率 | ≤30% | navigator.hardwareConcurrency |
240
-
241
- ### 2. 存储性能优化
242
- **批量写入策略**:
243
- ```ts
244
- // IndexedDBAdapter增强
245
- async push(deviceId: string, data: any): Promise<void> {
246
- // 实现批量缓冲
247
- if (!this.writeBuffer) {
248
- this.writeBuffer = [];
249
- // 500ms批量提交
250
- setTimeout(() => this.flushBuffer(), 500);
251
- }
252
- this.writeBuffer.push({ deviceId, data });
253
- }
77
+ ### Consume-Only 模式
254
78
 
255
- private async flushBuffer(): Promise<void> {
256
- if (!this.db || !this.writeBuffer) return;
257
-
258
- const transaction = this.db.transaction(STORE_NAME, 'readwrite');
259
- const store = transaction.objectStore(STORE_NAME);
260
-
261
- // 使用游标批量更新
262
- const cursor = await store.openCursor();
263
- while (cursor) {
264
- const updated = this.writeBuffer.find(
265
- item => item.deviceId === cursor.key
266
- );
267
- if (updated) {
268
- await cursor.update({
269
- ...cursor.value,
270
- data: [...cursor.value.data, ...updated.data]
271
- });
272
- }
273
- await cursor.continue();
274
- }
275
-
276
- this.writeBuffer = null;
277
- }
278
- ```
79
+ | 方法 | 说明 |
80
+ |------|------|
81
+ | `setConsumeOnlyMode(enable)` | 开启/关闭只采集不上报 |
82
+ | `isConsumeOnlyMode()` | 查询当前是否为只采集模式 |
83
+ | `toggleConsumeOnlyMode()` | 切换模式,返回新状态 |
279
84
 
280
- ## 加密模块设计
281
-
282
- ### 1. 加密架构设计
283
- ```mermaid
284
- sequenceDiagram
285
- participant SDK
286
- participant Crypto
287
- participant Storage
288
-
289
- SDK->>Crypto: setEncryptionKey() 设置密钥
290
- SDK->>Crypto: encryptData() 请求加密
291
- Crypto->>Crypto: 生成IV (12字节)
292
- Crypto->>Crypto: 使用AES-GCM加密
293
- Crypto-->>SDK: 返回Base64加密数据
294
- SDK->>Storage: 存储加密数据
295
- ```
85
+ ### 调试工具
296
86
 
297
- ### 2. 加密实现细节
298
- ```ts
299
- // 加密配置接口
300
- interface EncryptionConfig {
301
- enabled: boolean; // 加密开关
302
- algorithm: 'AES-GCM' | 'AES-CBC'; // 算法选择
303
- keyLength: 128 | 192 | 256; // 密钥长度
304
- autoRotate: boolean; // 密钥自动轮换
305
- rotationInterval: number; // 轮换间隔(小时)
306
- }
87
+ 通过 `debug` 对象访问:
307
88
 
308
- // 加密服务实现
309
- class EncryptionService {
310
- private key: CryptoKey | null = null;
311
- private config: EncryptionConfig = {
312
- enabled: false,
313
- algorithm: 'AES-GCM',
314
- keyLength: 256,
315
- autoRotate: true,
316
- rotationInterval: 24
317
- };
318
-
319
- async setKey(key: CryptoKey): Promise<void> {
320
- this.key = key;
321
- if (this.config.autoRotate) {
322
- this.scheduleKeyRotation();
323
- }
324
- }
325
-
326
- async encrypt(data: any): Promise<string> {
327
- if (!this.config.enabled || !this.key) {
328
- return JSON.stringify(data);
329
- }
330
-
331
- const iv = crypto.getRandomValues(new Uint8Array(12));
332
- const encoder = new TextEncoder();
333
- const encrypted = await crypto.subtle.encrypt(
334
- {
335
- name: this.config.algorithm,
336
- iv
337
- },
338
- this.key,
339
- encoder.encode(JSON.stringify(data))
340
- );
341
-
342
- // 返回包含元数据的加密数据
343
- return JSON.stringify({
344
- v: 1, // 版本号
345
- alg: this.config.algorithm,
346
- iv: arrayBufferToBase64(iv),
347
- data: arrayBufferToBase64(encrypted)
348
- });
349
- }
350
-
351
- private scheduleKeyRotation(): void {
352
- setInterval(async () => {
353
- const newKey = await this.generateKey();
354
- await this.rotateKey(newKey);
355
- }, this.config.rotationInterval * 3600000);
356
- }
357
- }
89
+ ```typescript
90
+ import { debug } from '@antglobal/rlog-sdk';
91
+
92
+ debug.getStorageAdapterType(); // 当前存储类型: 'indexeddb' | 'localstorage' | 'memory'
93
+ debug.getDeviceId(); // 设备 ID
94
+ debug.getSessionId(); // 当前 Tab 的 Session ID
95
+ debug.getStorageKey(); // 存储键 (deviceId_sessionId)
96
+ debug.resetUploadState(); // 重置上传状态
97
+ debug.getStorageState(); // Promise<{ adapterType, eventCount }>
98
+ debug.clearStorage(); // Promise<void> 清空存储
99
+ debug.getConfig(); // 当前 CDN 配置
100
+ debug.shouldRecordUrl(url); // 判断 URL 是否会被网络监控记录
358
101
  ```
359
102
 
360
- ### 3. 敏感数据脱敏
361
- ```ts
362
- // 脱敏配置
363
- interface SanitizationRule {
364
- selector: string; // CSS选择器
365
- type: 'mask' | 'hash' | 'remove'; // 脱敏类型
366
- hashAlgorithm?: 'SHA-1' | 'SHA-256'; // 哈希算法
367
- maskChar?: string; // 掩码字符
368
- maskLength?: number; // 掩码长度
369
- }
103
+ ## CDN 动态配置
370
104
 
371
- // 脱敏处理器
372
- class DataSanitizer {
373
- private rules: SanitizationRule[] = [
374
- {
375
- selector: 'input[type="password"]',
376
- type: 'mask',
377
- maskChar: '*',
378
- maskLength: 8
379
- },
380
- {
381
- selector: 'input[name="credit-card"]',
382
- type: 'hash',
383
- hashAlgorithm: 'SHA-256'
105
+ 通过 `cdnConfigUrl` 传入远程 JSON 配置,SDK 会定期拉取更新。完整配置项:
106
+
107
+ ```json
108
+ {
109
+ "enable": false,
110
+ "uploadInterval": 2000,
111
+ "configUpdateInterval": 300000,
112
+ "captureMode": "full",
113
+ "packEvents": false,
114
+ "clearStorageBeforeRecord": true,
115
+ "http": false,
116
+ "maxRetryCount": 3,
117
+ "consumeOnly": false,
118
+ "urlParamsToCache": [],
119
+ "sampling": {
120
+ "canvas": 15,
121
+ "mousemove": 50,
122
+ "scroll": 100,
123
+ "input": "last"
124
+ },
125
+ "ignoreClass": "rr-ignore",
126
+ "blockClass": "rr-block",
127
+ "maskTextClass": "rr-mask",
128
+ "console": {
129
+ "enable": false,
130
+ "level": ["log", "warn", "error", "info"],
131
+ "lengthThreshold": 1000,
132
+ "stringifyOptions": {
133
+ "stringLengthLimit": 500,
134
+ "numOfKeysLimit": 50,
135
+ "depthOfLimit": 4
384
136
  }
385
- ];
386
-
387
- sanitize(data: any): any {
388
- const result = { ...data };
389
-
390
- // 遍历DOM节点应用脱敏规则
391
- document.querySelectorAll('*').forEach(node => {
392
- const element = node as HTMLElement;
393
- this.rules.forEach(rule => {
394
- if (element.matches(rule.selector)) {
395
- switch (rule.type) {
396
- case 'mask':
397
- result.textContent = this.applyMask(
398
- element.textContent || '',
399
- rule.maskChar || '*',
400
- rule.maskLength || 8
401
- );
402
- break;
403
- case 'hash':
404
- result.textContent = this.hashContent(
405
- element.textContent || '',
406
- rule.hashAlgorithm || 'SHA-256'
407
- );
408
- break;
409
- case 'remove':
410
- result.remove();
411
- break;
412
- }
413
- }
414
- });
415
- });
416
-
417
- return result;
137
+ },
138
+ "routerMonitor": {
139
+ "enable": false,
140
+ "trackHashChange": true,
141
+ "trackHistoryChange": true,
142
+ "trackPageStayTime": true,
143
+ "ignoreRoutes": []
144
+ },
145
+ "errorCapture": {
146
+ "beforeDuration": 30000,
147
+ "afterDuration": 30000,
148
+ "httpErrorThreshold": 400
418
149
  }
419
150
  }
420
151
  ```
421
152
 
422
- ## 网络配置API参考
423
-
424
- ### 1. 配置方法
425
-
426
- #### setWhiteListUrls(urls: string[])
427
- 设置白名单URL列表,只有这些接口会被记录和监控。
153
+ ### 配置说明
154
+
155
+ | 字段 | 默认值 | 说明 |
156
+ |------|--------|------|
157
+ | `enable` | `false` | 采集总开关 |
158
+ | `uploadInterval` | `2000` | 上传间隔(ms) |
159
+ | `configUpdateInterval` | `300000` | 配置刷新间隔(ms) |
160
+ | `captureMode` | `"full"` | `"full"` 全量录制 / `"error"` 错误触发录制 |
161
+ | `packEvents` | `false` | 是否压缩事件数据 |
162
+ | `clearStorageBeforeRecord` | `true` | 录制前是否清空存储 |
163
+ | `http` | `false` | 是否开启网络请求监控 |
164
+ | `maxRetryCount` | `3` | 上传失败最大重试次数 |
165
+ | `consumeOnly` | `false` | 只采集不上报 |
166
+ | `sampling.canvas` | `15` | Canvas 采样率(fps) |
167
+ | `sampling.mousemove` | `50` | 鼠标移动采样间隔(ms) |
168
+ | `sampling.scroll` | `100` | 滚动防抖间隔(ms) |
169
+ | `sampling.input` | `"last"` | `"all"` 全部 / `"last"` 仅最终值 |
170
+ | `errorCapture.beforeDuration` | `30000` | 错误前录制时长(ms) |
171
+ | `errorCapture.afterDuration` | `30000` | 错误后继续录制时长(ms) |
172
+ | `errorCapture.httpErrorThreshold` | `400` | HTTP 错误状态码阈值 |
173
+
174
+ ## 采集模式
175
+
176
+ ### Full 模式(默认)
177
+
178
+ 持续录制所有用户操作,按 `uploadInterval` 定时上传,每批最多 100 条事件。
179
+
180
+ ### Error 模式
181
+
182
+ 事件持续写入本地存储,仅在错误发生时触发上传。上传时间窗口为 `[now - beforeDuration, now + afterDuration]`。若 `afterDuration` 期间再次发生错误,窗口自动延长。
183
+
184
+ ## 架构
185
+
186
+ ```
187
+ src/
188
+ ├── index.ts # 公共 API 导出
189
+ └── lib/
190
+ ├── init.ts # SDK 初始化与销毁
191
+ ├── config.ts # CDN 配置管理
192
+ ├── rrweb.ts # rrweb 录制启动
193
+ ├── storage-manager.ts # 存储管理(序列化队列)
194
+ ├── uploader.ts # 上传调度(全量/错误模式)
195
+ ├── upload-worker-manager.ts # Web Worker 管理
196
+ ├── upload-worker.ts # Worker 上传逻辑
197
+ ├── net.ts # 网络监控(XHR/Fetch 拦截)
198
+ ├── api.ts # 上传接口
199
+ ├── request.ts # HTTP 请求工具
200
+ ├── router-monitor.ts # 路由监控
201
+ ├── error.ts # 错误捕获
202
+ ├── error-trigger.ts # 错误模式状态机
203
+ ├── utils.ts # 工具函数
204
+ ├── logger.ts # 日志输出
205
+ ├── constants.ts # 常量定义
206
+ └── drive/
207
+ ├── storage-interface.ts # StorageAdapter 接口
208
+ ├── indexeddb-adapt.ts # IndexedDB 适配器
209
+ ├── localstorage-adapt.ts # LocalStorage 适配器(含分布式锁)
210
+ ├── memory-adapt.ts # Memory 适配器
211
+ └── safe-storage.ts # 安全 KV 存储(降级到内存)
212
+ ```
213
+
214
+ ## 多 Tab 并发
215
+
216
+ - 每个标签页分配唯一 `sessionId`,存储键为 `deviceId_sessionId`
217
+ - Session 注册表追踪活跃标签页
218
+ - SDK 初始化时自动清理孤儿 session 的残留数据
219
+ - LocalStorage 操作通过分布式锁(CAS + 超时)保证原子性
220
+
221
+ ## 上传重试
222
+
223
+ 上传失败时事件回退到队列头部,下个周期重试。连续失败达到 `maxRetryCount` 后:
224
+ 1. 派发 `rlog-upload-failure` 自定义事件(window + rrweb)
225
+ 2. 停止 rrweb 录制
226
+ 3. 停止上传循环
227
+
228
+ 监听失败事件:
428
229
 
429
- **参数:**
430
- - `urls`: string[] - URL列表,支持完整URL和相对路径
431
-
432
- **示例:**
433
230
  ```javascript
434
- Rlog.setWhiteListUrls([
435
- 'https://api.example.com',
436
- '/api/v1/', // 相对路径
437
- '/ebank/api/v1/rlog/record'
438
- ]);
231
+ window.addEventListener('rlog-upload-failure', (e) => {
232
+ console.log('上传失败', e.detail);
233
+ });
439
234
  ```
440
235
 
441
- #### setBlackListUrls(urls: string[])
442
- 设置黑名单URL列表,这些接口将不会被记录和监控。
443
-
444
- **参数:**
445
- - `urls`: string[] - URL列表,支持完整URL和相对路径
236
+ ## 开发
446
237
 
447
- **示例:**
448
- ```javascript
449
- Rlog.setBlackListUrls([
450
- 'https://api.sensitive.com/user-info',
451
- '/api/auth/token',
452
- '/ebank/api/v1/rlog/record' // 避免循环上报
453
- ]);
238
+ ```bash
239
+ npm run dev # 开发模式
240
+ npm run build # 构建(ESM + CJS)
454
241
  ```
455
242
 
456
- #### getWhiteListUrls(): string[]
457
- 获取当前白名单URL列表。
458
-
459
- **返回值:**
460
- - string[] - 当前白名单URL列表
461
-
462
- #### getBlackListUrls(): string[]
463
- 获取当前黑名单URL列表。
464
-
465
- **返回值:**
466
- - string[] - 当前黑名单URL列表
467
-
468
- ### 2. 配置优先级
469
- 网络接口的过滤优先级如下:
470
- 1. **黑名单优先**:如果URL在黑名单中,无论是否在白名单都不会被记录
471
- 2. **白名单过滤**:只有在白名单中的URL才会被记录(如果不在黑名单中)
472
- 3. **默认行为**:如果白名单为空,则记录所有不在黑名单中的请求
473
-
474
- ### 3. 路径匹配规则
475
-
476
- #### 完整URL匹配
477
- ```javascript
478
- // 匹配以指定URL开头的请求
479
- 'https://api.example.com/v1/users' // 匹配 https://api.example.com/v1/users/123
480
- ```
481
-
482
- #### 相对路径匹配
483
- ```javascript
484
- // 匹配以指定路径开头的请求
485
- '/api/v1/' // 匹配 /api/v1/users, /api/v1/data 等
486
- '/ebank/api/v1/rlog/record' // 精确匹配该路径
487
- ```
488
-
489
- #### 域名匹配
490
- ```javascript
491
- // 匹配指定域名下的所有请求
492
- 'api.example.com' // 匹配该域名下的所有接口
493
- ```
243
+ ## License
494
244
 
495
- ## 相关文档和示例
496
-
497
- ### 1. 路由监控功能
498
- - [详细使用指南](docs/ROUTER_MONITOR_GUIDE.md) - 包含完整的路由监控配置和使用示例
499
- - [在线示例](examples/test-router-monitor.html) - 可直接在浏览器中测试路由监控功能
500
-
501
- ### 2. 上传重试机制
502
- - [重试逻辑指南](docs/RETRY_LOGIC_GUIDE.md) - 上传失败后的重试策略和配置
503
- - [重试测试示例](examples/test-retry-logic.html) - 测试上传重试功能
504
-
505
- ### 3. 消费模式
506
- - [消费模式指南](docs/CONSUME_ONLY_MODE_GUIDE.md) - 仅消费数据的轻量级使用模式
507
- - [消费模式示例](examples/consume-only-mode.html) - 消费模式的实际应用示例
508
-
509
- ### 4. 取消方法
510
- - [取消方法指南](docs/CANCEL_METHOD_GUIDE.md) - 如何正确停止录制和数据收集
511
- - [取消方法示例](examples/test-cancel.html) - 演示如何正确停止录制和数据收集
512
-
513
- ## 改进建议实施状态
514
- | 改进项 | 实施状态 | 完成度 |
515
- |-------|----------|--------|
516
- | IndexedDB降级修复 | 已完成 | 100% |
517
- | 动态采样率调整 | 已完成 | 100% |
518
- | 路由监控功能 | 已完成 | 100% |
519
- | 错误处理优化 | 设计中 | 50% |
520
- | 上传重试机制 | 已完成 | 100% |
521
- | 消费模式支持 | 已完成 | 100% |
522
- | 取消方法支持 | 已完成 | 100% |
523
- | 移动端触控增强 | 未开始 | 0% |
524
- | 数据加密模块 | 设计完成 | 50% |
525
- | 数据压缩模块 | 未开始 | 0% |
245
+ MIT