@be-link/cls-logger 1.0.11 → 1.0.12
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 +430 -68
- package/dist/ClsLoggerCore.d.ts +37 -5
- package/dist/ClsLoggerCore.d.ts.map +1 -1
- package/dist/index.esm.js +379 -62
- package/dist/index.js +379 -62
- package/dist/index.umd.js +379 -62
- package/dist/mini/behaviorMonitor.d.ts.map +1 -1
- package/dist/mini/deviceInfo.d.ts.map +1 -1
- package/dist/mini/errorMonitor.d.ts.map +1 -1
- package/dist/mini.esm.js +278 -49
- package/dist/mini.js +278 -49
- package/dist/types.d.ts +41 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/web/deviceInfo.d.ts.map +1 -1
- package/dist/web/errorMonitor.d.ts.map +1 -1
- package/dist/web/performanceMonitor.d.ts.map +1 -1
- package/dist/web.esm.js +303 -38
- package/dist/web.js +303 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,79 +2,86 @@
|
|
|
2
2
|
|
|
3
3
|
腾讯云 CLS(`tencentcloud-cls-sdk-js-web` / `tencentcloud-cls-sdk-js-mini`)日志上报封装,支持 Web、H5 和小程序环境,提供统一的调用方式。
|
|
4
4
|
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 自动环境适配(Web / H5 / 小程序)
|
|
8
|
+
- 内存队列批量上报,减少网络请求
|
|
9
|
+
- 页面关闭时 `sendBeacon` 保证日志不丢失
|
|
10
|
+
- 支持浏览器空闲时上报(`requestIdleCallback`)
|
|
11
|
+
- 错误即时上报,信息日志批量上报
|
|
12
|
+
- 自动采集:请求监控、性能监控、错误监控、行为埋点
|
|
13
|
+
- 失败重试 + 本地缓存兜底
|
|
14
|
+
|
|
5
15
|
## 安装
|
|
6
16
|
|
|
7
17
|
```bash
|
|
8
18
|
pnpm add @be-link/cls-logger
|
|
9
19
|
```
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
>
|
|
13
|
-
> 1. SDK 内部会自动根据运行环境加载对应的腾讯云 SDK(Web 或小程序),无需手动安装额外依赖。
|
|
14
|
-
> 2. 如果业务对包体积有极致要求,建议使用**分环境引入方式**(见下文)。
|
|
21
|
+
### 依赖说明
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
| 入口 | 依赖 | 说明 |
|
|
24
|
+
| -------------------------- | -------------------------------------------- | ----------------------------------- |
|
|
25
|
+
| `@be-link/cls-logger` | `tencentcloud-cls-sdk-js-web` | 统一入口,自动适配环境 |
|
|
26
|
+
| `@be-link/cls-logger/web` | `tencentcloud-cls-sdk-js-web` + `web-vitals` | Web/H5 专用,含 Web Vitals 性能监控 |
|
|
27
|
+
| `@be-link/cls-logger/mini` | `tencentcloud-cls-sdk-js-mini` | 小程序专用 |
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
> **注意**:所有依赖已内置,无需手动安装。
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
## 快速开始
|
|
32
|
+
|
|
33
|
+
### 1. 统一引入方式(推荐快速接入)
|
|
21
34
|
|
|
22
35
|
```ts
|
|
23
36
|
import clsLogger from '@be-link/cls-logger';
|
|
24
37
|
|
|
25
|
-
// 初始化(建议在应用入口处调用)
|
|
26
38
|
clsLogger.init({
|
|
27
39
|
projectId: 'my-project',
|
|
28
40
|
appId: 'my-app-id',
|
|
29
|
-
// 默认配置可不传
|
|
30
|
-
// tencentCloud: {
|
|
31
|
-
// endpoint: 'https://ap-shanghai.cls.tencentcs.com',
|
|
32
|
-
// topicID: '17475bcd-6315-4b20-859c-e7b087fb3683',
|
|
33
|
-
// },
|
|
34
41
|
source: 'my-source',
|
|
35
42
|
});
|
|
36
43
|
```
|
|
37
44
|
|
|
38
|
-
### 2.
|
|
45
|
+
### 2. 分环境引入方式(推荐生产环境)
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#### Web / H5 项目:
|
|
47
|
+
#### Web / H5:
|
|
43
48
|
|
|
44
49
|
```ts
|
|
45
|
-
// 仅包含 Web 相关逻辑,不再包含小程序代码
|
|
46
50
|
import { clsLogger } from '@be-link/cls-logger/web';
|
|
47
51
|
|
|
48
52
|
clsLogger.init({
|
|
49
53
|
projectId: 'my-web-project',
|
|
50
|
-
// tencentCloud: { ... }, // 可选
|
|
51
54
|
source: 'web-source',
|
|
52
55
|
});
|
|
53
56
|
```
|
|
54
57
|
|
|
55
|
-
####
|
|
58
|
+
#### 小程序:
|
|
56
59
|
|
|
57
60
|
```ts
|
|
58
|
-
// 仅包含小程序相关逻辑,不再包含 Web 代码
|
|
59
61
|
import { clsLogger } from '@be-link/cls-logger/mini';
|
|
60
62
|
|
|
61
63
|
clsLogger.init({
|
|
62
64
|
projectId: 'my-mini-project',
|
|
63
|
-
appId: 'wx123456789',
|
|
64
|
-
// tencentCloud: { ... }, // 可选
|
|
65
|
+
appId: 'wx123456789',
|
|
65
66
|
source: 'mini-source',
|
|
66
67
|
});
|
|
67
68
|
```
|
|
68
69
|
|
|
69
|
-
##
|
|
70
|
+
## API
|
|
70
71
|
|
|
71
|
-
###
|
|
72
|
+
### 日志方法
|
|
72
73
|
|
|
73
74
|
```ts
|
|
74
|
-
//
|
|
75
|
+
// 信息日志(走批量队列)
|
|
75
76
|
clsLogger.info('应用启动', { startUpTime: 120 });
|
|
76
77
|
|
|
77
|
-
//
|
|
78
|
+
// 警告日志(走批量队列)
|
|
79
|
+
clsLogger.warn('资源加载慢', { duration: 3000 });
|
|
80
|
+
|
|
81
|
+
// 错误日志(默认即时上报)
|
|
82
|
+
clsLogger.error('支付失败', { orderId: '123' });
|
|
83
|
+
|
|
84
|
+
// Error 对象(自动解析堆栈)
|
|
78
85
|
try {
|
|
79
86
|
doSomething();
|
|
80
87
|
} catch (err) {
|
|
@@ -82,7 +89,17 @@ try {
|
|
|
82
89
|
}
|
|
83
90
|
```
|
|
84
91
|
|
|
85
|
-
###
|
|
92
|
+
### 即时上报选项
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// info/warn 强制即时上报
|
|
96
|
+
clsLogger.info('重要事件', { data: 1 }, { immediate: true });
|
|
97
|
+
|
|
98
|
+
// error 走批量队列(默认是即时上报)
|
|
99
|
+
clsLogger.error('非关键错误', { data: 1 }, { immediate: false });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 自定义埋点
|
|
86
103
|
|
|
87
104
|
```ts
|
|
88
105
|
clsLogger.track('click_event', {
|
|
@@ -91,9 +108,7 @@ clsLogger.track('click_event', {
|
|
|
91
108
|
});
|
|
92
109
|
```
|
|
93
110
|
|
|
94
|
-
### 统计埋点
|
|
95
|
-
|
|
96
|
-
用于简单的计数/分布统计。
|
|
111
|
+
### 统计埋点
|
|
97
112
|
|
|
98
113
|
```ts
|
|
99
114
|
clsLogger.stat({
|
|
@@ -104,67 +119,395 @@ clsLogger.stat({
|
|
|
104
119
|
});
|
|
105
120
|
```
|
|
106
121
|
|
|
107
|
-
##
|
|
122
|
+
## 配置项
|
|
123
|
+
|
|
124
|
+
### 完整配置示例
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
clsLogger.init({
|
|
128
|
+
// 基础配置
|
|
129
|
+
enabled: true, // 是否启用,默认 true
|
|
130
|
+
projectId: 'my-project', // 项目标识
|
|
131
|
+
appId: 'wx123456789', // 应用 ID(小程序必填)
|
|
132
|
+
appVersion: '1.0.0', // 应用版本
|
|
133
|
+
source: 'my-source', // CLS source
|
|
134
|
+
|
|
135
|
+
// 腾讯云 CLS 配置
|
|
136
|
+
tencentCloud: {
|
|
137
|
+
endpoint: 'https://ap-shanghai.cls.tencentcs.com',
|
|
138
|
+
topicID: 'your-topic-id',
|
|
139
|
+
retry_times: 3,
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
// 批量上报配置
|
|
143
|
+
batch: {
|
|
144
|
+
maxSize: 50, // 队列达到此数量立即发送,默认 20
|
|
145
|
+
intervalMs: 1000, // 定时批量发送间隔,默认 500ms
|
|
146
|
+
startupDelayMs: 3000, // 启动合并窗口,默认 0(不启用)
|
|
147
|
+
startupMaxSize: 500, // 启动窗口内的队列阈值,默认 maxSize*10(至少200)
|
|
148
|
+
useIdleCallback: true, // 使用浏览器空闲时间上报,默认 false
|
|
149
|
+
idleTimeout: 3000, // 空闲回调超时时间,默认 3000ms
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// 请求监控配置
|
|
153
|
+
requestMonitor: {
|
|
154
|
+
enabled: true, // 是否开启,默认 true
|
|
155
|
+
sampleRate: 1, // 采样率 0~1,默认 1
|
|
156
|
+
ignoreUrls: [/localhost/], // 忽略的 URL
|
|
157
|
+
includeMethod: true, // 是否携带 method,默认 true
|
|
158
|
+
includeQuery: true, // 是否携带 query,默认 true
|
|
159
|
+
includeBody: true, // 是否携带 body,默认 true
|
|
160
|
+
maxParamLength: 2000, // 参数最大长度,默认 2000
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
// 错误监控配置
|
|
164
|
+
errorMonitor: {
|
|
165
|
+
enabled: true, // 是否开启,默认 true
|
|
166
|
+
sampleRate: 1, // 采样率 0~1,默认 1
|
|
167
|
+
captureResourceError: true, // 是否采集资源加载错误,默认 true
|
|
168
|
+
maxTextLength: 4000, // stack/message 最大长度,默认 4000
|
|
169
|
+
dedupeWindowMs: 3000, // 错误去重窗口,默认 3000ms
|
|
170
|
+
dedupeMaxKeys: 200, // 去重缓存最大 key 数,默认 200
|
|
171
|
+
ignoreMessages: [
|
|
172
|
+
// 忽略的错误信息(默认值)
|
|
173
|
+
'Script error.',
|
|
174
|
+
'Script error',
|
|
175
|
+
/^ResizeObserver loop/,
|
|
176
|
+
'Permission was denied',
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// 性能监控配置
|
|
181
|
+
performanceMonitor: {
|
|
182
|
+
enabled: true, // 是否开启,默认 true
|
|
183
|
+
sampleRate: 1, // 采样率 0~1,默认 1
|
|
184
|
+
webVitals: true, // 是否采集 Web Vitals(含 TTFB),默认 true
|
|
185
|
+
resourceTiming: true, // 是否采集资源加载耗时,默认 true
|
|
186
|
+
ignoreUrls: [/localhost/], // 忽略的资源 URL
|
|
187
|
+
maxTextLength: 2000, // 性能指标文本最大长度,默认 2000
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
// 行为埋点配置
|
|
191
|
+
behaviorMonitor: {
|
|
192
|
+
enabled: true, // 是否开启,默认 true
|
|
193
|
+
pv: true, // PV 是否开启,默认 true
|
|
194
|
+
uv: true, // UV 是否开启,默认 true
|
|
195
|
+
click: true, // 点击是否开启,默认 true
|
|
196
|
+
sampleRate: 1, // 采样率 0~1,默认 1
|
|
197
|
+
uvExpireDays: 30, // UV 标识过期天数,默认 30
|
|
198
|
+
clickTrackIdAttr: 'data-track-id', // 点击元素埋点标识属性名
|
|
199
|
+
clickMaxTextLength: 120, // 点击文本最大长度,默认 120
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// 设备信息配置
|
|
203
|
+
deviceInfo: {
|
|
204
|
+
enabled: true, // 是否开启,默认 true
|
|
205
|
+
includeUserAgent: true, // 是否包含 UA,默认 true
|
|
206
|
+
includeNetwork: true, // 是否包含网络信息,默认 true
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// 自定义基础字段
|
|
210
|
+
generateBaseFields: () => ({
|
|
211
|
+
userId: getUserId(),
|
|
212
|
+
userName: getUserName(),
|
|
213
|
+
environment: 'production',
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## 常见场景配置
|
|
219
|
+
|
|
220
|
+
### 场景 1:首屏请求过多
|
|
221
|
+
|
|
222
|
+
页面首次加载时日志请求过多,影响其他请求:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
clsLogger.init({
|
|
226
|
+
batch: {
|
|
227
|
+
startupDelayMs: 3000, // 启动 3 秒内的日志合并发送
|
|
228
|
+
startupMaxSize: 500, // 启动窗口内允许更多日志积累(防止 maxSize 打断合并)
|
|
229
|
+
maxSize: 100, // 正常运行时的队列阈值
|
|
230
|
+
intervalMs: 2000, // 延长批量间隔
|
|
231
|
+
useIdleCallback: true, // 等待延迟后在浏览器空闲时上报
|
|
232
|
+
},
|
|
233
|
+
performanceMonitor: {
|
|
234
|
+
resourceTiming: false, // 关闭资源监控(首屏资源多时可大幅减少日志量)
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
> **说明**:`startupMaxSize` 确保启动窗口内不会因为 `maxSize` 被频繁触发而打断日志合并。
|
|
240
|
+
|
|
241
|
+
### 场景 2:减少资源监控日志
|
|
242
|
+
|
|
243
|
+
开发环境资源过多,或生产环境不需要全量资源监控:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
clsLogger.init({
|
|
247
|
+
performanceMonitor: {
|
|
248
|
+
resourceTiming: false, // 关闭资源监控
|
|
249
|
+
// 或者采样
|
|
250
|
+
// sampleRate: 0.1, // 10% 采样
|
|
251
|
+
// 或者过滤
|
|
252
|
+
// ignoreUrls: [/localhost/, /node_modules/],
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 场景 3:过滤无意义的错误
|
|
258
|
+
|
|
259
|
+
过滤第三方 SDK 的跨域错误:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
clsLogger.init({
|
|
263
|
+
errorMonitor: {
|
|
264
|
+
ignoreMessages: [
|
|
265
|
+
// 默认规则
|
|
266
|
+
'Script error.',
|
|
267
|
+
'Script error',
|
|
268
|
+
/^ResizeObserver loop/,
|
|
269
|
+
'Permission was denied',
|
|
270
|
+
// 自定义规则
|
|
271
|
+
/火山SDK/,
|
|
272
|
+
/VolcEngine/,
|
|
273
|
+
/network error/i,
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 场景 4:高并发场景(直播间)
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
clsLogger.init({
|
|
283
|
+
batch: {
|
|
284
|
+
startupDelayMs: 3000, // 启动合并窗口
|
|
285
|
+
startupMaxSize: 500, // 启动窗口内的队列阈值
|
|
286
|
+
maxSize: 100, // 正常运行时的队列阈值
|
|
287
|
+
intervalMs: 2000, // 延长批量间隔
|
|
288
|
+
useIdleCallback: true, // 空闲时上报,不阻塞主线程
|
|
289
|
+
},
|
|
290
|
+
performanceMonitor: {
|
|
291
|
+
resourceTiming: false, // 关闭资源监控
|
|
292
|
+
},
|
|
293
|
+
requestMonitor: {
|
|
294
|
+
sampleRate: 0.1, // 请求监控采样 10%
|
|
295
|
+
ignoreUrls: [
|
|
296
|
+
/heartbeat/i, // 忽略心跳请求
|
|
297
|
+
/polling/i, // 忽略轮询请求
|
|
298
|
+
/danmaku|barrage/i, // 忽略弹幕请求
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## 最佳实践
|
|
108
305
|
|
|
109
|
-
### 1.
|
|
306
|
+
### 1. 批量配置的正确姿势
|
|
110
307
|
|
|
111
|
-
|
|
112
|
-
- **小程序**: 自动采集小程序环境信息(系统信息、微信版本、网络类型等)。
|
|
308
|
+
#### `useIdleCallback` 工作原理
|
|
113
309
|
|
|
114
|
-
|
|
310
|
+
当 `useIdleCallback: true` 时,SDK 的上报流程为:
|
|
115
311
|
|
|
116
|
-
|
|
312
|
+
```
|
|
313
|
+
日志产生 → 等待 intervalMs/startupDelayMs → 等待浏览器空闲 → 发送
|
|
314
|
+
↑ 最小等待时间 ↑ 在 idleTimeout 内空闲就发送
|
|
315
|
+
```
|
|
117
316
|
|
|
118
|
-
|
|
119
|
-
- **小程序**: 拦截 `wx.request` / `wx.cloud.callFunction`。
|
|
317
|
+
**关键点**:
|
|
120
318
|
|
|
121
|
-
|
|
319
|
+
- `intervalMs`/`startupDelayMs` 是**最小等待时间**,保证不会过早发送
|
|
320
|
+
- `idleTimeout` 是空闲等待的**最大时间**,防止浏览器一直繁忙导致日志积压
|
|
122
321
|
|
|
123
|
-
|
|
322
|
+
#### `startupMaxSize` 的作用
|
|
124
323
|
|
|
125
|
-
|
|
126
|
-
- **小程序**: 支持采集页面首屏渲染耗时 (`firstRender`)、路由切换耗时 (`route`) 及启动耗时 (`appLaunch`)。
|
|
324
|
+
启动阶段(`startupDelayMs` 窗口内)日志量通常很大(性能指标、资源加载等),如果 `maxSize` 设置过小,会频繁触发队列满而打断合并:
|
|
127
325
|
|
|
128
|
-
|
|
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
|
+
```
|
|
129
340
|
|
|
130
|
-
|
|
341
|
+
### 2. 推荐配置模板
|
|
131
342
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
+
```
|
|
144
357
|
|
|
145
|
-
|
|
358
|
+
#### 首屏性能敏感(电商、活动页)
|
|
146
359
|
|
|
147
|
-
|
|
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
|
+
```
|
|
148
375
|
|
|
149
|
-
|
|
376
|
+
#### 高频交互页面(直播间、游戏)
|
|
150
377
|
|
|
151
378
|
```ts
|
|
152
379
|
clsLogger.init({
|
|
153
380
|
batch: {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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/],
|
|
157
394
|
},
|
|
158
395
|
});
|
|
159
396
|
```
|
|
160
397
|
|
|
161
|
-
###
|
|
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
|
+
**排查步骤**:
|
|
162
415
|
|
|
163
|
-
|
|
416
|
+
1. 检查 `startupDelayMs` 是否配置
|
|
417
|
+
2. 检查 `startupMaxSize` 是否足够大(建议 300-500)
|
|
418
|
+
3. 检查 `resourceTiming` 是否需要开启(这是日志量最大的来源)
|
|
164
419
|
|
|
165
|
-
|
|
420
|
+
#### 问题:日志延迟过高
|
|
166
421
|
|
|
167
|
-
|
|
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
|
+
|
|
439
|
+
## 功能说明
|
|
440
|
+
|
|
441
|
+
### 1. 批量上报机制
|
|
442
|
+
|
|
443
|
+
SDK 使用内存队列批量上报日志:
|
|
444
|
+
|
|
445
|
+
| 触发条件 | 说明 |
|
|
446
|
+
| -------- | ------------------------------------------------------- |
|
|
447
|
+
| 队列满 | 达到 `maxSize`(启动窗口内为 `startupMaxSize`)立即发送 |
|
|
448
|
+
| 定时器 | 每 `intervalMs` 毫秒发送一次 |
|
|
449
|
+
| 页面关闭 | `visibilitychange` + `pagehide` 触发 `sendBeacon` 发送 |
|
|
450
|
+
| 启动合并 | `startupDelayMs` 窗口内的日志尽量合并 |
|
|
451
|
+
| 空闲上报 | `useIdleCallback` 开启时,等待浏览器空闲后发送 |
|
|
452
|
+
|
|
453
|
+
### 2. 即时上报 vs 批量上报
|
|
454
|
+
|
|
455
|
+
| 方法 | 默认行为 | 说明 |
|
|
456
|
+
| --------- | -------- | -------------------------------------------------------- |
|
|
457
|
+
| `error()` | 即时上报 | 错误需要及时发现,可通过 `{ immediate: false }` 改为批量 |
|
|
458
|
+
| `info()` | 批量上报 | 可通过 `{ immediate: true }` 改为即时 |
|
|
459
|
+
| `warn()` | 批量上报 | 可通过 `{ immediate: true }` 改为即时 |
|
|
460
|
+
| `track()` | 批量上报 | - |
|
|
461
|
+
|
|
462
|
+
### 3. 页面关闭保障
|
|
463
|
+
|
|
464
|
+
页面关闭时(`visibilitychange` / `pagehide`),SDK 会:
|
|
465
|
+
|
|
466
|
+
1. 使用 `navigator.sendBeacon` 同步发送队列中的日志
|
|
467
|
+
2. 如果 `sendBeacon` 不可用,将日志缓存到本地存储
|
|
468
|
+
3. 下次启动时自动重试发送缓存的日志
|
|
469
|
+
|
|
470
|
+
### 4. 失败重试机制
|
|
471
|
+
|
|
472
|
+
- 上报失败后使用指数退避算法重试
|
|
473
|
+
- 多次重试仍失败,日志落盘到本地缓存
|
|
474
|
+
- 下次应用启动时自动尝试重新上报
|
|
475
|
+
- 本地缓存最多保留 200 条(可配置 `failedCacheMax`)
|
|
476
|
+
|
|
477
|
+
### 5. 自动采集内容
|
|
478
|
+
|
|
479
|
+
#### 请求监控
|
|
480
|
+
|
|
481
|
+
- **Web**: 拦截 `fetch` / `XMLHttpRequest`
|
|
482
|
+
- **小程序**: 拦截 `wx.request` / `wx.cloud.callFunction`
|
|
483
|
+
|
|
484
|
+
#### 性能监控
|
|
485
|
+
|
|
486
|
+
- **Web**: 使用 [Google web-vitals](https://github.com/GoogleChrome/web-vitals) 库实现
|
|
487
|
+
- **FCP** (First Contentful Paint): 首次内容渲染
|
|
488
|
+
- **LCP** (Largest Contentful Paint): 最大内容渲染(用户交互后自动停止)
|
|
489
|
+
- **CLS** (Cumulative Layout Shift): 累积布局偏移(5秒会话窗口算法)
|
|
490
|
+
- **INP** (Interaction to Next Paint): 交互到绘制延迟(替代 FID)
|
|
491
|
+
- **TTFB** (Time to First Byte): 首字节时间
|
|
492
|
+
- **资源加载耗时**: PerformanceResourceTiming
|
|
493
|
+
- 自动处理 BFCache 恢复时的指标重置
|
|
494
|
+
- 上报数据包含 `rating` 字段:`'good'` | `'needs-improvement'` | `'poor'`
|
|
495
|
+
- **小程序**: 首屏渲染、路由切换、启动耗时
|
|
496
|
+
|
|
497
|
+
#### 错误监控
|
|
498
|
+
|
|
499
|
+
- **Web**: `window.onerror`, `unhandledrejection`, 资源加载错误
|
|
500
|
+
- **小程序**: `wx.onError`, `wx.onUnhandledRejection`, `App.onError`
|
|
501
|
+
|
|
502
|
+
#### 行为埋点
|
|
503
|
+
|
|
504
|
+
- **PV**: 页面访问
|
|
505
|
+
- **UV**: 用户访问(自动生成持久化 ID)
|
|
506
|
+
- **点击**: 带 `data-track-id` 属性的元素点击
|
|
507
|
+
|
|
508
|
+
## 手动注入 SDK
|
|
509
|
+
|
|
510
|
+
在某些特殊构建环境下,可以手动注入 SDK:
|
|
168
511
|
|
|
169
512
|
```ts
|
|
170
513
|
import { clsLogger } from '@be-link/cls-logger/mini';
|
|
@@ -172,6 +515,25 @@ import * as MiniSdk from 'tencentcloud-cls-sdk-js-mini';
|
|
|
172
515
|
|
|
173
516
|
clsLogger.init({
|
|
174
517
|
tencentCloud: { topicID: 'xxx', endpoint: 'xxx' },
|
|
175
|
-
sdk: MiniSdk,
|
|
518
|
+
sdk: MiniSdk,
|
|
176
519
|
});
|
|
177
520
|
```
|
|
521
|
+
|
|
522
|
+
## 类型定义
|
|
523
|
+
|
|
524
|
+
```ts
|
|
525
|
+
import type {
|
|
526
|
+
ClsLoggerInitOptions,
|
|
527
|
+
BatchOptions,
|
|
528
|
+
ReportOptions,
|
|
529
|
+
RequestMonitorOptions,
|
|
530
|
+
ErrorMonitorOptions,
|
|
531
|
+
PerformanceMonitorOptions,
|
|
532
|
+
BehaviorMonitorOptions,
|
|
533
|
+
DeviceInfoOptions,
|
|
534
|
+
} from '@be-link/cls-logger';
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## License
|
|
538
|
+
|
|
539
|
+
MIT
|
package/dist/ClsLoggerCore.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClsLoggerInitOptions, ErrorMonitorOptions, EnvType, FlatFields, PerformanceMonitorOptions, PutOptions, QueueItem, ReportLog, RequestMonitorOptions, BehaviorMonitorOptions, DeviceInfoOptions } from './types';
|
|
1
|
+
import type { ClsLoggerInitOptions, ErrorMonitorOptions, EnvType, FlatFields, PerformanceMonitorOptions, PutOptions, QueueItem, ReportLog, ReportOptions, RequestMonitorOptions, BehaviorMonitorOptions, DeviceInfoOptions } from './types';
|
|
2
2
|
import type { ClsSdkModule } from './clsSdkTypes';
|
|
3
3
|
/**
|
|
4
4
|
* CLS Logger 核心基类
|
|
@@ -38,6 +38,11 @@ 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;
|
|
42
|
+
protected useIdleCallback: boolean;
|
|
43
|
+
protected idleTimeout: number;
|
|
44
|
+
protected pendingIdleCallback: number | null;
|
|
45
|
+
protected visibilityCleanup: (() => void) | null;
|
|
41
46
|
protected failedCacheKey: string;
|
|
42
47
|
protected failedCacheMax: number;
|
|
43
48
|
protected requestMonitorStarted: boolean;
|
|
@@ -75,8 +80,24 @@ export declare abstract class ClsLoggerCore {
|
|
|
75
80
|
* 子类可按需重写(默认检测 wx)
|
|
76
81
|
*/
|
|
77
82
|
protected detectEnvType(): EnvType;
|
|
78
|
-
init(options: ClsLoggerInitOptions):
|
|
83
|
+
init(options: ClsLoggerInitOptions): Promise<boolean>;
|
|
79
84
|
private getBaseFields;
|
|
85
|
+
/**
|
|
86
|
+
* 设置页面可见性监听
|
|
87
|
+
* - visibilitychange: 页面隐藏时使用 sendBeacon 发送队列
|
|
88
|
+
* - pagehide: 作为移动端 fallback
|
|
89
|
+
*/
|
|
90
|
+
private setupVisibilityListener;
|
|
91
|
+
/**
|
|
92
|
+
* 同步发送内存队列(使用 sendBeacon)
|
|
93
|
+
* - 用于页面关闭时确保数据发送
|
|
94
|
+
* - sendBeacon 不可用时降级为缓存到 localStorage
|
|
95
|
+
*/
|
|
96
|
+
private flushBatchSync;
|
|
97
|
+
/**
|
|
98
|
+
* 构建 sendBeacon 的 payload
|
|
99
|
+
*/
|
|
100
|
+
private buildSendBeaconPayload;
|
|
80
101
|
private startRequestMonitor;
|
|
81
102
|
private startErrorMonitor;
|
|
82
103
|
private startPerformanceMonitor;
|
|
@@ -121,10 +142,21 @@ export declare abstract class ClsLoggerCore {
|
|
|
121
142
|
* 参考《一、概述》:统一上报入口(内存队列 + 批量发送)
|
|
122
143
|
*/
|
|
123
144
|
report(log: ReportLog): void;
|
|
145
|
+
/**
|
|
146
|
+
* 调度批量发送
|
|
147
|
+
* - 先使用 setTimeout 保证最小延迟(desiredDelay)
|
|
148
|
+
* - 若开启 useIdleCallback,在延迟结束后等待浏览器空闲再执行
|
|
149
|
+
*/
|
|
150
|
+
private scheduleFlush;
|
|
151
|
+
/**
|
|
152
|
+
* 取消已调度的批量发送
|
|
153
|
+
* - 同时清理 setTimeout 和可能的 requestIdleCallback
|
|
154
|
+
*/
|
|
155
|
+
private cancelScheduledFlush;
|
|
124
156
|
private getDesiredBatchFlushDueAt;
|
|
125
|
-
info(message: string | Error, data?: FlatFields): void;
|
|
126
|
-
warn(message: string | Error, data?: FlatFields): void;
|
|
127
|
-
error(message: string | Error, data?: FlatFields): void;
|
|
157
|
+
info(message: string | Error, data?: FlatFields, options?: ReportOptions): void;
|
|
158
|
+
warn(message: string | Error, data?: FlatFields, options?: ReportOptions): void;
|
|
159
|
+
error(message: string | Error, data?: FlatFields, options?: ReportOptions): void;
|
|
128
160
|
track(trackType: string, data?: FlatFields): void;
|
|
129
161
|
/**
|
|
130
162
|
* 立即发送内存队列
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClsLoggerCore.d.ts","sourceRoot":"","sources":["../src/ClsLoggerCore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,OAAO,EACP,UAAU,EACV,yBAAyB,EACzB,UAAU,EACV,SAAS,EACT,SAAS,EACT,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAWjB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAYlD;;;;;GAKG;AACH,8BAAsB,aAAa;IACjC,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAQ;IAC1C,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAAQ;IAC1D,SAAS,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAAQ;IAC7C,SAAS,CAAC,iBAAiB,EAAE,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAQ;IAC9E,SAAS,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,CAAQ;IAC9F,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI,CAAQ;IAC9G,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAA0C;IAC1E,SAAS,CAAC,QAAQ,SAA2C;IAC7D,SAAS,CAAC,UAAU,SAAK;IACzB,SAAS,CAAC,MAAM,SAAe;IAC/B,SAAS,CAAC,OAAO,UAAQ;IAEzB,SAAS,CAAC,SAAS,SAAM;IACzB,SAAS,CAAC,WAAW,SAAM;IAC3B,SAAS,CAAC,KAAK,SAAM;IACrB,SAAS,CAAC,UAAU,SAAM;IAC1B,SAAS,CAAC,OAAO,EAAE,OAAO,CAAa;IACvC,SAAS,CAAC,sBAAsB,EAAE,CAAC,MAAM,UAAU,CAAC,GAAG,IAAI,CAAQ;IACnE,SAAS,CAAC,sBAAsB,EAAE,CAAC,MAAM,UAAU,CAAC,GAAG,IAAI,CAAQ;IACnE,SAAS,CAAC,UAAU,SAAiB;IACrC,SAAS,CAAC,SAAS,SAAM;IAGzB,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE,CAAM;IACxC,SAAS,CAAC,YAAY,SAAM;IAC5B,SAAS,CAAC,eAAe,SAAO;IAChC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAQ;IAClE,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChD,SAAS,CAAC,MAAM,EAAE,MAAM,CAAK;IAC7B,SAAS,CAAC,cAAc,EAAE,MAAM,CAAK;
|
|
1
|
+
{"version":3,"file":"ClsLoggerCore.d.ts","sourceRoot":"","sources":["../src/ClsLoggerCore.ts"],"names":[],"mappings":"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"}
|