@pluve/logger-sdk 0.0.8 → 0.0.9
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.html +681 -0
- package/README.md +130 -192
- package/package.json +1 -1
- package/dist/cjs/logger-sdk.mermaid +0 -84
- package/dist/cjs/logger-sdk.svg +0 -1
- package/dist/esm/logger-sdk.mermaid +0 -84
- package/dist/esm/logger-sdk.svg +0 -1
package/README.md
CHANGED
|
@@ -1,208 +1,146 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Logger SDK v2 说明文档
|
|
2
2
|
|
|
3
3
|
## 概览
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
5
|
+
- 跨环境支持:浏览器与微信小程序
|
|
6
|
+
- 采集与采样:开关、日志等级白名单、分级/来源/路径采样率
|
|
7
|
+
- 传输适配:Beacon、像素图 Image、微信 `wx.request`
|
|
8
|
+
- 批量与队列:批量阈值与定时器、队列持久化(localforage)
|
|
9
|
+
- 重试策略:可配置最大次数与指数退避
|
|
10
|
+
- 压缩能力:可选 gzip 压缩,优先使用浏览器 CompressionStream,回退 fflate.gzipSync
|
|
9
11
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
- 安装:`yarn add @pluve/logger-sdk`
|
|
13
|
-
- ESM:`import { LoggerSDK } from '@pluve/logger-sdk'`
|
|
14
|
-
- UMD:构建后全局为 `LoggerSDK`
|
|
15
|
-
|
|
16
|
-
## 快速开始(单例 + init)
|
|
12
|
+
## 快速开始
|
|
17
13
|
|
|
18
14
|
```ts
|
|
19
|
-
import { LoggerSDK } from '
|
|
15
|
+
import { LoggerSDK } from './core/loggerSDK';
|
|
20
16
|
|
|
21
17
|
const sdk = LoggerSDK.getInstance();
|
|
18
|
+
|
|
22
19
|
sdk.init({
|
|
23
|
-
endpoint: '/
|
|
24
|
-
appId: '
|
|
25
|
-
env: '
|
|
20
|
+
// endpoint: 'https://logger.yfpharmacy.com/log', // 实际使用以 config 中 API 为准
|
|
21
|
+
appId: 'fe-vue-pc-seed-frontend',
|
|
22
|
+
env: 'develop',
|
|
23
|
+
logStage: 'develop',
|
|
26
24
|
debug: true,
|
|
27
|
-
//
|
|
25
|
+
// 采集与性能
|
|
26
|
+
enableGzip: true,
|
|
27
|
+
enableBatch: true,
|
|
28
|
+
batchSize: 10,
|
|
29
|
+
batchInterval: 15000,
|
|
30
|
+
maxPixelUrlLen: 8192,
|
|
31
|
+
// 重试
|
|
32
|
+
enableRetry: true,
|
|
33
|
+
maxRetries: 3,
|
|
34
|
+
retryDelay: 1000,
|
|
35
|
+
retryBackoff: true,
|
|
36
|
+
// 身份与鉴权
|
|
37
|
+
userId: 'u-001',
|
|
38
|
+
storeCode: 's-001',
|
|
39
|
+
token: '<token>',
|
|
40
|
+
// 采样率(可选)
|
|
41
|
+
sampleRate: 1,
|
|
28
42
|
});
|
|
29
43
|
|
|
30
|
-
//
|
|
31
|
-
sdk.identify('user_123');
|
|
32
|
-
sdk.setStoreCode('STORE_001');
|
|
33
|
-
|
|
34
|
-
// 记录错误(推荐传入 Error,提高定位能力)
|
|
35
|
-
await sdk.track({
|
|
36
|
-
message: 'TypeError: Cannot read property',
|
|
37
|
-
error: new Error('TypeError: Cannot read property'),
|
|
38
|
-
traceId: 'trace-abc-123', // 可选
|
|
39
|
-
logLevel: 'error', // 可选,默认 'info'
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// 记录普通信息
|
|
43
|
-
await sdk.track({
|
|
44
|
-
message: 'User clicked submit',
|
|
45
|
-
logLevel: 'info',
|
|
46
|
-
});
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## 事件数据结构(实际实现)
|
|
50
|
-
|
|
51
|
-
```ts
|
|
52
|
-
{
|
|
53
|
-
// 唯一日志标识:由 appId + UUID + 时间戳组成(非纯 v4)
|
|
54
|
-
logId: "web-shop24f8d7ef-1ed4-41fc-8aa8-c1c01cfa5b291767079629320",
|
|
55
|
-
traceId: "trace-123456", // 可选
|
|
56
|
-
appId: "web-shop",
|
|
57
|
-
stage: "prod", // prod/stage/dev
|
|
58
|
-
level: "error", // info/warn/error/fatal
|
|
59
|
-
message: "TypeError: ...",
|
|
60
|
-
stack: "...", // 可选
|
|
61
|
-
url: "https://...", // 当前页面
|
|
62
|
-
userId: "123", // 可选(建议脱敏)
|
|
63
|
-
frontendId: "session_xxx", // init 时锁定的会话标识(同 sessionId)
|
|
64
|
-
tags: { // 环境标签(init 时收集)
|
|
65
|
-
platform: "browser",
|
|
66
|
-
browser: "Chrome",
|
|
67
|
-
os: "macOS",
|
|
68
|
-
screenWidth: 1920,
|
|
69
|
-
screenHeight: 1080,
|
|
70
|
-
language: "zh-CN"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## API 与行为
|
|
76
|
-
|
|
77
|
-
### 单例与初始化
|
|
78
|
-
|
|
79
|
-
- `LoggerSDK.getInstance(): LoggerSDK` 获取全局唯一实例
|
|
80
|
-
- `init(options: SDKOptions)` 初始化、锁定 `sessionId`、收集环境标签
|
|
81
|
-
- `new LoggerSDK(options?: SDKOptions)` 构造时传入 options 会自动 init
|
|
82
|
-
|
|
83
|
-
### SDKOptions(实际默认值)
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
interface SDKOptions {
|
|
87
|
-
endpoint: string; // 必填
|
|
88
|
-
appId: string; // 必填
|
|
89
|
-
env?: 'prod' | 'stage' | 'dev'; // 默认 'dev'
|
|
90
|
-
debug?: boolean; // 默认 false
|
|
91
|
-
pixelParam?: string; // 默认 'data'
|
|
92
|
-
maxPixelUrlLen?: number; // 默认 4096
|
|
93
|
-
enableGzip?: boolean; // 默认 true(传输适配器内部处理)
|
|
94
|
-
enableBatch?: boolean; // 默认 false(需显式开启)
|
|
95
|
-
batchSize?: number; // 默认 10
|
|
96
|
-
batchInterval?: number; // 默认 5000 ms
|
|
97
|
-
maxQueueSize?: number; // 默认 100
|
|
98
|
-
enableStorage?: boolean; // 默认 true(队列持久化)
|
|
99
|
-
storagePrefix?: string; // 默认 'logger_sdk'
|
|
100
|
-
enableRetry?: boolean; // 默认 true
|
|
101
|
-
maxRetries?: number; // 默认 3
|
|
102
|
-
retryDelay?: number; // 默认 1000 ms
|
|
103
|
-
retryBackoff?: boolean; // 默认 true(指数退避 + 0-30% 抖动,上限 30s)
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### 事件上报
|
|
108
|
-
|
|
109
|
-
- `track(options: TrackOptions)`
|
|
110
|
-
- `message: string`(必填)
|
|
111
|
-
- `error?: Error`(推荐在错误场景传入)
|
|
112
|
-
- `traceId?: string`
|
|
113
|
-
- `logLevel?: 'info' | 'warn' | 'error' | 'fatal'`(默认 'info')
|
|
114
|
-
- `logId` 由 `appId + UUID + now()` 组成,保证唯一
|
|
115
|
-
- `identify(userId: string)` 设置用户标识(自动随事件上报)
|
|
116
|
-
- `setStoreCode(storeCode: string)` 设置店铺编码(自动随事件上报)
|
|
117
|
-
- `flush()` 在批量开启时立即上报队列内容
|
|
118
|
-
- `destroy()` 停止定时器与重试,刷新队列,清理单例并重置会话锁定
|
|
119
|
-
|
|
120
|
-
### 自动采集
|
|
121
|
-
|
|
122
|
-
- 浏览器:visibilitychange/pagehide/beforeunload 触发 `flush()`,确保卸载时尽量发送
|
|
123
|
-
- 微信小程序:建议在 App 生命周期中调用(SDK 内部识别环境)
|
|
124
|
-
|
|
125
|
-
## 传输适配器
|
|
126
|
-
|
|
127
|
-
- 默认选择:
|
|
128
|
-
- 小程序:`wx.request`
|
|
129
|
-
- 浏览器:`navigator.sendBeacon` → 降级到 Image 像素
|
|
130
|
-
- Content-Type:
|
|
131
|
-
- Beacon:`application/json`;启用 gzip 时为 `application/json; charset=utf-8`
|
|
132
|
-
- 小程序:`application/json`;启用 gzip 时为 `application/json; charset=utf-8`
|
|
133
|
-
- Image:通过 query 拼接,受 URL 长度限制(默认 4096)
|
|
134
|
-
|
|
135
|
-
## 重试策略(实际实现)
|
|
136
|
-
|
|
137
|
-
- 启用时对单事件与批量发送采用统一重试
|
|
138
|
-
- 指数退避:`baseDelay * (2 ** (attempt - 1))`
|
|
139
|
-
- 抖动:`delay * [0, 0.3]`,最大不超过 30000ms
|
|
140
|
-
- 防重复:同一 taskId 重试中会拒绝重复执行
|
|
141
|
-
|
|
142
|
-
## 场景示例
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
// 错误监控(浏览器)
|
|
146
|
-
window.addEventListener('error', (event) => {
|
|
147
|
-
sdk.track({
|
|
148
|
-
message: event.message,
|
|
149
|
-
error: event.error,
|
|
150
|
-
logLevel: 'error',
|
|
151
|
-
traceId: `err-${Date.now()}`,
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Promise 未捕获
|
|
156
|
-
window.addEventListener('unhandledrejection', (event) => {
|
|
157
|
-
sdk.track({
|
|
158
|
-
message: 'Unhandled Promise Rejection',
|
|
159
|
-
error: new Error(String(event.reason)),
|
|
160
|
-
logLevel: 'error',
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// 页面浏览
|
|
44
|
+
// 业务日志
|
|
165
45
|
sdk.track({
|
|
166
|
-
message:
|
|
167
|
-
|
|
168
|
-
|
|
46
|
+
message: '用户点击了购买按钮',
|
|
47
|
+
traceId: 'trace-xyz',
|
|
48
|
+
logLevel: 'INFO',
|
|
169
49
|
});
|
|
50
|
+
|
|
51
|
+
// 动态设置
|
|
52
|
+
sdk.identify('u-002');
|
|
53
|
+
sdk.setStoreCode('s-002');
|
|
54
|
+
sdk.setStage('testing');
|
|
170
55
|
```
|
|
171
56
|
|
|
172
|
-
##
|
|
173
|
-
|
|
174
|
-
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
57
|
+
## 配置项(节选)
|
|
58
|
+
|
|
59
|
+
- enableGzip:是否启用 gzip 压缩(默认 true)
|
|
60
|
+
- enableBatch:是否启用批量上报(默认需显式开启)
|
|
61
|
+
- batchSize:批量阈值(默认 10)
|
|
62
|
+
- batchInterval:批量定时器间隔(默认 15000ms)
|
|
63
|
+
- maxPixelUrlLen:像素图 URL 最大长度(默认 8192)
|
|
64
|
+
- enableStorage:队列持久化开关(默认 true)
|
|
65
|
+
- enableRetry/maxRetries/retryDelay/retryBackoff:重试相关配置
|
|
66
|
+
- sampleRate/levelSampleRate/sourceSampleRate/pathSampleRate:采样配置
|
|
67
|
+
|
|
68
|
+
详细定义参考类型文件:[sdkOptions.ts](src/pages/logger-sdk-tester/logger-sdk-v2/types/sdkOptions.ts).
|
|
69
|
+
|
|
70
|
+
## 压缩实现
|
|
71
|
+
|
|
72
|
+
- gzipCompress(data)
|
|
73
|
+
- 浏览器支持 CompressionStream 时,流式 gzip 压缩,再转 Base64 字符串
|
|
74
|
+
- 不支持时,回退到 fflate.gzipSync(默认压缩级别),转 Base64
|
|
75
|
+
- 返回值为 Base64 字符串,适用于传输(像素图 URL/JSON 体)
|
|
76
|
+
- 代码参考:[compression.ts](src/pages/logger-sdk-tester/logger-sdk-v2/compress/compression.ts).
|
|
77
|
+
- 备注:当前默认压缩级别,无级别可调参数暴露;如需级别控制可在 fflate 路径引入配置。
|
|
78
|
+
|
|
79
|
+
## 传输适配
|
|
80
|
+
|
|
81
|
+
- TransportAdapter 根据环境选择传输器:
|
|
82
|
+
- 微信:WechatTransport(wx.request POST,支持 gzip)
|
|
83
|
+
- 浏览器:优先 BeaconTransport(sendBeacon Blob),否则 PixelImageTransport(Image GET)
|
|
84
|
+
- WechatTransport
|
|
85
|
+
- 请求体字符串化 safeStringify
|
|
86
|
+
- enableGzip 时使用 gzipCompress 生成 Base64,Content-Type 设为 `application/json; charset=utf-8`
|
|
87
|
+
- PixelImageTransport
|
|
88
|
+
- 字符串化 items,enableGzip 时压缩为 Base64,URL 参数附带 `gzip=1`
|
|
89
|
+
- 构造像素上报 URL(含 appId、appStage、items、cacheBuster)
|
|
90
|
+
- URL 超长打印警告
|
|
91
|
+
- BeaconTransport
|
|
92
|
+
- 使用 Blob 指定 Content-Type,通过 `navigator.sendBeacon` 发送
|
|
93
|
+
|
|
94
|
+
代码参考:
|
|
95
|
+
|
|
96
|
+
- 适配器选择:[transportAdapter.ts](src/pages/logger-sdk-tester/logger-sdk-v2/transport/transportAdapter.ts)
|
|
97
|
+
- WeChat:[wechatTransport.ts](src/pages/logger-sdk-tester/logger-sdk-v2/transport/wechatTransport.ts)
|
|
98
|
+
- Pixel Image:[pixelImageTransport.ts](src/pages/logger-sdk-tester/logger-sdk-v2/transport/pixelImageTransport.ts)
|
|
99
|
+
- Beacon:[beaconTransport.ts](src/pages/logger-sdk-tester/logger-sdk-v2/transport/beaconTransport.ts)
|
|
100
|
+
|
|
101
|
+
## 批量与队列
|
|
102
|
+
|
|
103
|
+
- 启用批量后,事件入队,当队列大小达到 batchSize 或定时器触发时 flush
|
|
104
|
+
- flush:按 appId|stage 分组与分块(最多 200/块),批量发送成功后出队
|
|
105
|
+
- 队列持久化:localforage 存储,页面刷新/卸载可恢复
|
|
106
|
+
- 页面事件触发 flush:visibilitychange(hidden)、pagehide、beforeunload
|
|
107
|
+
- 代码参考:
|
|
108
|
+
- [queueManager.ts](src/pages/logger-sdk-tester/logger-sdk-v2/core/queueManager.ts)
|
|
109
|
+
- [loggerSDK.ts(flush/sendBatch)](src/pages/logger-sdk-tester/logger-sdk-v2/core/loggerSDK.ts#L452-L485)
|
|
110
|
+
|
|
111
|
+
## 重试策略
|
|
112
|
+
|
|
113
|
+
- 单个事件 sendEvent 与批量 sendBatch 均支持 executeWithRetry
|
|
114
|
+
- 可配置最大次数、基础延迟、指数退避
|
|
115
|
+
- 代码参考:[retryManager.ts](src/pages/logger-sdk-tester/logger-sdk-v2/core/retryManager.ts)
|
|
116
|
+
|
|
117
|
+
## 采样与开关
|
|
118
|
+
|
|
119
|
+
- 后端注册返回:
|
|
120
|
+
- collectSwitch:采集开关(0 关闭)
|
|
121
|
+
- collectLogLevel:采集日志等级白名单
|
|
122
|
+
- samplingRate:全局采样率
|
|
123
|
+
- 前端 shouldSend:
|
|
124
|
+
- 综合 level/source/path/global 采样率
|
|
125
|
+
- 基于 seed 哈希概率决定是否发送
|
|
126
|
+
- 参考:
|
|
127
|
+
- [loggerSDK.ts(shouldSend)](src/pages/logger-sdk-tester/logger-sdk-v2/core/loggerSDK.ts#L348-L411)
|
|
128
|
+
- [api.ts](src/pages/logger-sdk-tester/logger-sdk-v2/types/api.ts)
|
|
129
|
+
|
|
130
|
+
## 数据格式
|
|
131
|
+
|
|
132
|
+
- LogEvent:标准化日志格式(logId/seq/appId/stage/level/traceId/frontendId/url/location/message/throwable/userId/storeCode/tags)
|
|
133
|
+
- 类型参考:[logEvent.ts](src/pages/logger-sdk-tester/logger-sdk-v2/types/logEvent.ts)
|
|
134
|
+
- ReportData:上报批次(appId/appStage/items[])
|
|
135
|
+
|
|
136
|
+
## 限制与注意
|
|
137
|
+
|
|
138
|
+
- Beacon:浏览器与网络环境兼容性依赖,失败仅打印不抛出
|
|
139
|
+
- 像素图:URL 长度受限;压缩可显著降低长度但 Base64 会比二进制略增
|
|
140
|
+
- 压缩:CompressionStream 不提供压缩级别参数;fflate 同步压缩适合小批量数据
|
|
141
|
+
- 安全:不要在日志中包含敏感数据(token、密码、隐私信息等)
|
|
142
|
+
|
|
143
|
+
## 流程图
|
|
144
|
+
|
|
145
|
+
- 完整 Mermaid 流程图见文件:
|
|
146
|
+
- [logger-sdk.mermaid](src/pages/logger-sdk-tester/logger-sdk-v2/logger-sdk.mermaid)
|
package/package.json
CHANGED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
flowchart TD
|
|
2
|
-
A[初始化 SDK] --> B[设置选项(批量/重试/gzip/自动采集)]
|
|
3
|
-
B --> C{启用批量?}
|
|
4
|
-
C -->|是| D[创建队列管理器并加载存储]
|
|
5
|
-
C -->|否| E[跳过队列管理器]
|
|
6
|
-
B --> F{启用重试?}
|
|
7
|
-
F -->|是| G[创建重试管理器]
|
|
8
|
-
F -->|否| H[跳过重试管理器]
|
|
9
|
-
B --> I[选择传输适配器]
|
|
10
|
-
I --> J{运行环境}
|
|
11
|
-
J -->|微信小程序| K[WechatTransport]
|
|
12
|
-
J -->|浏览器| L{支持 Beacon?}
|
|
13
|
-
L -->|是| M[BeaconTransport]
|
|
14
|
-
L -->|否| N[PixelImageTransport]
|
|
15
|
-
B --> O[生成会话ID]
|
|
16
|
-
B --> P[收集环境标签]
|
|
17
|
-
B --> Q[注册 SDK]
|
|
18
|
-
Q --> R[接收初始化数据: 开关/等级/采样率]
|
|
19
|
-
R --> S{启用批量?}
|
|
20
|
-
S -->|是| T[启动批量定时器]
|
|
21
|
-
R --> U[挂载卸载/可见性事件处理]
|
|
22
|
-
U --> V{enableAutoCapture?}
|
|
23
|
-
V -->|是| V1[按 autoCapture: 注册 js/promise/resource/wechat]
|
|
24
|
-
V -->|否| V2[跳过自动采集]
|
|
25
|
-
|
|
26
|
-
subgraph 采集与上报
|
|
27
|
-
W[调用 track 或自动采集] --> X{已初始化且未关闭?}
|
|
28
|
-
X -->|否| X1[跳过]
|
|
29
|
-
X -->|是| X2{3秒去重窗口?}
|
|
30
|
-
X2 -->|重复| X3[跳过]
|
|
31
|
-
X2 -->|非重复| Y{shouldSend 采样?}
|
|
32
|
-
Y -->|否| Y1[采样丢弃]
|
|
33
|
-
Y -->|是| Z[构建 LogEvent]
|
|
34
|
-
Z --> AA{启用批量?}
|
|
35
|
-
AA -->|是| AB[enqueue 入队]
|
|
36
|
-
AB --> AC{队列达到批量阈值?}
|
|
37
|
-
AC -->|是| AD[flush 刷新]
|
|
38
|
-
AC -->|否| AE[等待定时器/下一次触发]
|
|
39
|
-
AA -->|否| AF[sendEvent 直接发送]
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
subgraph 批量刷新
|
|
43
|
-
AD --> AG[peek 读取待发事件]
|
|
44
|
-
AG --> AH[sendBatch 批量发送]
|
|
45
|
-
AH --> AI[按 appId & stage 分组并分块]
|
|
46
|
-
AI --> AJ[transporter.send(并发收集)]
|
|
47
|
-
AJ --> AK[dequeue 成功后出队]
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
subgraph 传输细节
|
|
51
|
-
K --> K1[字符串化; 启用 gzip 时压缩成 Base64; wx.request POST]
|
|
52
|
-
M --> M1{启用 gzip? 且满足批量条件}
|
|
53
|
-
M1 -->|是| M2[压缩 items 为 Base64 字符串; 替换 body 为 「...payload, items: Base64」; 设置 Content-Type]
|
|
54
|
-
M1 -->|否| M3[直接 JSON body; Blob 包裹; sendBeacon POST]
|
|
55
|
-
N --> N1[字符串化 items; gzip: Base64 / btoa / encodeURIComponent 回退; Image GET]
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
subgraph 压缩流程
|
|
59
|
-
C1[gzipCompress(data)] --> C2{支持 CompressionStream?}
|
|
60
|
-
C2 -->|是| C3[CompressionStream('gzip') 流式压缩后 Base64]
|
|
61
|
-
C2 -->|否| C4[fflate.gzipSync + Base64.fromUint8Array]
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
subgraph 定时与卸载
|
|
65
|
-
T --> T1[setInterval 周期性 flush]
|
|
66
|
-
U --> U1[visibilitychange/pagehide/beforeunload 触发 flush]
|
|
67
|
-
V1 --> U2[销毁时统一 off(js/promise/resource/wechat)]
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
subgraph 重试策略
|
|
71
|
-
AF --> R1{启用重试?}
|
|
72
|
-
R1 -->|是| R2[executeWithRetry(event.logId, sendFn)]
|
|
73
|
-
R1 -->|否| R3[直接 sendFn]
|
|
74
|
-
AH --> R4{启用重试?}
|
|
75
|
-
R4 -->|是| R5[executeWithRetry(batchId, sendFn)]
|
|
76
|
-
R4 -->|否| R6[直接 sendFn]
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
subgraph 存储兼容
|
|
80
|
-
D --> D1{环境}
|
|
81
|
-
D1 -->|浏览器| D2[动态 import localforage 使用 IndexedDB; 失败回退 localStorage]
|
|
82
|
-
D2 --> D2a[如解析失败: 回退 globalThis.localforage]
|
|
83
|
-
D1 -->|微信小程序| D3[使用 wx.storage 同步 API]
|
|
84
|
-
end
|