@blueking/open-telemetry 0.0.22 → 0.0.24

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 (44) hide show
  1. package/README.md +256 -70
  2. package/dist/bk-rum.global.js +2 -2
  3. package/dist/bk-rum.global.js.map +1 -1
  4. package/dist/core/config.d.ts +4 -2
  5. package/dist/core/processor.d.ts +2 -2
  6. package/dist/core/runtime-context.d.ts +4 -0
  7. package/dist/core/sampling.d.ts +0 -1
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +395 -477
  10. package/dist/index.js.map +1 -1
  11. package/dist/plugins/blank-screen.d.ts +1 -1
  12. package/dist/plugins/common.d.ts +3 -4
  13. package/dist/plugins/web-vitals.d.ts +0 -5
  14. package/dist/schema/attributes.d.ts +6 -8
  15. package/dist/schema/span.d.ts +24 -15
  16. package/package.json +1 -1
  17. package/skills/bk-rum-otele/SKILL.md +26 -23
  18. package/skills/bk-rum-otele/references/actions.md +166 -0
  19. package/skills/bk-rum-otele/references/api.md +248 -215
  20. package/skills/bk-rum-otele/references/architecture.md +139 -37
  21. package/skills/bk-rum-otele/references/blank-screen.md +190 -0
  22. package/skills/bk-rum-otele/references/capabilities.md +175 -83
  23. package/skills/bk-rum-otele/references/configuration.md +226 -151
  24. package/skills/bk-rum-otele/references/data-model.md +156 -24
  25. package/skills/bk-rum-otele/references/errors-security.md +168 -0
  26. package/skills/bk-rum-otele/references/extensions.md +236 -0
  27. package/skills/bk-rum-otele/references/framework-integration.md +318 -75
  28. package/skills/bk-rum-otele/references/getting-started.md +186 -70
  29. package/skills/bk-rum-otele/references/network.md +258 -0
  30. package/skills/bk-rum-otele/references/performance.md +197 -0
  31. package/skills/bk-rum-otele/references/privacy.md +236 -67
  32. package/skills/bk-rum-otele/references/production.md +264 -0
  33. package/skills/bk-rum-otele/references/session-context.md +185 -0
  34. package/skills/bk-rum-otele/references/telemetry-reference.md +479 -51
  35. package/skills/bk-rum-otele/references/transport-sampling.md +318 -32
  36. package/skills/bk-rum-otele/references/troubleshooting.md +341 -151
  37. package/skills/bk-rum-otele/references/views-routing.md +211 -0
  38. package/skills/bk-rum-otele/references/concepts.md +0 -60
  39. package/skills/bk-rum-otele/references/custom-plugin.md +0 -170
  40. package/skills/bk-rum-otele/references/plugins-basic.md +0 -135
  41. package/skills/bk-rum-otele/references/plugins-error-security.md +0 -83
  42. package/skills/bk-rum-otele/references/plugins-experience.md +0 -124
  43. package/skills/bk-rum-otele/references/plugins-network.md +0 -32
  44. package/skills/bk-rum-otele/references/plugins.md +0 -62
@@ -2,245 +2,435 @@
2
2
 
3
3
  # 调试与排障
4
4
 
5
- 本页按接入阶段常见问题组织。
5
+ 排障建议从“有没有创建有效 Session/View”开始,再看 Span 过滤、批处理和网络出口。只盯 `/v1/rum` 请求很容易把采样、Consent 或关联问题误判成 Collector 故障。
6
6
 
7
- ## 本地看不到数据
7
+ ## 最小诊断配置
8
8
 
9
- 先打开 debug,并使用 simple span processor。
9
+ 在测试环境临时使用:
10
10
 
11
11
  ```ts
12
- new BkOpenTelemetry({
12
+ const rum = new BkOpenTelemetry({
13
13
  application: { name: 'rum-debug' },
14
- debug: true,
15
- session: {
16
- sampleRate: 1,
17
- },
18
14
  transport: {
19
- endpoint: 'http://localhost:4318',
15
+ endpoint: 'https://rum.example.com',
20
16
  processor: 'simple',
21
17
  },
18
+ session: { sampleRate: 1 },
19
+ debug: true,
20
+ autoStart: false,
22
21
  });
22
+
23
+ await rum.start();
23
24
  ```
24
25
 
25
- 检查点:
26
+ 这个配置的目的:
27
+
28
+ - 采样率 1 排除“Session 未命中”;
29
+ - simple 排除 5 秒批量等待;
30
+ - `debug: true` 在 exporter 前打印 Span,也显示插件初始化和部分丢弃警告;
31
+ - 显式 `await start()` 让启动错误可以被捕获。
26
32
 
27
- - Collector 是否监听 `4318`。
28
- - 浏览器 Network 中是否有 `/v1/rum` 请求。
29
- - 是否被采样丢弃。
30
- - `enabled` 是否为 `false`。
33
+ 生产问题确认后应恢复 batch,避免逐 Span 请求。
31
34
 
32
- ## 手动事件没有上报
35
+ ## 分层定位流程
33
36
 
34
- `reportAction()` 和 `reportCustomEvent()` 受采样控制。未采样时会静默丢弃。
37
+ ### 1. 确认实例和配置
35
38
 
36
39
  ```ts
37
- new BkOpenTelemetry({
38
- application: { name: 'rum-debug' },
39
- debug: true,
40
- session: {
41
- sampleRate: 1,
42
- },
43
- transport: { endpoint: 'https://rum-collector.example.com' },
44
- });
40
+ console.log(rum.config.application);
41
+ console.log(rum.config.transport.endpoint); // 应以 /v1/rum 结尾
45
42
  ```
46
43
 
47
- ## 自定义插件注册失败
44
+ 检查:
48
45
 
49
- `use()` 必须在 `start()` 前调用。如果需要注册插件,关闭自动启动。
46
+ - `application.name` 非空;
47
+ - `transport.endpoint` 非空且没有把 `/v1/rum` 手工写两次;
48
+ - 页面只创建了一个实例;
49
+ - 没有 `enabled: false`;
50
+ - 当前实例没有已经 `shutdown()`。
51
+
52
+ ### 2. 确认 Consent 与启动
50
53
 
51
54
  ```ts
52
- const bkOT = new BkOpenTelemetry({
53
- application: { name: 'rum-debug' },
54
- autoStart: false,
55
- transport: { endpoint: 'https://rum-collector.example.com' },
56
- });
55
+ console.log(rum.config.trackingConsent);
56
+ await rum.start();
57
+ ```
57
58
 
58
- bkOT.use(myPlugin);
59
+ `not-granted` 不会安装采集插件。授权后必须调用:
59
60
 
60
- await bkOT.start();
61
+ ```ts
62
+ await rum.setTrackingConsent('granted');
61
63
  ```
62
64
 
63
- ## 空白屏误报
65
+ 如果使用 `autoStart: true`,构造后立刻调用 `use()` 会抛错;扩展注册请改为 `autoStart: false`。自动启动没有单独暴露 ready Promise,构造后立即同步调用手动事件也不会排队,可能因为 View 尚未建立而被过滤。必须保证首个手动事件不丢时,应使用 `autoStart: false` 并显式 `await rum.start()`。
64
66
 
65
- SPA 应用应配置 `rootSelector` 和 loading/skeleton 忽略选择器。
67
+ ### 3. 确认 Session/View/采样
66
68
 
67
69
  ```ts
68
- new BkOpenTelemetry({
69
- application: { name: 'rum-debug' },
70
- transport: { endpoint: 'https://rum-collector.example.com' },
71
- tracking: {
72
- blankScreen: {
73
- rootSelector: '#app',
74
- ignoreSelectors: ['.bk-loading', '.skeleton'],
75
- checkDelay: 5000,
76
- },
77
- },
70
+ console.table(rum.getRuntimeAttributes());
71
+ console.log({
72
+ sampled: rum.isSampled(),
73
+ session: rum.isSessionActive(),
74
+ view: rum.isViewActive(),
78
75
  });
79
76
  ```
80
77
 
81
- ## 接口 span 太多
78
+ 普通 Span 导出的必要条件:
79
+
80
+ - `isSampled() === true`;
81
+ - 有 `session.id`;
82
+ - 有 `view.id`。
82
83
 
83
- 先确认是否有多个 SDK 实例重复初始化,尤其是微前端场景。其次用 `excludedUrls` 排除探活或高频无价值请求。
84
+ `browser.session` 是唯一可以没有 `view.id` 的内置 Span。
85
+
86
+ manual View 模式下,必须在 Session 建立后调用 `startView()`:
84
87
 
85
88
  ```ts
86
- new BkOpenTelemetry({
87
- application: { name: 'rum-debug' },
88
- transport: { endpoint: 'https://rum-collector.example.com' },
89
- tracking: {
90
- request: {
91
- excludedUrls: [/\/health(?:\?|$)/, /\/polling\//],
92
- },
93
- },
94
- });
89
+ await rum.start();
90
+ rum.startView({ name: '首页' });
95
91
  ```
96
92
 
97
- ## URL 或用户信息泄露风险
93
+ ### 4. 确认 Span 到达 exporter
98
94
 
99
- 配置 URL 和属性脱敏。
95
+ `debug: true` 会打印:
100
96
 
101
- ```ts
102
- new BkOpenTelemetry({
103
- application: { name: 'rum-debug' },
104
- transport: { endpoint: 'https://rum-collector.example.com' },
105
- privacy: {
106
- redactUrl: url => url.replace(/([?&]token=)[^&]+/g, '$1***'),
107
- redactAttributes: attributes => {
108
- const next = { ...attributes };
109
- delete next['user.email'];
110
- return next;
111
- },
112
- },
113
- });
97
+ ```text
98
+ [bk-ot][rum] [...ReadableSpan]
114
99
  ```
115
100
 
116
- ## Long Task 没有数据
101
+ 如果能看到 Span、看不到网络请求,重点检查 exporter、并发、页面退出和浏览器拦截。如果完全看不到 Span,重点检查 capability 开关、浏览器 API 支持、Session/View/采样和 beforeSend。
102
+
103
+ ### 5. 确认网络和 Collector
104
+
105
+ Network 面板过滤 `v1/rum`,检查:
106
+
107
+ - URL、POST、请求体和 `Content-Type`;
108
+ - OPTIONS 预检;
109
+ - `Authorization` 和自定义 header;
110
+ - response status;
111
+ - Console 中 CORS、Mixed Content、CSP、ad blocker 错误;
112
+ - 响应是否真的是 2xx,而非页面网关返回的 30x/HTML。
117
113
 
118
- Long Task API 并非所有浏览器都支持。Firefox 不支持时插件会跳过。
114
+ ## 完全没有 `/v1/rum` 请求
115
+
116
+ 常见原因与证据:
117
+
118
+ | 原因 | 怎么确认 | 处理 |
119
+ | --- | --- | --- |
120
+ | batch 正在等待 | 调用 `await rum.flush()` | 联调临时 simple;生产保留 batch |
121
+ | 未命中采样 | `rum.isSampled() === false` | 测试环境设 `sampleRate: 1` |
122
+ | 未授权 | `rum.config.trackingConsent` | 授权后调用 `setTrackingConsent('granted')` |
123
+ | 没有 View | `rum.isViewActive() === false` | manual 模式调用 `startView()`;检查 View 插件 |
124
+ | SDK 未启动 | 显式 `await rum.start()` | 捕获启动异常 |
125
+ | 全部被 Hook 丢弃 | 暂时移除两个 beforeSend | 修正返回条件 |
126
+ | 页面没有产生结束 Span | 手动 `reportCustomEvent()` 后 flush | 再定位具体插件 |
127
+ | endpoint 被浏览器阻止 | Console/Network | 修复 HTTPS、CSP、CORS、扩展拦截 |
128
+
129
+ 最小探针:
119
130
 
120
131
  ```ts
121
- new BkOpenTelemetry({
122
- application: { name: 'rum-debug' },
123
- transport: { endpoint: 'https://rum-collector.example.com' },
124
- tracking: {
125
- longTask: {
126
- threshold: 50,
127
- },
128
- },
129
- });
132
+ rum.reportCustomEvent({ name: 'rum_probe' });
133
+ await rum.flush();
130
134
  ```
131
135
 
132
- ## HTTP Body 没有数据
136
+ 若 `isSampled/session/view` 都为 true,探针仍无 exporter 日志,检查 `tracking.beforeSend` 是否返回 false。
137
+
138
+ ## 有 debug Span,但请求失败
139
+
140
+ ### CORS
133
141
 
134
- 这是预期行为:SDK 不读取或上报请求/响应 Body。
142
+ 典型表现:OPTIONS 失败、`TypeError: Failed to fetch`、响应在 DevTools 中不可读。
135
143
 
136
- ## WebSocket 采集异常
144
+ Collector 需要允许页面 origin、POST/OPTIONS 和实际 header。使用 token 时必须允许 `authorization`;自定义 header 也要列入 allow headers。
137
145
 
138
- WebSocket 插件会 Proxy 全局 `WebSocket`。如果应用或第三方库也 patch 了 WebSocket,应避免重复 patch。
146
+ ### URL 错误
147
+
148
+ SDK固定追加 `/v1/rum`。如果配置:
139
149
 
140
150
  ```ts
141
- new BkOpenTelemetry({
142
- application: { name: 'rum-debug' },
143
- transport: { endpoint: 'https://rum-collector.example.com' },
144
- tracking: {
145
- websocket: true,
146
- },
147
- });
151
+ endpoint: 'https://rum.example.com/v1/rum'
152
+ ```
153
+
154
+ 最终是:
155
+
156
+ ```text
157
+ https://rum.example.com/v1/rum/v1/rum
148
158
  ```
149
159
 
150
- # FAQ
160
+ 应传上报根地址。
151
161
 
152
- ## SDK 会采集哪些数据?
162
+ ### 401/403
153
163
 
154
- 默认采集页面访问与稳定耗时、用户动作、资源加载、fetch/xhr、JavaScript 错误、Web Vitals、空白屏、设备信息和会话信息。HTTP body、Long Task、CSP、WebSocket 默认关闭。
164
+ 检查:
165
+
166
+ - token 是否过期、是否误含 `Bearer ` 前缀;SDK 会自行添加;
167
+ - `headers.Authorization` 是否覆盖了 token 生成的 header;
168
+ - Collector 是否允许浏览器凭证和当前应用/租户;
169
+ - 预检是否允许 Authorization。
170
+
171
+ ### 404/405
172
+
173
+ Collector 没有暴露 SDK 约定的 `/v1/rum` POST,或网关路径重写不一致。不要把它改成 `/v1/traces` 除非网关明确把 `/v1/rum` 转发到对应处理器。
174
+
175
+ ### 413
176
+
177
+ 批量 body 超过网关限制。降低 `maxExportBatchSize`,并确认 Collector body limit。队列大小影响内存与丢弃,不直接限定单个 body 字节数。
178
+
179
+ ### 429/502/503/504
180
+
181
+ 当前 exporter 会在总体 `timeoutMillis` 内重试,支持 `Retry-After`。持续失败时:
182
+
183
+ - 修复 Collector 容量或限流;
184
+ - 适当降低采样率;
185
+ - 避免同时开启高成本/高事件量能力;
186
+ - 不要仅无限增大客户端 queue 和 timeout。
187
+
188
+ ## 手动事件不上报
189
+
190
+ 按以下顺序完整排查,不要只检查事件 payload。
191
+
192
+ ### 1. 启动与 Consent
155
193
 
156
194
  ```ts
157
- new BkOpenTelemetry({
158
- application: { name: 'demo' },
159
- transport: { endpoint: 'https://rum-collector.example.com' },
160
- tracking: {
161
- action: true,
162
- longTask: true,
163
- websocket: true,
164
- },
195
+ console.log({
196
+ enabled: rum.config.enabled,
197
+ consent: rum.config.trackingConsent,
165
198
  });
166
199
  ```
167
200
 
168
- ## `user.id` 会被 SDK 脱敏吗?
201
+ - `enabled` 必须为 true;
202
+ - Consent 必须为 `granted`;
203
+ - 实例不能已经 shutdown;
204
+ - 默认 autoStart 是异步的,手动事件不会在启动完成前排队。需要确定时序时改用:
169
205
 
170
- 不会。`user.id` 由接入方提供,SDK 原样透传。如果业务要求 hash,需要在传入前处理。
206
+ ```ts
207
+ const rum = new BkOpenTelemetry({
208
+ application: { name: 'rum-debug' },
209
+ transport: { endpoint: 'https://rum.example.com' },
210
+ autoStart: false,
211
+ });
212
+
213
+ await rum.start();
214
+ ```
215
+
216
+ ### 2. Session、采样和 View
171
217
 
172
218
  ```ts
173
- new BkOpenTelemetry({
174
- application: { name: 'demo' },
175
- transport: { endpoint: 'https://rum-collector.example.com' },
176
- context: {
177
- user: {
178
- id: hashUserId(rawUserId),
179
- },
180
- },
219
+ console.log({
220
+ sampled: rum.isSampled(),
221
+ session: rum.isSessionActive(),
222
+ view: rum.isViewActive(),
181
223
  });
182
224
  ```
183
225
 
184
- ## `session.sampleRate` 是 trace 级采样吗?
226
+ 三者对普通手动事件都应为 true。`reportAction()` 和 `reportCustomEvent()` 未采样时直接返回;manual View 未建立时,即使创建 Span 也会在过滤层因缺少 `view.id` 被丢弃。manual 模式应在 `await rum.start()` 后调用一次当前路由的 `startView()`。
227
+
228
+ ### 3. Payload 和 Hook
185
229
 
186
- 不是。它是会话级确定性采样,同一会话内保持一致。
230
+ - `name` 类型必须是 string,并建议使用非空、低基数枚举;
231
+ - 当前运行时不拒绝空字符串:`reportCustomEvent({ name: '' })` 会尝试生成名为 `custom.` 的 Span,`reportAction({ name: '' })` 会生成空的 `action.name`,都不会仅因空 name 抛错或丢弃,但数据不可用,不应依赖该行为;
232
+ - attributes 只能使用合法 OTel Attribute 类型;
233
+ - `context.attributes.page/custom` 与 `privacy.redactAttributes` 不应抛错;
234
+ - `tracking.beforeSend` 不能按 name 返回 false;Custom Event 不经过请求级 `request.beforeSend`。
235
+
236
+ ### 4. 强制结束 batch 并观察 exporter
187
237
 
188
238
  ```ts
189
- new BkOpenTelemetry({
190
- application: { name: 'demo' },
191
- transport: { endpoint: 'https://rum-collector.example.com' },
192
- session: {
193
- sampleRate: 0.2,
194
- },
195
- });
239
+ rum.reportCustomEvent({ name: 'rum_probe' });
240
+ await rum.flush();
196
241
  ```
197
242
 
198
- ## 为什么不使用 OpenTelemetry userInteraction instrumentation?
243
+ 临时启用 `debug: true` 并使用 `transport.processor: 'simple'`。若控制台存在 `[bk-ot][rum]` Span 而 Network 没有成功请求,事件创建和过滤已经通过,应转查 exporter/CORS;若没有 debug Span,继续检查前述上下文和 Hook。
244
+
245
+ ### 5. 网络与 Collector
246
+
247
+ - URL 是 `<endpoint>/v1/rum`,未重复追加路径;
248
+ - OPTIONS/POST、Content-Type、鉴权和自定义 Header 的 CORS 正确;
249
+ - 返回 2xx,而不是 30x、HTML 错误页或可重试失败;
250
+ - 没有 Mixed Content、CSP、广告拦截器、超时或并发队列问题。
251
+
252
+ 如果探针成功、业务事件失败,再比较两者的 name、attributes 和业务 Hook 分支;如果探针也失败,按本页开头的分层流程继续检查通用出口。
253
+
254
+ ## Fetch/XHR 没有 Span
255
+
256
+ 1. `tracking.request !== false`;
257
+ 2. URL 没命中 `excludedUrls`;
258
+ 3. `request.beforeSend` 没返回 false;
259
+ 4. 请求是 SDK 启动之后发生;
260
+ 5. 页面没有第二个实例/第三方库反复覆盖 `fetch` 或 XHR prototype;
261
+ 6. SDK 自身 `/v1/rum` 请求会被有意排除;
262
+ 7. Span 有 Session/View 并命中采样。
263
+
264
+ `resource.*` 网络阶段缺失不代表请求 Span 丢失。跨域没有 `Timing-Allow-Origin`、浏览器清理 buffer、匹配等待超过 200ms 都可能只保留基础 Fetch/XHR 属性。
199
265
 
200
- 官方 userInteraction instrumentation 主要用于把交互回调中的异步任务组织成 trace,但没有稳定的 RUM action 语义、动作命名、页面活动窗口和关联计数。本 SDK 统一使用 `action` 插件,避免同一次点击重复上报;内置 request 采集统一负责 Fetch/XHR 网络 trace。
266
+ ## `traceparent` 没有注入
267
+
268
+ 这是默认行为。只有 URL 明确命中 `allowedTracingUrls` 才注入,同源也不会自动注入:
201
269
 
202
270
  ```ts
203
- bkOT.reportAction({
204
- name: '确认提交',
205
- attributes: {
206
- 'biz.scene': 'strategy-create',
271
+ tracking: {
272
+ request: {
273
+ allowedTracingUrls: ['https://api.example.com/'],
207
274
  },
208
- });
275
+ }
209
276
  ```
210
277
 
211
- ## 可以只上报 traces,不上报 metrics/logs 吗?
278
+ 跨域还需要服务端 CORS 允许请求头 `traceparent`。如果预检失败,缩小白名单并修复 API 服务的 CORS;不要把所有第三方 URL 加入白名单。
279
+
280
+ ## 请求 Span 太多或 View loading 一直不结束
212
281
 
213
- SDK 固定只上报 RUM Trace,不创建 Metrics/Logs Provider,无需配置开关。
282
+ 使用两个不同的排除入口:
214
283
 
215
284
  ```ts
216
- new BkOpenTelemetry({
217
- application: { name: 'demo' },
218
- transport: { endpoint: 'https://trace-gateway.example.com' },
219
- });
285
+ tracking: {
286
+ request: {
287
+ excludedUrls: [/\/rum-noise/],
288
+ },
289
+ view: {
290
+ excludedActivityUrls: [/\/events\/stream/, /\/long-poll/],
291
+ },
292
+ }
220
293
  ```
221
294
 
222
- Endpoint 会解析为 `https://trace-gateway.example.com/v1/rum`。
295
+ - `request.excludedUrls`:完全不采集、不传播、不计活动;
296
+ - `view.excludedActivityUrls`:请求仍可采集,但不延长 View loading time。
297
+
298
+ 长轮询、SSE fetch、埋点和永不结束的流式请求通常应配置第二项。
299
+
300
+ ## 静态资源字段不完整
301
+
302
+ 常见原因:
303
+
304
+ - 浏览器不提供新字段;
305
+ - 跨域资源没有 `Timing-Allow-Origin`,大小和详细时序被限制;
306
+ - Service Worker/cache 让某些阶段为 0;
307
+ - Resource Timing buffer 已满;
308
+ - 条目时间顺序异常,SDK 会省略无效阶段而不是上报负值。
309
+
310
+ 先判断 `browser.resource` 是否存在,再判断单个可选字段,不要把“字段缺失”当成“插件未工作”。
311
+
312
+ ## Web Vitals 缺失或值不同
313
+
314
+ - 指标依赖浏览器支持和页面生命周期,不保证每个 View 都有五项;
315
+ - LCP/CLS 等在隐藏或 View 结束时定稿;
316
+ - INP 需要真实 interaction;没有交互时可缺失;
317
+ - SPA 每个 View 的聚合边界由 SDK 维护,与只计算整页一次的工具可能不同;
318
+ - BFCache 会创建新的 View loading type;
319
+ - attribution 字段比核心 value 更依赖浏览器能力。
223
320
 
224
- ## 为什么不建议多个实例同时运行?
321
+ 不要用刷新后立刻查看网络来断言缺失;先触发交互、切换可见性或调用 `flush()`。
225
322
 
226
- fetch、xhr、action、websocket 等能力会监听或 patch 全局 API。多个实例可能重复采集、重复上报或互相影响。
323
+ ## Action 名称不符合预期
324
+
325
+ 默认 `nameCollection: 'explicit'`:
326
+
327
+ 1. 从点击元素和祖先读取 `data-bk-action-name`;
328
+ 2. 没有显式名称时使用元素标签名;
329
+ 3. 不读取按钮可见文字。
330
+
331
+ 推荐补 `data-bk-action-name`。只有确实接受文本隐私风险时才设置 `nameCollection: 'text'`。
332
+
333
+ 如果没有 Action:确认点击是主按钮、Action 开启、Session/View 有效,并检查页面是否有覆盖层/Shadow DOM 目标。SDK 最多向上检查 10 层父节点进行部分命名和可交互判断。
334
+
335
+ ## Rage/Dead/Error Click 不符合预期
336
+
337
+ - Rage click:1 秒内至少 3 次、位置距离不超过 100px 的点击链;报告会等待连击窗口;
338
+ - Error click:Action 生命周期内捕获到错误活动;
339
+ - Dead click:点击后没有被认为有效的请求、DOM、导航、错误等副作用,并排除输入/选择/滚动等情况;
340
+ - Action 最长默认 10 秒,页面活动安静后还需短暂确认。
341
+
342
+ 这些是启发式信号,不是业务失败结论。服务端应保留原始 frustration type,结合 View/资源/错误分析。
343
+
344
+ ## 白屏误报
345
+
346
+ 按顺序检查:
347
+
348
+ 1. `rootSelector` 是否指向实际应用根节点;
349
+ 2. 页面是否用 Canvas/WebGL/iframe 等九点 DOM 采样难以识别的渲染方式;
350
+ 3. 骨架屏/加载层是否被错误忽略;
351
+ 4. 页面布局的主要内容是否避开了九个采样点;
352
+ 5. `checkDelay` 是否覆盖真实异步渲染时间;
353
+ 6. `threshold` 是否过低。
227
354
 
228
355
  ```ts
229
- if (!window.__BK_RUM_INSTANCE__) {
230
- window.__BK_RUM_INSTANCE__ = new BkOpenTelemetry({
231
- application: { name: 'demo' },
232
- transport: {
233
- endpoint: 'https://rum-collector.example.com',
234
- },
235
- });
356
+ tracking: {
357
+ blankScreen: {
358
+ rootSelector: '#app',
359
+ checkDelay: 2000,
360
+ confirmationDelay: 300,
361
+ threshold: 0.9,
362
+ ignoreSelectors: ['.my-skeleton'],
363
+ },
236
364
  }
237
365
  ```
238
366
 
239
- ## 如何在页面离开前尽量 flush?
367
+ 根节点暂时不存在会被判断为 `missing_root` 候选。每个 View 最多上报一次,修改配置后要创建新 View 才能重新验证。
240
368
 
241
- SDK 已监听部分页面生命周期事件。业务也可以在关键流程后主动调用 `flush()`。
369
+ ## Long Task 没数据
242
370
 
243
- ```ts
244
- await saveCriticalConfig();
245
- await bkOT.flush();
371
+ - 默认关闭,需要 `tracking.longTask: true`;
372
+ - 需要 `PerformanceObserver`;
373
+ - 优先 `long-animation-frame`,否则回退 `longtask`;
374
+ - entry duration 必须达到 threshold;
375
+ - 浏览器可能只支持基础 Long Task,没有脚本归因;
376
+ - 页面后台、跨域 iframe 与浏览器实现会限制 attribution。
377
+
378
+ ## CSP 没数据
379
+
380
+ - 默认关闭,需要 `tracking.cspViolation: true`;
381
+ - SDK 只能接收页面派发的 `securitypolicyviolation` 事件;
382
+ - Collector 自身被 CSP `connect-src` 阻止时,CSP Span 也无法上报;
383
+ - Report-Only 和强制策略的浏览器行为要用真实浏览器验证;
384
+ - `original_policy` 等字段可能被 `redactAttributes` 删除。
385
+
386
+ ## WebSocket 没数据
387
+
388
+ - 默认关闭,需要 `tracking.websocket: true`;
389
+ - 只记录 connect/open/error/close 生命周期,不记录 message;
390
+ - SDK 启动前已经创建的连接无法追溯;
391
+ - 多实例或其他库重复 patch WebSocket 会造成冲突;
392
+ - 连接未关闭时,最终 close Span 需要等事件或 shutdown 逻辑,不能只看刚创建后的网络。
393
+
394
+ ## View 重复、缺失或基数过高
395
+
396
+ - query-only 变化不会新建自动 View;
397
+ - pathname 或非纯锚点 hash 变化会触发;
398
+ - Router 同时手动 `startView()` 且使用 auto 会重复;
399
+ - 微前端多个实例会重复;
400
+ - `getPathGroup` 默认仅返回 pathname,不会自动识别 `/orders/123` 动态 ID;
401
+ - `setViewName()` 是改名,不创建新 View;
402
+ - Session 续期和 BFCache 恢复会创建具有特定 loading type 的 View。
403
+
404
+ 选择 auto 或 manual 一种边界来源,并配置低基数 path group。
405
+
406
+ ## 队列丢数据
407
+
408
+ Batch queue 默认 2048。高事件量页面同时开启 Resource、Long Task、CSP、WebSocket 等能力时可能塞满。表现通常是 debug/OTel diag 中 dropped warning,而不是业务异常。
409
+
410
+ 处理优先级:
411
+
412
+ 1. 降低 `session.sampleRate`;
413
+ 2. 关闭不需要的高量能力;
414
+ 3. 排除噪声 URL/活动;
415
+ 4. 确认 Collector 性能和网络成功率;
416
+ 5. 再评估 queue/batch 大小,避免只增加浏览器内存。
417
+
418
+ ## 插件初始化失败
419
+
420
+ PluginManager 会隔离单个插件异常:失败插件不进入 started 列表,其余插件继续。设置 `debug: true` 查看:
421
+
422
+ ```text
423
+ [bk-ot] plugin "<name>" init failed
246
424
  ```
425
+
426
+ 自定义插件应在 init 失败前自行清理已经安装的部分监听;因为 init 抛错后 PluginManager 不会为该插件调用 shutdown。
427
+
428
+ ## 提交问题时应附带
429
+
430
+ - SDK 版本、浏览器版本、框架/路由模式;
431
+ - 精简后的构造配置(删除 token 和敏感字段);
432
+ - `isSampled/isSessionActive/isViewActive` 结果;
433
+ - `/v1/rum` 请求 URL、status、CORS 信息;
434
+ - debug 模式的 Span name 和关键属性,不要粘贴敏感完整 body;
435
+ - 是否多实例、微前端、Service Worker、代理或浏览器扩展;
436
+ - 最小复现步骤以及预期/实际 Span 名。