@blueking/open-telemetry 0.0.33 → 0.0.35-beta.1

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 (54) hide show
  1. package/README.md +67 -57
  2. package/dist/bk-rum.global.js +2 -2
  3. package/dist/bk-rum.global.js.map +1 -1
  4. package/dist/core/action-activity.d.ts +5 -1
  5. package/dist/core/action-target.d.ts +19 -0
  6. package/dist/core/config.d.ts +15 -5
  7. package/dist/core/event-time.d.ts +7 -0
  8. package/dist/core/performance-timing.d.ts +13 -0
  9. package/dist/core/plugin.d.ts +37 -2
  10. package/dist/core/processor.d.ts +24 -2
  11. package/dist/core/request-timing.d.ts +3 -2
  12. package/dist/core/runtime-context.d.ts +62 -2
  13. package/dist/core/sdk.d.ts +23 -1
  14. package/dist/core/session-transition.d.ts +19 -0
  15. package/dist/core/trace-context.d.ts +6 -7
  16. package/dist/core/view-location.d.ts +10 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +2955 -1483
  19. package/dist/index.js.map +1 -1
  20. package/dist/integrations/vue-router.d.ts +25 -0
  21. package/dist/plugins/action.d.ts +1 -1
  22. package/dist/plugins/blank-screen-detection.d.ts +11 -0
  23. package/dist/plugins/blank-screen.d.ts +10 -18
  24. package/dist/plugins/common.d.ts +4 -2
  25. package/dist/plugins/document-vitals.d.ts +25 -0
  26. package/dist/plugins/page-view.d.ts +1 -1
  27. package/dist/plugins/resource.d.ts +14 -1
  28. package/dist/plugins/session-state.d.ts +14 -2
  29. package/dist/plugins/session-store.d.ts +12 -0
  30. package/dist/plugins/session.d.ts +1 -0
  31. package/dist/plugins/web-vitals-metrics.d.ts +80 -0
  32. package/dist/plugins/web-vitals.d.ts +2 -59
  33. package/dist/schema/attributes.d.ts +63 -0
  34. package/dist/schema/span.d.ts +5 -2
  35. package/package.json +9 -4
  36. package/skills/bk-rum-otele/references/actions.md +54 -37
  37. package/skills/bk-rum-otele/references/api.md +72 -51
  38. package/skills/bk-rum-otele/references/architecture.md +16 -16
  39. package/skills/bk-rum-otele/references/blank-screen.md +72 -142
  40. package/skills/bk-rum-otele/references/capabilities.md +66 -60
  41. package/skills/bk-rum-otele/references/configuration.md +101 -98
  42. package/skills/bk-rum-otele/references/data-model.md +22 -17
  43. package/skills/bk-rum-otele/references/errors-security.md +13 -13
  44. package/skills/bk-rum-otele/references/extensions.md +5 -3
  45. package/skills/bk-rum-otele/references/framework-integration.md +7 -24
  46. package/skills/bk-rum-otele/references/network.md +62 -49
  47. package/skills/bk-rum-otele/references/performance.md +62 -30
  48. package/skills/bk-rum-otele/references/privacy.md +5 -5
  49. package/skills/bk-rum-otele/references/production.md +9 -13
  50. package/skills/bk-rum-otele/references/session-context.md +67 -38
  51. package/skills/bk-rum-otele/references/span-protocol.md +771 -315
  52. package/skills/bk-rum-otele/references/telemetry-reference.md +288 -213
  53. package/skills/bk-rum-otele/references/troubleshooting.md +2 -2
  54. package/skills/bk-rum-otele/references/views-routing.md +103 -27
@@ -277,7 +277,7 @@ tracking: {
277
277
 
278
278
  跨域还需要服务端 CORS 允许请求头 `traceparent`。如果预检失败,缩小白名单并修复 API 服务的 CORS;不要把所有第三方 URL 加入白名单。
279
279
 
280
- 命中白名单却依然没有注入时,看 Span Link 的 `attributes.injected`。为 `false` 说明业务已经自行设置了 trace Header,SDK 尊重既有链路而不注入,此时 `attributes.format` 告诉你是哪种格式,同组的原始 Header 也一并记在 Link Attributes 里。注意不能只看 `format`:业务自带合法 `traceparent` 时它同样是 `traceparent`,与 SDK 注入无法区分。
280
+ 命中白名单却依然没有注入时,看 Span Link 的 `attributes.injected`。为 `false` 说明业务已经自行设置了 trace Header,SDK 尊重既有链路而不注入,此时 `attributes.format` 告诉你是哪种格式,自动 Link 不再保存原始 Header。注意不能只看 `format`:业务自带合法 `traceparent` 时它同样是 `traceparent`,与 SDK 注入无法区分。
281
281
 
282
282
  ## 后端按 `traceparent` 的 trace-id 查不到 RUM Span
283
283
 
@@ -285,7 +285,7 @@ tracking: {
285
285
 
286
286
  如果 Link 的 `attributes.injected` 为 `false` 且 `attributes.format` 不是 `traceparent`,说明业务用的是 `b3` / `sw8` / Datadog 等格式。后端只解析 W3C `traceparent`,这种情况下后端不会生成 Trace,Link 里的 trace-id 自然查不到。
287
287
 
288
- `sw8` 以及 `b3: 0` 这类只有采样标记的值,SDK 解析不出合法 OTel id,会补一对**随机占位 id** 让 Link 结构保持统一。这对 id 在后端一定查不到,判断依据仍是 `attributes.format` 与其中的原始 Header。
288
+ `sw8` 以及 `b3: 0` 这类只有采样标记的值,SDK 不额外注入,也不生成 Link。缺少 Link 不能直接推断没有业务 Trace Header,应在业务请求侧检查传播格式。
289
289
 
290
290
  ## 请求 Span 太多或 View loading 一直不结束
291
291
 
@@ -6,12 +6,12 @@ View 表示一次可独立分析的页面体验。初始文档加载、SPA 路
6
6
 
7
7
  ## View 类型
8
8
 
9
- | `view.loading_type` | 创建场景 | `span_type` |
10
- | --- | --- | --- |
11
- | `initial_load` | 初始自动 View;手动模式第一次 `startView()` | `view` |
12
- | `route_change` | SPA 自动路由;手动模式后续 `startView()` | `view` |
13
- | `bf_cache` | 从 Back/Forward Cache 恢复 | `view` |
14
- | `session_renewal` | Session 过期后新 Session 接管当前页面 | `view` |
9
+ | `view.loading_type` | 创建场景 | `span_type` |
10
+ | ------------------- | ---------------------------------------------------- | ----------- |
11
+ | `initial_load` | 起点仍属于当前 Session 的首次文档 View | `view` |
12
+ | `route_change` | SPA 路由、手动划分;晚于初始 Session 的首次手动 View | `view` |
13
+ | `bf_cache` | 从 Back/Forward Cache 恢复 | `view` |
14
+ | `session_renewal` | Session 过期后新 Session 接管当前页面 | `view` |
15
15
 
16
16
  每个 View 都生成新的 `view.id`。View 的 URL、路由模板、名称和自定义属性作为运行时上下文挂到其间发生的普通 Span。
17
17
 
@@ -21,11 +21,23 @@ View 表示一次可独立分析的页面体验。初始文档加载、SPA 路
21
21
 
22
22
  - 启动时创建初始 View;
23
23
  - 观察 `history.pushState()`、`history.replaceState()`、`popstate` 和 `hashchange`;
24
- - pathname 改变时创建新 View;
25
- - 非页内锚点的 hash path 改变时创建新 View;
24
+ - 根据 `routeMode` 判断逻辑路径是否改变;
26
25
  - query-only 变化不创建 View;
27
26
  - 指向当前页面真实元素 ID 的 hash 视为页内锚点,不创建 View。
28
27
 
28
+ `tracking.view.routeMode`:
29
+
30
+ | 模式 | 页面边界与默认模板 |
31
+ | -------------- | ------------------------------------------------------------------ |
32
+ | `auto`(默认) | `#/`、`#!/` 识别为 Hash 路由,其余用 pathname 与锚点启发式 |
33
+ | `hash` | hash 内逻辑路径;忽略 hash 内 query/二级锚点,不受 DOM ID 碰撞影响 |
34
+ | `history` | pathname;fragment 不创建 View |
35
+ | `document` | 不因同文档 URL 变化创建 View;新文档仍创建 initial_load |
36
+
37
+ MPA 整页跳转、SPA 首次打开和刷新都是新文档加载;只有同文档导航才使用上述比较规则。整页 query 导航仍创建 initial_load。BFCache 恢复使用 bf_cache,不复用文档下载时间。
38
+
39
+ 同 View 的 URL 变化也会更新脱敏后的 `view.url` 和历史上下文,不改变 View ID。默认脱敏仍移除 query/hash;Hash 页面身份由逻辑路径生成的 `view.url_template` 和 `view.name` 保留,不能靠放开所有 URL 参数解决页面聚合。
40
+
29
41
  ## 手动 View 模式
30
42
 
31
43
  框架路由希望完全控制边界时:
@@ -48,13 +60,15 @@ bkOT.startView({
48
60
  });
49
61
  ```
50
62
 
51
- 必须先建立采样有效的 Session。`startView()` 在尚未启动、未授权、未采样或没有 Session 时被忽略。手动模式第一次 `startView()` 之前没有有效 View,因此普通 Span 不会导出。
63
+ `startView()` 保存最新手动路由意图;尚未启动、未授权或没有有效 Session 时不会导出,允许采集后再建立 View。已 shutdown 的实例忽略该调用。手动模式第一次 `startView()` 之前没有有效 View,因此普通 Span 不会导出。
64
+
65
+ 第一次手动 View 只有在文档起点仍属于当前 Session 时才回溯到 `performance.timeOrigin`;若此前已经跨 Session,则使用当前有效时间,避免起点与 Session 不匹配而漏报。
52
66
 
53
67
  `attributes` 会经过 `redactAttributes`,并删除 SDK 所有保留字段;业务无法通过 View attributes 覆盖 `session.*`、`view.*`、`span_type` 或 `outcome.*`。
54
68
 
55
69
  ## View 名称和路由模板
56
70
 
57
- 默认 `view.url_template` 取 URL pathname 并把数字 ID、UUID、长十六进制段折叠为 `:id`。请求和静态资源 Span 的 `url.template` 复用同一套折叠规则,但走独立的 `tracking.request.getUrlTemplate`。静态资源先通过 `redactUrl` 脱敏,再生成模板。
71
+ 默认 `view.url_template` 取当前路由模式的逻辑路径并把数字 ID、UUID、长十六进制段折叠为 `:id`。例如 `/#/orders/42` 默认得到 `/orders/:id`。请求和静态资源仍使用 URL pathname,走独立的 `tracking.request.getUrlTemplate`,不解析为 Hash 页面路由。
58
72
 
59
73
  `view.name` 是视图名称,`view.url_template` 是路由模板(如 `/orders/:id`)。SDK 优先使用 `startView({ name })` 或 `setViewName()` 设置的名称;未显式设置时,`view.name` 默认取 `view.url_template`。
60
74
 
@@ -72,6 +86,8 @@ tracking: {
72
86
 
73
87
  `getUrlTemplate()` 应返回低基数、稳定的路由模板。默认实现已经会把数字 ID、UUID 和长十六进制段替换为 `:id`,但它只能按形状猜:纯数字段无法与语义段区分,`/reports/2024/summary` 会被折成 `/reports/:id/summary`。路由规则明确的应用应显式提供模板,不要依赖猜测。
74
88
 
89
+ `startView({ urlTemplate: '/orders/:orderId' })` 可以直接使用 Router 的匹配模板,优先于 URL 推断。前序页面也保留旧 View 的显式模板。
90
+
75
91
  运行期可修改名称:
76
92
 
77
93
  ```ts
@@ -80,6 +96,18 @@ bkOT.setViewName('订单详情-只读');
80
96
 
81
97
  名称变化不会创建新 View,但会更新运行时上下文并发送 View update Span。传入与当前相同名称时不发送更新,此后的 Span 使用新名称。
82
98
 
99
+ 名称、URL 与业务属性更新从调用时刻生效;历史事件仍使用其发生时的快照。
100
+
101
+ ```ts
102
+ rum.setViewContext({ 'biz.page_kind': 'detail' }); // 替换业务 View 属性
103
+ rum.setViewContextProperty('biz.order_id', '42'); // 更新一个属性;undefined 删除
104
+ const attributes = rum.getViewContext();
105
+ rum.addTiming('content.ready'); // 调用时刻相对 View 起点的毫秒
106
+ rum.addTiming('data.ready', 240); // 显式提供相对 View 起点的毫秒,不是 epoch
107
+ ```
108
+
109
+ 业务属性经过脱敏与保留字段过滤;custom timings 同名后一次覆盖,最多 100 个名称。负数、非有限值及未来时间忽略,名称规范为字母/数字/点/下划线/短横线且最多 100 字符。
110
+
83
111
  ## URL 与前序页面
84
112
 
85
113
  - `view.url`:当前 URL,经 `privacy.redactUrl`。
@@ -94,11 +122,11 @@ bkOT.setViewName('订单详情-只读');
94
122
 
95
123
  Span 名使用 `view.name`:
96
124
 
97
- | phase | 触发 |
98
- | --- | --- |
99
- | `start` | 创建 View |
100
- | `update` | Loading Time 就绪、手动覆盖 Loading Time、名称变化 |
101
- | `end` | 新 View、pagehide、BFCache、Session 过期或 SDK shutdown |
125
+ | phase | 触发 |
126
+ | -------- | ----------------------------------------------------------------------- |
127
+ | `start` | 创建 View |
128
+ | `update` | Loading Time、名称/URL/属性/timing 更新;flush、隐藏/冻结及 60 秒检查点 |
129
+ | `end` | 新 View、pagehide、BFCache、Session 过期或 SDK shutdown |
102
130
 
103
131
  每条生命周期 Span 都是瞬时事件,并携带递增的 `view.version`。常见 `view.end_reason`:
104
132
 
@@ -111,17 +139,21 @@ Span 名使用 `view.name`:
111
139
 
112
140
  服务端应按 `view.id + view.version` 幂等合并,而不是依赖网络到达顺序。
113
141
 
142
+ 每个快照带 `view.time_spent`(包含后台的累计 ms)、`view.foreground_time`(SDK 实际观察到的前台累计 ms)、`view.is_active`。`view.page_states` 是 JSON 字符串,记录最近最多 100 个 `{ state, start }`,start 相对 View 起点为 ms,state 为 active/passive/hidden/frozen。裁剪状态明细不会清零已累计前台时长;SDK 初始化前的前台时间不凭空补算。
143
+
144
+ 检查点和 flush 不修改 Session 用户活动时间,也不强制结束 View。没有可靠 end 时,最后检查点只代表已观测时长下界。View 和 Vital 分别按各自版本覆盖,不能把多个累计快照相加。
145
+
114
146
  ## 初始导航时间
115
147
 
116
148
  初始 View 尝试从 `PerformanceNavigationTiming` 读取:
117
149
 
118
- | 字段 | 浏览器原值 | 单位 |
119
- | --- | --- | --- |
120
- | `view.first_byte` | `responseStart` | 相对 `performance.timeOrigin` 的 ms |
121
- | `view.dom_interactive` | `domInteractive` | 同上 |
122
- | `view.dom_content_loaded` | `domContentLoadedEventEnd` | 同上 |
123
- | `view.dom_complete` | `domComplete` | 同上 |
124
- | `view.load_event` | `loadEventEnd` | 同上 |
150
+ | 字段 | 浏览器原值 | 单位 |
151
+ | ------------------------- | -------------------------- | ----------------------------------- |
152
+ | `view.first_byte` | `responseStart` | 相对 `performance.timeOrigin` 的 ms |
153
+ | `view.dom_interactive` | `domInteractive` | 同上 |
154
+ | `view.dom_content_loaded` | `domContentLoadedEventEnd` | 同上 |
155
+ | `view.dom_complete` | `domComplete` | 同上 |
156
+ | `view.load_event` | `loadEventEnd` | 同上 |
125
157
 
126
158
  值必须有限且大于 0 才写入。它们是相对导航起点的时间,不是 epoch 时间戳。
127
159
 
@@ -130,7 +162,8 @@ Span 名使用 `view.name`:
130
162
  `tracking.view.loadingTime` 默认 `true`。SDK 同时等待:
131
163
 
132
164
  1. 页面活动进入稳定状态;
133
- 2. 初始加载的 `window.load` / `loadEventEnd` 可用。
165
+ 2. 初始加载的 `window.load` / `loadEventEnd` 可用;
166
+ 3. BFCache 恢复后的首帧已经渲染(双 `requestAnimationFrame`)。
134
167
 
135
168
  页面活动包括:
136
169
 
@@ -142,7 +175,8 @@ Span 名使用 `view.name`:
142
175
  页面从 View 创建后先观察 100ms:没有任何页面活动时,活动侧不提供候选值;发生过活动后,所有请求完成且连续 100ms 无新活动即认为稳定。
143
176
 
144
177
  - 初始加载:只要能取得 `loadEventEnd`,即使前 100ms 没有其他活动,也可生成 Loading Time;最终取 `loadEventEnd` 与页面活动结束耗时的较大值。
145
- - SPA/BFCache/Session Renewal:只有观察到页面活动时才生成自动 Loading Time,取 View 开始到页面活动结束的耗时。
178
+ - SPA/Session Renewal:只有观察到页面活动时才生成自动 Loading Time,取 View 开始到页面活动结束的耗时。
179
+ - BFCache:以 `pageshow` 事件时刻为起点,时间戳不可用时回退到 SDK 处理时刻;即使没有页面活动,也可使用恢复后首帧(双 `requestAnimationFrame`)的耗时作为候选值;有页面活动时,取首帧耗时与页面活动结束耗时的较大值。
146
180
  - 页面在计算期间变为 hidden:取消自动计算,不上报不可靠结果。
147
181
  - **创建 View 时页面已经是 hidden:完全不启动自动计算**,之后回到前台也不会补算。后台标签页预加载、`target=_blank` 打开的页面因此常常没有 `view.loading_time`;这类场景需要 `setViewLoadingTime()` 手动确认。
148
182
 
@@ -184,13 +218,16 @@ SDK 计算“调用时刻 - View 开始时间”,取消仍在进行的自动
184
218
 
185
219
  ## BFCache
186
220
 
187
- 页面以 `pagehide.persisted=true` 进入 BFCache 时:
221
+ 自动模式中,页面以 `pagehide.persisted=true` 进入 BFCache 时:
188
222
 
189
223
  1. 结束当前 View,`view.end_reason=bfcache`。
190
224
  2. 保存旧 View 的名称、URL 和自定义属性。
191
- 3. `pageshow.persisted=true` 时创建新的 `bf_cache` View。
225
+ 3. `pageshow.persisted=true` 时创建新的 `bf_cache` View,View 开始时间为 `pageshow` 事件时刻:由 `event.timeStamp` 回推(`Date.now() - (performance.now() - event.timeStamp)`,与 web-vitals、Datadog 一致),因此先于 SDK 执行的业务 `pageshow` 回调也计入 Loading Time;`timeStamp` 不可用时退回 SDK 处理时刻。
226
+ 4. 恢复后首帧渲染且页面活动结束后,上报带 `view.loading_time` 的 `update`。
227
+
228
+ 冻结时间不会计入旧 View 或恢复后的新 View。如果恢复时 Session 已过期,SDK 等到新 Session 建立后恢复 View,起点不得早于新 Session 的生效时间。已有待执行的恢复命令保留 `bf_cache`;由 Session 生命周期直接重建时标记 `session_renewal`。
192
229
 
193
- 冻结时间不会计入旧 View 或恢复后的新 View。如果恢复时 Session 已过期,SDK等到新 Session 建立后再创建 `session_renewal` View。
230
+ 手动模式需要业务或 Router 集成显式恢复 View。下文 `trackVueRouterViews()` 包含此处理,并避免与 Session 续期重复创建。
194
231
 
195
232
  ## 常见问题
196
233
 
@@ -211,3 +248,42 @@ SDK 计算“调用时刻 - View 开始时间”,取消仍在进行的自动
211
248
  ### View 数量过多
212
249
 
213
250
  确认是否同时使用自动模式和框架 `startView()`。手动同步路由时必须设 `tracking: 'manual'`。
251
+
252
+ ## Vue Router 标准接入
253
+
254
+ `trackVueRouterViews()` 直接接收 Vue Router 实例,不依赖或打包 Vue。Hash 和 HTML5 History 模式使用同一套逻辑路由接口:
255
+
256
+ ```ts
257
+ import { BkOpenTelemetry, trackVueRouterViews } from '@blueking/open-telemetry';
258
+ import { createRouter, createWebHashHistory } from 'vue-router';
259
+
260
+ const router = createRouter({
261
+ history: createWebHashHistory(), // History 模式可换成 createWebHistory()
262
+ routes,
263
+ });
264
+ const rum = new BkOpenTelemetry({
265
+ application: { name: 'order-web' },
266
+ autoStart: false,
267
+ transport: { endpoint: 'https://rum.example.com' },
268
+ tracking: { view: { tracking: 'manual' } },
269
+ });
270
+
271
+ await rum.start();
272
+ const stopTrackingViews = trackVueRouterViews(rum, router);
273
+ app.use(router);
274
+ app.mount('#app');
275
+
276
+ // 应用/微前端卸载时,先移除 Router 订阅,再关闭 SDK。
277
+ // stopTrackingViews();
278
+ // await rum.shutdown();
279
+ ```
280
+
281
+ - 必须配置 `tracking.view.tracking='manual'`,否则辅助函数抛出配置错误;它不会在运行时修改 SDK 配置。
282
+ - 如果 Router 已完成首次解析,立即以当前路由创建 View;否则等待首次成功的 `afterEach`。
283
+ - 取消、守卫拦截、重复等失败导航不创建 View;成功导航只在逻辑 `path` 改变时创建,query-only 和同路径页内 hash 不创建。
284
+ - 采用最深匹配记录的参数化路径作为 `view.name`、`view.url_template`,例如 `/orders/:orderId`;未匹配路由回退到默认路径模板。页面 URL 仍由 SDK 按真实地址和隐私规则处理。
285
+ - 同一 SDK 与 Router 重复注册复用同一监听和卸载函数;卸载可重复调用。不要再额外写一套 `afterEach(startView)`,否则仍会重复创建 View。
286
+ - BFCache 恢复即使没有 `afterEach` 也会重建当前匹配路由的 View,标记为 `bf_cache`;如果 Session 续期已经恢复 View,则跳过重复创建。卸载同时移除恢复监听。
287
+ - 导航提交不等于主体内容可用。业务内容完成时仍可调用 `setViewLoadingTime()` 或 `addTiming()`;query/state 本身代表新业务页面时,应改用业务自己的手动 View 集成。
288
+
289
+ 此辅助函数面向 Vue Router 的 `currentRoute.value`/`afterEach` 接口;不自动为 React Router、Nuxt 或 Vue Router 3 提供兼容分支。