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