@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
@@ -1,44 +1,330 @@
1
1
  <!-- 本文件由 packages/open-telemetry/scripts/gen-skill-references.mjs 从 wikis 自动生成,请勿手改。 -->
2
2
 
3
- # 传输与采样
3
+ # 上报协议、批处理与采样
4
4
 
5
- ## 单一 Endpoint
5
+ 本文描述当前源码真正使用的传输链路。SDK 只创建 Trace Provider,不创建 Metric Provider 或 Log Provider;所有 RUM 数据都编码为 Span,并从一个 OTLP/HTTP 入口上报。
6
6
 
7
- `transport.endpoint` 是必填根地址,SDK 去掉末尾斜杠后拼接 `/v1/rum`。没有 `/v1/metrics`、`/v1/logs` 或独立信号开关。
7
+ ## 最终请求
8
+
9
+ ```text
10
+ POST <transport.endpoint 去除末尾斜杠>/v1/rum
11
+ Content-Type: application/json
12
+ Authorization: Bearer <transport.token> # 配置 token 时
13
+
14
+ <OTLP ExportTraceServiceRequest JSON>
15
+ ```
16
+
17
+ 例如 `endpoint: 'https://rum.example.com/collector/'` 最终会请求:
18
+
19
+ ```text
20
+ https://rum.example.com/collector/v1/rum
21
+ ```
22
+
23
+ `endpoint` 是必填的上报根地址。SDK 不支持分别配置 trace、metric、log 地址,也不会自动追加标准 OTLP 的 `/v1/traces`。
24
+
25
+ 请求体的完整层级与字段归属见[RUM 数据模型](./data-model.md)和[遥测字段字典](./telemetry-reference.md)。
26
+
27
+ ### 实际 OTLP JSON 示例
28
+
29
+ 下面是当前 `JsonTraceSerializer` 会生成的真实编码形态。为了让单条请求可读,示例使用 `tracking.device=false`,只放一个没有 Resource Timing 增强字段的成功 Fetch Span;ID 和时间值是示例值,但字段名、枚举数字、Attribute Value 包装和数据类型与当前依赖一致:
30
+
31
+ ```json
32
+ {
33
+ "resourceSpans": [
34
+ {
35
+ "resource": {
36
+ "attributes": [
37
+ { "key": "deployment.environment.name", "value": { "stringValue": "production" } },
38
+ { "key": "service.name", "value": { "stringValue": "order-center" } },
39
+ { "key": "session.sample_rate", "value": { "intValue": 1 } },
40
+ { "key": "telemetry.sdk.language", "value": { "stringValue": "webjs" } },
41
+ { "key": "telemetry.sdk.name", "value": { "stringValue": "@blueking/open-telemetry" } },
42
+ { "key": "telemetry.sdk.version", "value": { "stringValue": "0.0.22" } }
43
+ ],
44
+ "droppedAttributesCount": 0
45
+ },
46
+ "scopeSpans": [
47
+ {
48
+ "scope": { "name": "bk-rum" },
49
+ "spans": [
50
+ {
51
+ "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
52
+ "spanId": "00f067aa0ba902b7",
53
+ "name": "browser.resource",
54
+ "kind": 3,
55
+ "startTimeUnixNano": "1784592000123000000",
56
+ "endTimeUnixNano": "1784592000248000000",
57
+ "attributes": [
58
+ { "key": "session.id", "value": { "stringValue": "session-01" } },
59
+ { "key": "session.start_time", "value": { "intValue": 1784592000000 } },
60
+ { "key": "session.type", "value": { "stringValue": "user" } },
61
+ { "key": "session.has_replay", "value": { "boolValue": false } },
62
+ { "key": "view.id", "value": { "stringValue": "view-01" } },
63
+ { "key": "view.name", "value": { "stringValue": "/orders/:id" } },
64
+ { "key": "view.url", "value": { "stringValue": "https://app.example.com/orders/123" } },
65
+ { "key": "view.url_path_group", "value": { "stringValue": "/orders/:id" } },
66
+ { "key": "view.loading_type", "value": { "stringValue": "initial_load" } },
67
+ { "key": "span_type", "value": { "stringValue": "resource" } },
68
+ { "key": "outcome.type", "value": { "stringValue": "success" } },
69
+ { "key": "resource.type", "value": { "stringValue": "fetch" } },
70
+ { "key": "http.request.method", "value": { "stringValue": "GET" } },
71
+ { "key": "http.response.status_code", "value": { "intValue": 200 } },
72
+ { "key": "url.full", "value": { "stringValue": "https://api.example.com/orders/123" } },
73
+ { "key": "server.address", "value": { "stringValue": "api.example.com" } }
74
+ ],
75
+ "droppedAttributesCount": 0,
76
+ "events": [],
77
+ "droppedEventsCount": 0,
78
+ "status": { "code": 0 },
79
+ "links": [],
80
+ "droppedLinksCount": 0,
81
+ "flags": 257
82
+ }
83
+ ]
84
+ }
85
+ ]
86
+ }
87
+ ]
88
+ }
89
+ ```
90
+
91
+ Wire 编码注意点:
92
+
93
+ - `kind=3` 是 OTLP 的 `SPAN_KIND_CLIENT`;INTERNAL 为 `1`;
94
+ - Status `code=0` 是 UNSET,ERROR 为 `2`;
95
+ - `startTimeUnixNano`、`endTimeUnixNano` 和 Event `timeUnixNano` 编码为十进制字符串;
96
+ - Attribute 不是普通扁平对象,而是 `{ key, value }` 数组;value 使用 `stringValue`、`intValue`、`doubleValue`、`boolValue` 或 `arrayValue`;
97
+ - `traceId` 是 32 位十六进制字符串,`spanId` / `parentSpanId` 是 16 位;没有父 Span 时省略 `parentSpanId`;
98
+ - `events` 中的 exception/Long Task Event 也使用同样的 Attribute Value 包装;
99
+ - `flags=257` 是当前 transformer 写出的“本地 sampled Span 且携带 isRemote 有效位”组合值,不要把它当作业务字段;
100
+ - 数组顺序和 Attribute 顺序不应作为 Collector 契约,Collector 应按 key 读取。
101
+
102
+ 发生 Fetch 网络异常时,同一 Span 的 `events` 会采用以下实际形态,并把 `status.code` 设为 `2`:
103
+
104
+ ```json
105
+ {
106
+ "events": [
107
+ {
108
+ "attributes": [
109
+ { "key": "exception.type", "value": { "stringValue": "TypeError" } },
110
+ { "key": "exception.message", "value": { "stringValue": "Failed to fetch" } },
111
+ { "key": "exception.stacktrace", "value": { "stringValue": "TypeError: Failed to fetch\n at ..." } }
112
+ ],
113
+ "name": "exception",
114
+ "timeUnixNano": "1784592000248000000",
115
+ "droppedAttributesCount": 0
116
+ }
117
+ ],
118
+ "status": { "code": 2 }
119
+ }
120
+ ```
121
+
122
+ 这是 Span 内对应字段的片段,不是独立请求体;exception 字段是否齐全取决于浏览器实际 Error。
123
+
124
+ ## 请求格式
125
+
126
+ 当前使用 `@opentelemetry/exporter-trace-otlp-http@0.217.0` 的浏览器 JSON exporter:
127
+
128
+ | 项目 | 当前行为 |
129
+ | --- | --- |
130
+ | HTTP 方法 | `POST` |
131
+ | 编码 | OTLP/HTTP JSON |
132
+ | Content-Type | `application/json` |
133
+ | 压缩 | 不压缩 |
134
+ | 浏览器 API | `fetch` |
135
+ | 成功响应 | HTTP `200`–`299`;响应 Body 不解析 |
136
+ | 默认单次导出超时 | `10000ms` |
137
+ | 默认并发导出上限 | `30` |
138
+
139
+ Collector 至少需要:
140
+
141
+ 1. 接受浏览器发出的 OTLP JSON Trace 请求;
142
+ 2. 暴露 SDK 约定的 `/v1/rum` 路径;
143
+ 3. 跨域时正确处理 CORS 和预检请求;
144
+ 4. 返回 2xx 表示整批接收成功;
145
+ 5. 如需限流恢复,返回受支持的重试状态和可选 `Retry-After`。
146
+
147
+ 当前浏览器 transport 只判断 HTTP status,不读取成功或失败响应 Body。2xx 可以返回空 Body;即使返回 OTLP `partialSuccess` JSON,SDK 也不会解析或打印其中的 rejected span 数量。部分拒绝必须由 Collector 自身监控,不能依赖浏览器 SDK 感知。
148
+
149
+ ## 鉴权与自定义请求头
150
+
151
+ ```ts
152
+ transport: {
153
+ endpoint: 'https://rum.example.com',
154
+ token: 'report-token',
155
+ headers: {
156
+ 'X-Tenant-ID': 'tenant-a',
157
+ },
158
+ }
159
+ ```
160
+
161
+ `token` 会生成默认请求头:
162
+
163
+ ```text
164
+ Authorization: Bearer report-token
165
+ ```
166
+
167
+ `headers` 在合并时优先级更高,因此可以显式覆盖 `Authorization`:
168
+
169
+ ```ts
170
+ transport: {
171
+ endpoint: 'https://rum.example.com',
172
+ token: 'will-be-overridden',
173
+ headers: {
174
+ Authorization: 'Custom credential',
175
+ },
176
+ }
177
+ ```
178
+
179
+ 不要把长期有效、权限过大的后台密钥写入浏览器。浏览器内的 token 和 header 对访问页面的用户可见,应使用受限的上报凭证,并在服务端限制来源、租户和权限。
180
+
181
+ ## 批处理器
182
+
183
+ 默认 `processor: 'batch'`。结束的 Span 先进入内存队列,满足批量大小、调度延迟,或调用 `flush()` 时导出。
184
+
185
+ | 配置 | 默认值 | 作用 |
186
+ | --- | ---: | --- |
187
+ | `transport.batch.maxQueueSize` | `2048` | 内存中最多排队的已结束 Span;满后新 Span 被丢弃 |
188
+ | `transport.batch.maxExportBatchSize` | `512` | 一次 export 最多取出的 Span 数 |
189
+ | `transport.batch.scheduledDelayMillis` | `5000` | 未达到批量大小时的最长调度等待 |
190
+ | `transport.batch.exportTimeoutMillis` | `30000` | BatchSpanProcessor 等待一次 export 完成的上限 |
191
+
192
+ 约束与行为:
193
+
194
+ - `maxExportBatchSize` 大于 `maxQueueSize` 时,OpenTelemetry 会把它降为 `maxQueueSize`;
195
+ - 队列已满时,新结束的 Span 会直接丢弃,不会落盘;
196
+ - 上表是当前 `@opentelemetry/sdk-trace-base@2.7.1` 默认值;浏览器构建通常没有 Node 环境变量,但依赖本身也识别 `OTEL_BSP_*`;
197
+ - `exportTimeoutMillis` 是批处理器等待出口的上限,`transport.timeoutMillis` 是 exporter 请求及重试总期限,两者不是同一个配置。
198
+
199
+ 生产环境通常保留 batch:
8
200
 
9
201
  ```ts
10
- new BkOpenTelemetry({
11
- application: { name: 'demo' },
12
- transport: {
13
- endpoint: 'https://collector.example.com',
14
- token: 'report-token',
15
- processor: 'batch',
16
- batch: {
17
- maxQueueSize: 2048,
18
- maxExportBatchSize: 512,
19
- scheduledDelayMillis: 5000,
20
- exportTimeoutMillis: 30000,
21
- },
22
- timeoutMillis: 10_000,
23
- concurrencyLimit: 10,
202
+ transport: {
203
+ endpoint: 'https://rum.example.com',
204
+ processor: 'batch',
205
+ timeoutMillis: 10_000,
206
+ batch: {
207
+ maxQueueSize: 2048,
208
+ maxExportBatchSize: 512,
209
+ scheduledDelayMillis: 5000,
210
+ exportTimeoutMillis: 30_000,
24
211
  },
25
- });
212
+ }
213
+ ```
214
+
215
+ ## SimpleSpanProcessor
216
+
217
+ `processor: 'simple'` 会在每个 Span 结束后立即触发 export,不经过批量队列:
218
+
219
+ ```ts
220
+ transport: {
221
+ endpoint: 'https://rum.example.com',
222
+ processor: 'simple',
223
+ }
224
+ ```
225
+
226
+ 它适合本地验证时观察请求,不建议作为高流量页面的默认生产配置。`transport.batch` 在 simple 模式下不会生效。
227
+
228
+ ## 超时、并发与重试
229
+
230
+ ```ts
231
+ transport: {
232
+ endpoint: 'https://rum.example.com',
233
+ timeoutMillis: 15_000,
234
+ concurrencyLimit: 10,
235
+ }
26
236
  ```
27
237
 
28
- `token` 生成默认 `Authorization: Bearer <token>`,显式 `headers` 可覆盖它。SDK 在 `pagehide` 和页面进入 hidden 时触发 flush。
238
+ 当前 exporter 的默认值和重试规则如下:
239
+
240
+ | 项目 | 当前行为 |
241
+ | --- | --- |
242
+ | `timeoutMillis` | 默认 `10000ms`,且必须是大于 0 的有限数值 |
243
+ | `concurrencyLimit` | 默认 `30` 个待处理 export Promise |
244
+ | 可重试 HTTP 状态 | `429`、`502`、`503`、`504` |
245
+ | 可重试网络错误 | 浏览器 Fetch 的部分 `TypeError` 网络错误 |
246
+ | 最大重试次数 | 初次请求后最多再尝试 5 次,但不能超过总体超时期限 |
247
+ | 退避 | 初始 1 秒、倍率 1.5、上限 5 秒、±20% jitter |
248
+ | `Retry-After` | 支持秒数或 HTTP 日期;优先于本地退避 |
249
+
250
+ 其余 4xx/5xx 是不可重试失败。即使状态码可重试,如果预计等待时间超过本次 export 剩余期限,也不会继续重试。
251
+
252
+ 这些数值来自当前锁定的 OpenTelemetry exporter,并不是服务端协议字段。升级依赖时需要重新核对本文。
253
+
254
+ ## 页面退出与 keepalive
255
+
256
+ SDK 在以下时机主动调用 `flush()`:
257
+
258
+ - `document.visibilityState` 变为 `hidden`;
259
+ - `window.pagehide`;
260
+ - 业务显式调用 `flush()`;
261
+ - 撤销 Consent 时,停止插件后 flush;
262
+ - `shutdown()` 时,停止插件并导出剩余 Span。
29
263
 
30
- ## Session 级确定性采样
264
+ 浏览器 exporter 在待发送 `keepalive` 请求累计 body 不超过约 60 KiB,且当前少于 9 个 `keepalive` 请求时使用 `fetch(..., { keepalive: true })`;超过限制时仍会发送请求,但关闭 `keepalive`。因此页面退出时的发送是“尽力而为”,不是持久队列或交付保证。
265
+
266
+ 不要把 `flush()` 理解为服务端已经持久化:它只等待 SDK 的插件和 Trace Provider 完成导出调用;浏览器终止、网络中断、CORS 拒绝或服务端失败仍可能造成丢失。
267
+
268
+ ## Session 采样
31
269
 
32
270
  ```ts
33
- new BkOpenTelemetry({
34
- application: { name: 'demo' },
35
- transport: { endpoint: 'https://collector.example.com' },
36
- session: { sampleRate: 0.05 },
37
- });
38
- ```
39
-
40
- - `1` 表示全量,`0` 表示全部丢弃。
41
- - 采样由 `application.name + session.id` 的稳定 hash 决定。
42
- - Session 轮换后使用新 ID 重新计算。
43
- - `session.sample_rate` 写入 Resource,供后端做采样率修正。
44
- - 未采样 Session 不创建可导出的 RUM Span。
271
+ session: {
272
+ sampleRate: 0.2,
273
+ }
274
+ ```
275
+
276
+ `sampleRate`:
277
+
278
+ - 范围是 `0`–`1`,默认 `1`;
279
+ - 非有限数值回退为 `1`,小于 0 截为 0,大于 1 截为 1;
280
+ - 以 `application.name + session.id` 计算稳定 hash;
281
+ - 同一 Session 内的所有 SDK RUM Span 使用相同采样决定;
282
+ - Session 轮换后会重新计算;
283
+ - 采样率作为 Resource 属性 `session.sample_rate` 一并上报。
284
+
285
+ 未命中采样时:
286
+
287
+ - `startSpan()` 返回 non-recording Span;
288
+ - `reportAction()`、`reportCustomEvent()`、手动 View 控制不会产生可导出数据;
289
+ - SDK 仍需运行 Session 生命周期逻辑以建立稳定的采样边界;
290
+ - 不会先创建完整 Span 再在网络层抽样。
291
+
292
+ 排查“手动事件没有上报”时,先暂时设置 `sampleRate: 1`。
293
+
294
+ ## 导出前过滤
295
+
296
+ 一个已结束 Span 还需要通过 `FilteringSpanProcessor` 才会进入 simple/batch processor。以下数据会被丢弃:
297
+
298
+ - 没有命中当前 Session 采样;
299
+ - 没有关联有效 Session;
300
+ - 除 `browser.session` 外,没有关联有效 View;
301
+ - 命中 SDK 自身的 `/v1/rum` 上报地址;
302
+ - 被内部插件标记为丢弃;
303
+ - 被全局 `tracking.beforeSend` 返回 `false` 拒绝。
304
+
305
+ 过滤层会在 Span 创建时补齐缺失的运行时和页面属性;Span 结束时执行上述过滤,并在交给 exporter 前移除仅供内部使用的采样标记。详细顺序见[架构与数据流](./architecture.md)。
306
+
307
+ ## CORS 基线
308
+
309
+ 跨域 Collector 至少需要允许:
310
+
311
+ ```text
312
+ Access-Control-Allow-Origin: https://your-web-app.example.com
313
+ Access-Control-Allow-Methods: POST, OPTIONS
314
+ Access-Control-Allow-Headers: content-type, authorization, x-tenant-id
315
+ ```
316
+
317
+ 实际 header 清单以你的 `transport.headers` 为准。上报 CORS 与业务接口注入 `traceparent` 的 CORS 是两件事:前者影响 `/v1/rum` 数据能否发送,后者影响被观测 API 请求能否携带分布式追踪头。
318
+
319
+ ## Collector 验收清单
320
+
321
+ 联调时逐项确认:
322
+
323
+ 1. Network 面板中真实 URL 是 `<endpoint>/v1/rum`,没有重复路径;
324
+ 2. 预检和 POST 都成功,返回 2xx;
325
+ 3. 请求体顶层是 `resourceSpans`,其中是 Span 而非 metric/log;
326
+ 4. Collector 能读取 JSON 形式的 `traceId`、`spanId`、纳秒时间戳和 attributes;
327
+ 5. Collector 不依赖 SDK 从浏览器发送聚合计数、错误指纹或地理位置;
328
+ 6. 429/503 场景能返回合理 `Retry-After`,且不会诱导客户端超长等待;
329
+ 7. token 只能用于 RUM 写入,不能读取或管理后台数据;
330
+ 8. 服务端按 `service.name`、环境和租户做权限与路由校验。