@blueking/open-telemetry 0.0.27 → 0.0.29
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 +3 -3
- package/dist/bk-rum.global.js +1 -1
- package/dist/bk-rum.global.js.map +1 -1
- package/dist/core/config.d.ts +7 -4
- package/dist/core/runtime-context.d.ts +1 -1
- package/dist/core/url.d.ts +5 -0
- package/dist/index.js +430 -420
- package/dist/index.js.map +1 -1
- package/dist/schema/attributes.d.ts +1 -1
- package/package.json +1 -1
- package/skills/bk-rum-otele/SKILL.md +1 -1
- package/skills/bk-rum-otele/evals/evals.json +1 -1
- package/skills/bk-rum-otele/references/api.md +1 -1
- package/skills/bk-rum-otele/references/architecture.md +1 -1
- package/skills/bk-rum-otele/references/capabilities.md +1 -1
- package/skills/bk-rum-otele/references/configuration.md +5 -4
- package/skills/bk-rum-otele/references/framework-integration.md +7 -7
- package/skills/bk-rum-otele/references/getting-started.md +2 -2
- package/skills/bk-rum-otele/references/network.md +11 -3
- package/skills/bk-rum-otele/references/privacy.md +8 -6
- package/skills/bk-rum-otele/references/production.md +3 -3
- package/skills/bk-rum-otele/references/session-context.md +1 -1
- package/skills/bk-rum-otele/references/telemetry-reference.md +16 -12
- package/skills/bk-rum-otele/references/transport-sampling.md +2 -2
- package/skills/bk-rum-otele/references/troubleshooting.md +3 -3
- package/skills/bk-rum-otele/references/views-routing.md +9 -7
- package/dist/core/telemetry-attributes.d.ts +0 -3
|
@@ -54,7 +54,7 @@ export declare const RUM_ATTRIBUTES: {
|
|
|
54
54
|
readonly viewPhase: "view.phase";
|
|
55
55
|
readonly viewStartedAt: "view.started_at";
|
|
56
56
|
readonly viewUrl: "view.url";
|
|
57
|
-
readonly
|
|
57
|
+
readonly viewUrlTemplate: "view.url_template";
|
|
58
58
|
readonly viewVersion: "view.version";
|
|
59
59
|
readonly websocketPhase: "websocket.phase";
|
|
60
60
|
};
|
package/package.json
CHANGED
|
@@ -114,6 +114,6 @@ View Loading Time 默认开启;默认关闭、按需打开:`longTask`、`csp
|
|
|
114
114
|
- **隐私要业务显式配置**:SDK 不猜哪些字段敏感,URL、属性需通过 `privacy` / `request.beforeSend` 显式处理;SDK 不采集 HTTP Body;`user.id` 需 hash 的话要在传入前处理。`tracking.beforeSend` 新写入的字段不会再次自动经过 `redactAttributes`。
|
|
115
115
|
- **Consent**:未授权初始化时配置 `privacy.trackingConsent: 'not-granted'`,用户授权后调用 `setTrackingConsent('granted')`;撤销授权会停止采集并解除 patch。该配置不会阻止构造阶段读取 Device Resource 快照;要求授权前零读取时必须延迟构造 SDK。
|
|
116
116
|
- **单一信号**:只有 `/v1/rum` Trace 通道;计数、直方图、分位数、错误指纹和跨事件聚合由服务端完成。
|
|
117
|
-
-
|
|
117
|
+
- **低基数路由**:`tracking.view.getUrlTemplate` 与 `tracking.request.getUrlTemplate` 分别把页面路由和请求路径归类成 `/user/:id`,避免高基数 URL 污染指标维度。默认已按形状折叠数字 ID、UUID 和长十六进制段。
|
|
118
118
|
- **手动 View 的时机**:使用 `autoStart: false`,先 `await start()` 建立 Session,再调用 `startView()`;启动前调用会因没有有效采样 Session 而被忽略。
|
|
119
119
|
- **Action 命名隐私**:默认 `nameCollection: 'explicit'` 只读取 `data-bk-action-name`,否则退回标签名;只有显式设为 `text` 才读取可访问名称和 DOM 文本。
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"id": 0,
|
|
6
6
|
"name": "vue3-integration",
|
|
7
7
|
"prompt": "我们是一个 Vue3 + vue-router 的后台管理系统,想接入蓝鲸 RUM 做前端监控。collector 地址是 https://rum.example.com,token 放在 window.__RUM_TOKEN__。帮我写接入代码:要能追踪 SPA 路由切换、检测白屏(挂载点 #app),生产环境按 20% 采样,并且把 URL 里的 token 参数脱敏。",
|
|
8
|
-
"expected_output": "给出使用 @blueking/open-telemetry 的 BkOpenTelemetry 接入代码:application/transport(endpoint+token)、session.sampleRate=0.2、tracking.blankScreen.rootSelector='#app'、privacy.redactUrl 脱敏 token、通过 tracking.view.
|
|
8
|
+
"expected_output": "给出使用 @blueking/open-telemetry 的 BkOpenTelemetry 接入代码:application/transport(endpoint+token)、session.sampleRate=0.2、tracking.blankScreen.rootSelector='#app'、privacy.redactUrl 脱敏 token、通过 tracking.view.getUrlTemplate 自动追踪或 manual + await start() + startView() 对接 vue-router。API/配置项名称需与 SDK 实际一致。",
|
|
9
9
|
"files": [],
|
|
10
10
|
"assertions": []
|
|
11
11
|
},
|
|
@@ -108,7 +108,7 @@ SDK 只创建 OpenTelemetry Trace Provider。Session、View、请求、资源、
|
|
|
108
108
|
|
|
109
109
|
- `user.id`
|
|
110
110
|
- `session.id`、`session.start_time`、`session.type`、`session.has_replay`
|
|
111
|
-
- `view.id`、`view.
|
|
111
|
+
- `view.id`、`view.url`、`view.url_template`、`view.loading_type`,以及显式命名后才出现的 `view.name`
|
|
112
112
|
- 活动窗口内的 `action.id`
|
|
113
113
|
- Device 插件产生的视口、屏幕、网络和设备 ID
|
|
114
114
|
- View 自定义属性
|
|
@@ -93,7 +93,7 @@ View 类型:
|
|
|
93
93
|
|
|
94
94
|
每个 View 产生 start/update/end 生命周期 Span,`view.version` 递增。Loading Time 等待页面活动安静后更新;隐藏页面会取消当前自动计算,业务可用 `setViewLoadingTime()` 手动确认。
|
|
95
95
|
|
|
96
|
-
自动 mode 不因 query-only 改变创建 View。默认
|
|
96
|
+
自动 mode 不因 query-only 改变创建 View。默认 `view.url_template` 会把数字 ID、UUID 和长十六进制段折叠为 `:id`,但只按形状猜,非数字动态段需要用 `getUrlTemplate` 显式提供。
|
|
97
97
|
|
|
98
98
|
## 网络与资源
|
|
99
99
|
|
|
@@ -110,7 +110,7 @@ context: {
|
|
|
110
110
|
|
|
111
111
|
Hook 每次调用都应返回新的普通对象,且不能抛异常。SDK 不 hash、不改写 `user.id`。如果 ID 敏感,接入方必须在传入前完成不可逆处理。
|
|
112
112
|
|
|
113
|
-
未配置 `attributes.page` 时默认返回空对象。页面地址由 `view.url` 表达,低基数路由由 `view.
|
|
113
|
+
未配置 `attributes.page` 时默认返回空对象。页面地址由 `view.url` 表达,低基数路由由 `view.url_template` 表达;该 Hook 只用于补充业务自定义的页面维度。
|
|
114
114
|
|
|
115
115
|
属性合并优先级不是全局统一的:各插件会先组合公共字段、Hook 字段和事件字段,`startSpan()` 再用运行时上下文作为底层。精确字段请以对应能力页和[RUM 数据模型](./data-model.md)为准。
|
|
116
116
|
|
|
@@ -163,6 +163,7 @@ tracking: {
|
|
|
163
163
|
| `excludedUrls` | 无 | 匹配后不建请求 Span、不注入 trace header,也不计入 View/Action 活动 |
|
|
164
164
|
| `allowedTracingUrls` | 无 | 只有明确匹配的 URL 才注入 W3C `traceparent`,同源也不例外;注入的是独立 trace context,并通过 Span Link 关联回 RUM Span。业务已自行设置 trace Header 时不注入 |
|
|
165
165
|
| `beforeSend` | 无 | 只作用于 Fetch/XHR 请求事件;`event.resource.outcome` 区分 response/abort/timeout/network_error,返回 `false` 丢弃请求 Span |
|
|
166
|
+
| `getUrlTemplate` | 折叠动态段后的 pathname | 生成低基数 `url.template`,例如 `/api/orders/:id`。收到的是未脱敏 URL,返回空值或抛错时回退到默认规则 |
|
|
166
167
|
|
|
167
168
|
URL matcher 支持 string、RegExp 或函数:
|
|
168
169
|
|
|
@@ -179,10 +180,10 @@ URL matcher 支持 string、RegExp 或函数:
|
|
|
179
180
|
| --- | --- | --- | --- |
|
|
180
181
|
| `tracking` | `'auto' \| 'manual'` | `'auto'` | 自动监听 History/hash,或只接受 `startView()` |
|
|
181
182
|
| `loadingTime` | `boolean` | `true` | 自动计算初始加载和路由稳定耗时 |
|
|
182
|
-
| `
|
|
183
|
+
| `getUrlTemplate` | `(url) => string \| undefined` | 折叠动态段后的 pathname | 生成低基数 `view.url_template` |
|
|
183
184
|
| `excludedActivityUrls` | URL matcher | 无 | 不让长轮询/流式/埋点请求延长 View loading time |
|
|
184
185
|
|
|
185
|
-
`
|
|
186
|
+
`getUrlTemplate` 返回 `undefined` 或抛错时回退到默认规则:取 pathname 并把数字 ID、UUID、长十六进制段折叠为 `:id`。它与 `tracking.request.getUrlTemplate` 共用这套默认折叠,但两者是独立入口——页面路由与 API 路径的模板规则通常不同。自动路由不会因 query-only 变化创建新 View;hash 变化会创建,但纯锚点语义由业务自行决定是否改用 manual。详见[View、路由与页面加载](./views-routing.md)。
|
|
186
187
|
|
|
187
188
|
## action
|
|
188
189
|
|
|
@@ -280,7 +281,7 @@ const rum = new BkOpenTelemetry({
|
|
|
280
281
|
session: { sampleRate: 0.2 },
|
|
281
282
|
tracking: {
|
|
282
283
|
view: {
|
|
283
|
-
|
|
284
|
+
getUrlTemplate(url) {
|
|
284
285
|
return new URL(url, location.href).pathname.replace(/\/orders\/[^/]+/, '/orders/:id');
|
|
285
286
|
},
|
|
286
287
|
excludedActivityUrls: [/\/events\/stream(?:\?|$)/],
|
|
@@ -14,7 +14,7 @@ SDK 不绑定 Vue、React 或具体 Router。框架集成主要解决四件事
|
|
|
14
14
|
tracking: {
|
|
15
15
|
view: {
|
|
16
16
|
tracking: 'auto',
|
|
17
|
-
|
|
17
|
+
getUrlTemplate: groupRoute,
|
|
18
18
|
},
|
|
19
19
|
}
|
|
20
20
|
```
|
|
@@ -73,7 +73,7 @@ export const rum = new BkOpenTelemetry({
|
|
|
73
73
|
transport: { endpoint: window.__RUM_ENDPOINT__ },
|
|
74
74
|
tracking: {
|
|
75
75
|
view: {
|
|
76
|
-
|
|
76
|
+
getUrlTemplate(rawUrl) {
|
|
77
77
|
const path = new URL(rawUrl, location.href).pathname;
|
|
78
78
|
return routeGroups.find(item => item.pattern.test(path))?.group ?? path;
|
|
79
79
|
},
|
|
@@ -98,7 +98,7 @@ export const rum = new BkOpenTelemetry({
|
|
|
98
98
|
tracking: {
|
|
99
99
|
view: {
|
|
100
100
|
tracking: 'manual',
|
|
101
|
-
|
|
101
|
+
getUrlTemplate(rawUrl) {
|
|
102
102
|
const path = new URL(rawUrl, location.href).pathname;
|
|
103
103
|
return path.replace(/\/orders\/[^/]+/, '/orders/:id');
|
|
104
104
|
},
|
|
@@ -154,7 +154,7 @@ export const rum = new BkOpenTelemetry({
|
|
|
154
154
|
transport: { endpoint: window.__RUM_ENDPOINT__ },
|
|
155
155
|
tracking: {
|
|
156
156
|
view: {
|
|
157
|
-
|
|
157
|
+
getUrlTemplate(rawUrl) {
|
|
158
158
|
return new URL(rawUrl, location.href).pathname.replace(/\/orders\/[^/]+/, '/orders/:id');
|
|
159
159
|
},
|
|
160
160
|
},
|
|
@@ -196,7 +196,7 @@ export const rum = new BkOpenTelemetry({
|
|
|
196
196
|
tracking: {
|
|
197
197
|
view: {
|
|
198
198
|
tracking: 'manual',
|
|
199
|
-
|
|
199
|
+
getUrlTemplate: rawUrl =>
|
|
200
200
|
new URL(rawUrl, location.href).pathname.replace(/\/orders\/[^/]+/, '/orders/:id'),
|
|
201
201
|
},
|
|
202
202
|
blankScreen: { rootSelector: '#root' },
|
|
@@ -275,10 +275,10 @@ export const router = createBrowserRouter([
|
|
|
275
275
|
|
|
276
276
|
## Hash Router
|
|
277
277
|
|
|
278
|
-
自动模式会观察 hash。默认 URL 清洗会移除 hash,所以 `view.url` 看不到 hash 内容,但 `
|
|
278
|
+
自动模式会观察 hash。默认 URL 清洗会移除 hash,所以 `view.url` 看不到 hash 内容,但 `getUrlTemplate(rawUrl)` 仍可在清洗前解析它:
|
|
279
279
|
|
|
280
280
|
```ts
|
|
281
|
-
|
|
281
|
+
getUrlTemplate(rawUrl) {
|
|
282
282
|
const url = new URL(rawUrl, location.href);
|
|
283
283
|
const hashPath = url.hash.replace(/^#/, '').split('?')[0] || '/';
|
|
284
284
|
return hashPath.replace(/\/orders\/[^/]+/, '/orders/:id');
|
|
@@ -111,12 +111,12 @@ session: {
|
|
|
111
111
|
|
|
112
112
|
## 6. 治理动态路由
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
默认规则会把 pathname 里的数字 ID、UUID 和长十六进制段折叠为 `:id`,因此 `/orders/1001` 与 `/orders/1002` 会归到同一个 `/orders/:id`。代价是纯数字段无法与语义段区分,`/reports/2024/summary` 也会变成 `/reports/:id/summary`。需要精确模板时自行覆盖:
|
|
115
115
|
|
|
116
116
|
```ts
|
|
117
117
|
tracking: {
|
|
118
118
|
view: {
|
|
119
|
-
|
|
119
|
+
getUrlTemplate(rawUrl) {
|
|
120
120
|
const path = new URL(rawUrl, location.href).pathname;
|
|
121
121
|
return path
|
|
122
122
|
.replace(/\/orders\/[^/]+/g, '/orders/:id')
|
|
@@ -39,9 +39,14 @@ Fetch 和 XHR 都生成 `browser.resource`:
|
|
|
39
39
|
| `resource.type` | `fetch` | `xhr` |
|
|
40
40
|
| `http.request.method` | `init.method`、Request method 或 `GET`,转大写 | `open()` method,转大写 |
|
|
41
41
|
| `url.full` | 绝对 URL,经脱敏 | 同左 |
|
|
42
|
+
| `url.template` | 低基数路由模板,只含 path | 同左 |
|
|
42
43
|
| `http.response.status_code` | 获得真实 Response status 时 | `load` 且 `xhr.status>0` 时 |
|
|
43
44
|
| Span Kind | CLIENT | CLIENT |
|
|
44
45
|
|
|
46
|
+
`url.template` 是给后端按 API 路由聚合用的低基数维度(semconv `url.template`,当前仍是 Development 阶段)。默认取 pathname 并把数字 ID、UUID、长十六进制段折叠为 `:id`,`/api/orders/1001` 与 `/api/orders/1002` 都归到 `/api/orders/:id`。两点已知代价:纯数字段无法与语义段区分,`/reports/2024/summary` 会变成 `/reports/:id/summary`;模板按 semconv 定义不含 host,跨域同路径会聚到一起,需要区分来源时配合 `server.address`。需要精确模板时用 `tracking.request.getUrlTemplate` 覆盖,它拿到的是未脱敏 URL(便于按 query 判断路由),返回空值或抛错都回退到默认规则。
|
|
47
|
+
|
|
48
|
+
这套折叠规则与 View 的 `view.url_template` 共用,但入口独立:页面路由和 API 路径的模板规则通常不同,所以 `tracking.view.getUrlTemplate` 与 `tracking.request.getUrlTemplate` 互不影响。
|
|
49
|
+
|
|
45
50
|
Span 开始时间使用请求开始时间,结束时间优先使用匹配到的 `PerformanceResourceTiming.responseEnd`;没有匹配时使用 Fetch resolve/reject 或 XHR `load/abort/timeout/error` 的完成时间。`http.response.status_code` 只表示真实 HTTP Response,不会上报 XHR 的本地占位值 `0`。
|
|
46
51
|
|
|
47
52
|
## Outcome 与 Status
|
|
@@ -119,6 +124,7 @@ traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
|
|
|
119
124
|
"span_id": "00f067aa0ba902b7",
|
|
120
125
|
"attributes": {
|
|
121
126
|
"format": "traceparent",
|
|
127
|
+
"injected": true,
|
|
122
128
|
"traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
|
|
123
129
|
}
|
|
124
130
|
}
|
|
@@ -126,7 +132,9 @@ traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
|
|
|
126
132
|
}
|
|
127
133
|
```
|
|
128
134
|
|
|
129
|
-
`attributes.format`
|
|
135
|
+
`attributes.format` 是命中的传播格式,`attributes.injected` 标记这条 trace context 是否由 SDK 生成——业务自带合法 `traceparent` 时 `format` 与 SDK 注入同值,只能靠 `injected` 区分。其余键是该格式的**原始 Header 名与原始取值**(不做补零或进制转换),例如 Datadog 会带上 `x-datadog-trace-id`、`x-datadog-parent-id`、`x-datadog-sampling-priority` 等。
|
|
136
|
+
|
|
137
|
+
`tracestate` 不做记录:它在本链路上没有消费者(SDK 从不注入 `tracestate`,后端只解析 `traceparent`),而 W3C 允许 32 个成员、每成员 256 字符,最坏情况下会给每个被追踪请求平白增加数 KB 负载。这些 Link Attributes 也不经过 `privacy.redactAttributes` 脱敏。
|
|
130
138
|
|
|
131
139
|
请求 Patch 只在当前 Session 已采样时创建 Span 并注入,因此发出的 flags 恒为 `01`。注入的 span-id 在前端没有对应的已上报 Span,后端 Trace 的根 Span 会以它作为 `parent_span_id`。
|
|
132
140
|
|
|
@@ -136,14 +144,14 @@ traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
|
|
|
136
144
|
|
|
137
145
|
| 优先级 | `format` | Header | 能否解析出合法 OTel id |
|
|
138
146
|
| --- | --- | --- | --- |
|
|
139
|
-
| 1 | `traceparent` | `traceparent
|
|
147
|
+
| 1 | `traceparent` | `traceparent` | 能 |
|
|
140
148
|
| 2 | `sentry-trace` | `sentry-trace` | 能 |
|
|
141
149
|
| 3 | `b3` | `b3`(单头) | 能,64 位 trace-id 左侧补零到 128 位 |
|
|
142
150
|
| 4 | `b3-multi` | `x-b3-traceid` / `x-b3-spanid` / `x-b3-parentspanid` / `x-b3-sampled` / `x-b3-flags` | 同上 |
|
|
143
151
|
| 5 | `datadog` | `x-datadog-trace-id` / `x-datadog-parent-id` / `x-datadog-sampling-priority` / `x-datadog-origin` / `x-datadog-tags` | 能,十进制换算为 hex,128 位时从 `x-datadog-tags` 的 `_dd.p.tid` 拼接高位 |
|
|
144
152
|
| 6 | `sw8` | `sw8` | **不能**,SkyWalking 的 trace-id 不是 16 字节 hex |
|
|
145
153
|
|
|
146
|
-
一旦探测到上表任一 Header,SDK
|
|
154
|
+
一旦探测到上表任一 Header,SDK **完全不注入**,Link Attributes 里 `injected` 为 `false`,并写入命中格式的原始 Header。只记录命中格式自己的 Header——若 `traceparent` 与 `b3` 同时存在,按优先级只记录前者。
|
|
147
155
|
|
|
148
156
|
几点需要注意:
|
|
149
157
|
|
|
@@ -85,24 +85,26 @@ privacy: {
|
|
|
85
85
|
|
|
86
86
|
SDK 在写入 View、Request、Resource、错误资源、CSP source、Long Task source、referrer 等 URL 字段时调用该 Hook。自定义插件直接写入名为 URL 的任意属性不会被自动识别,插件必须显式调用 `context.config.hooks.redactUrl()`。
|
|
87
87
|
|
|
88
|
-
##
|
|
88
|
+
## 路由模板不是 URL 脱敏
|
|
89
89
|
|
|
90
90
|
```ts
|
|
91
91
|
tracking: {
|
|
92
92
|
view: {
|
|
93
|
-
|
|
93
|
+
getUrlTemplate(url) {
|
|
94
94
|
return new URL(url, location.href).pathname.replace(/\/orders\/[^/]+/, '/orders/:id');
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
97
|
}
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
`
|
|
100
|
+
`getUrlTemplate` 只生成低基数 `view.url_template`,不会改写 `view.url`。要保护原 URL,仍需 `privacy.redactUrl`。建议两者使用相同的动态段规则,但用途不同:
|
|
101
101
|
|
|
102
102
|
- `redactUrl`:隐私和敏感数据边界;
|
|
103
|
-
- `
|
|
103
|
+
- `getUrlTemplate`:聚合维度和查询基数。
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
请求侧的 `tracking.request.getUrlTemplate` 同理,只生成 `url.template`,不影响 `url.full` 的脱敏。注意它收到的是**未脱敏**的请求 URL,因此自定义实现不要把 query 里的原值拼进返回的模板。
|
|
106
|
+
|
|
107
|
+
未配置 `context.attributes.page` 时默认返回空对象,不存在独立的默认页面属性路径。页面地址统一由经过 `redactUrl` 的 `view.url` 表达,聚合维度使用 `view.url_template`;业务通过该 Hook 添加的属性仍需自行确保不包含敏感信息。
|
|
106
108
|
|
|
107
109
|
## 属性脱敏
|
|
108
110
|
|
|
@@ -267,7 +269,7 @@ SDK 不实现以下能力:
|
|
|
267
269
|
## 上线评审清单
|
|
268
270
|
|
|
269
271
|
1. `redactUrl` 覆盖 path 中的动态 ID,且仍删除 query/fragment/认证信息;
|
|
270
|
-
2. `view.
|
|
272
|
+
2. `view.url_template` 是低基数模板;
|
|
271
273
|
3. `user.id` 已按公司规范处理;
|
|
272
274
|
4. Action 未开启不必要的文本采集;
|
|
273
275
|
5. CSP、错误 stack、自定义字段经过字段评审;
|
|
@@ -26,7 +26,7 @@ export const rum = new BkOpenTelemetry({
|
|
|
26
26
|
},
|
|
27
27
|
tracking: {
|
|
28
28
|
view: {
|
|
29
|
-
|
|
29
|
+
getUrlTemplate(rawUrl) {
|
|
30
30
|
return new URL(rawUrl, location.href).pathname
|
|
31
31
|
.replace(/\/orders\/[^/]+/g, '/orders/:id')
|
|
32
32
|
.replace(/\/users\/[^/]+/g, '/users/:id');
|
|
@@ -97,7 +97,7 @@ Session 采样率控制整体数据量。粗略估算:
|
|
|
97
97
|
|
|
98
98
|
必须排查:
|
|
99
99
|
|
|
100
|
-
- `view.
|
|
100
|
+
- `view.url_template` 是否含订单 ID、用户 ID、UUID;
|
|
101
101
|
- custom/action name 是否拼业务 ID;
|
|
102
102
|
- 自定义属性是否包含时间戳、随机值、整条 URL;
|
|
103
103
|
- error message 是否因为动态值导致无限分组。
|
|
@@ -220,7 +220,7 @@ SDK 设计为:
|
|
|
220
220
|
- exporter 失败不会让业务 Fetch/XHR 失败;
|
|
221
221
|
- unsupported Performance API 时跳过对应能力。
|
|
222
222
|
|
|
223
|
-
但自定义 Hook/插件仍是业务代码:必须快速、同步、无副作用,不应发网络请求或抛异常。上线前对 `redactUrl`、`redactAttributes`、`
|
|
223
|
+
但自定义 Hook/插件仍是业务代码:必须快速、同步、无副作用,不应发网络请求或抛异常。上线前对 `redactUrl`、`redactAttributes`、`getUrlTemplate`、两个 `beforeSend` 做异常与性能测试。
|
|
224
224
|
|
|
225
225
|
## 12. 灰度验收
|
|
226
226
|
|
|
@@ -171,7 +171,7 @@ context: {
|
|
|
171
171
|
}
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
未配置时默认返回空对象。页面地址使用 `view.url`,低基数路由使用 `view.
|
|
174
|
+
未配置时默认返回空对象。页面地址使用 `view.url`,低基数路由使用 `view.url_template`;业务需要额外页面维度时可自行返回。
|
|
175
175
|
|
|
176
176
|
Hook 每次执行,应保持低成本且不要抛错。它可能包含高基数字段,但服务端聚合维度应只选择稳定、低基数属性。
|
|
177
177
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
| 领域属性 | `resource.*`、`error.*`、`vital.*`、`long_task.*` 等 | 具体发生了什么,耗时、来源和诊断细节是什么? |
|
|
17
17
|
| OTLP Envelope 与 Event | `traceId`、`spanId`、时间戳、`status`、`events` | 如何定位单条记录、关联调用链和读取异常/脚本归因? |
|
|
18
18
|
|
|
19
|
-
推荐先用 Resource 字段限定应用和环境,再以 `span_type` 选择信号类型,最后使用领域字段细分。Session/View 聚合优先使用 `session.id`、`view.id`;路由聚合优先使用低基数的 `view.
|
|
19
|
+
推荐先用 Resource 字段限定应用和环境,再以 `span_type` 选择信号类型,最后使用领域字段细分。Session/View 聚合优先使用 `session.id`、`view.id`;路由聚合优先使用低基数的 `view.url_template`,不要直接按完整 URL 或原始 path 建立高基数索引。
|
|
20
20
|
|
|
21
21
|
## 阅读约定
|
|
22
22
|
|
|
@@ -95,9 +95,9 @@ Resource Attribute 描述产生 Span 的 SDK 实例和运行环境,同一实
|
|
|
95
95
|
| `session.type` | string | Session 有效 | 当前固定为 `user`,为未来区分其他 Session 类型保留。 |
|
|
96
96
|
| `session.has_replay` | boolean | Session 有效 | 当前固定为 `false`,表示 SDK 没有随该 Session 上报 Session Replay 数据。 |
|
|
97
97
|
| `view.id` | string | View 有效 | 当前页面视图的关联 ID。首次加载、有效 SPA 路由变化、BFCache 恢复或 Session 续建都会创建新 View。 |
|
|
98
|
-
| `view.name` | string |
|
|
98
|
+
| `view.name` | string | 显式命名后 | 业务给出的可读名称,仅在 `startView({ name })` 或 `setViewName()` 调用后存在。默认不上报,展示请用 `view.name ?? view.url_template`。 |
|
|
99
99
|
| `view.url` | string | View 有效 | 创建 View 时的完整 URL,经 `redactUrl` 脱敏。与当前实时 `location.href` 不一定相同。 |
|
|
100
|
-
| `view.
|
|
100
|
+
| `view.url_template` | string | View 有效 | 低基数路由模板。默认把数字 ID、UUID 和长十六进制路径段归一为 `:id`,也可由 `getUrlTemplate` 自定义。 |
|
|
101
101
|
| `view.loading_type` | string | View 有效 | View 创建类型:`initial_load` 首次文档加载、`route_change` SPA 路由、`bf_cache` BFCache 恢复、`session_renewal` Session 到期后续建。 |
|
|
102
102
|
| `action.id` | string[] | 自动 Action 活动中 | 与当前 Span 同时相关的自动 Action ID 数组;允许多个点击 Action 生命周期重叠。注意 Action Span 自身的同名字段是单个 string。 |
|
|
103
103
|
| `device.id` | string | Device 插件开启 | SDK 生成的匿名设备关联 ID。默认仅在本次插件生命周期内稳定;`persistentId: true` 时写入 localStorage,从而跨页面和 Session 保持。 |
|
|
@@ -109,7 +109,7 @@ Resource Attribute 描述产生 Span 的 SDK 实例和运行环境,同一实
|
|
|
109
109
|
| `network.effective_type` | string | Network Information API 支持 | 浏览器估算的有效网络类型,常见为 `slow-2g`、`2g`、`3g`、`4g`。它反映体验模型,不等同于真实无线制式。 |
|
|
110
110
|
| `network.connection.type` | string | 浏览器提供 `connection.type` 时 | 浏览器返回的原始连接类型,例如 `wifi`、`cellular`、`ethernet`;多数 Safari/Firefox 环境可能缺失。 |
|
|
111
111
|
|
|
112
|
-
默认 `context.attributes.page()` 返回空对象,不附加独立页面属性。页面地址使用 View 创建时冻结并经过 `redactUrl` 的 `view.url`,低基数路由聚合使用 `view.
|
|
112
|
+
默认 `context.attributes.page()` 返回空对象,不附加独立页面属性。页面地址使用 View 创建时冻结并经过 `redactUrl` 的 `view.url`,低基数路由聚合使用 `view.url_template`;业务需要额外页面维度时可自定义该 Hook。
|
|
113
113
|
|
|
114
114
|
## RUM 公共分类字段
|
|
115
115
|
|
|
@@ -166,9 +166,9 @@ Session Span 允许没有 `view.id`:SDK 先建立 Session,再创建初始 Vi
|
|
|
166
166
|
| `view.id` | string | 所有阶段 | View 关联 ID。同一 View 的 start/update/end 使用相同值,可与该 View 内其他 Span 关联。 |
|
|
167
167
|
| `view.version` | number | 从 1 递增 | 每次 `emitViewEvent` 递增;用于恢复同一 View 生命周期快照的先后顺序。 |
|
|
168
168
|
| `view.started_at` | number | epoch ms | View 开始时间。初始 View 使用 `performance.timeOrigin`,路由/BFCache/续建 View 使用创建时刻。 |
|
|
169
|
-
| `view.name` | string |
|
|
169
|
+
| `view.name` | string | 显式命名后 | 业务可读名称,仅 `startView({ name })` 或 `setViewName()` 后存在;未命名的 View 不带该字段。 |
|
|
170
170
|
| `view.url` | string | 所有阶段 | 创建 View 时的 URL,经 `redactUrl` 脱敏;在该 View 生命周期内保持不变。 |
|
|
171
|
-
| `view.
|
|
171
|
+
| `view.url_template` | string | 所有阶段 | 低基数路由模板。数字 ID、UUID、长十六进制段默认折叠为 `:id`,用于稳定聚合动态路由。 |
|
|
172
172
|
| `view.loading_type` | string | 所有阶段 | `initial_load`、`route_change`、`bf_cache` 或 `session_renewal`,含义见运行时公共属性。 |
|
|
173
173
|
| `view.loading_time` | number | 计算完成后,ms | 从 `view.started_at` 到页面活动稳定的耗时。初始加载同时等待 load event 和页面活动,以较晚者为准;可由 `setViewLoadingTime()` 手动结束。 |
|
|
174
174
|
| `view.loading_time_source` | string | 有 `view.loading_time` 时 | `auto` 表示 SDK 自动观察页面活动;`manual` 表示业务调用 `setViewLoadingTime()`。 |
|
|
@@ -190,7 +190,8 @@ Session Span 允许没有 `view.id`:SDK 先建立 Session,再创建初始 Vi
|
|
|
190
190
|
| 字段 | 类型 | 条件/单位 | 来源与详细说明 |
|
|
191
191
|
| --------------------------------- | ------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
192
192
|
| `url.full` | string | 有有效请求/资源 URL | 绝对 URL,经 `redactUrl` 脱敏。用于定位请求目标;不要假设 query 中仍保留原始参数。 |
|
|
193
|
-
| `
|
|
193
|
+
| `url.template` | string | Fetch/XHR | 低基数路由模板,只含 path,例如 `/api/orders/:id`。默认把数字 ID、UUID、长十六进制段折叠为 `:id`,可由 `tracking.request.getUrlTemplate` 覆盖。按 API 路由聚合请求时用它,不要用 `url.full`。静态资源 Span 没有该字段。 |
|
|
194
|
+
| `server.address` | string | URL 可解析 | URL 的 `hostname`,不含端口。相对 URL 会基于当前页面地址解析。模板不含 host,跨域同路径会聚到一起,需要区分来源时配合该字段。 |
|
|
194
195
|
| `server.port` | number | URL 显式包含端口 | URL 的显式端口号。使用协议默认端口且 URL 未写端口时缺失。 |
|
|
195
196
|
| `resource.type` | string | 必有 | Fetch/XHR 为 `fetch`/`xhr`;静态资源使用 `PerformanceResourceTiming.initiatorType`,为空时为 `other`,常见还有 `script`、`link`、`img`、`css`。 |
|
|
196
197
|
| `http.request.method` | string | Fetch/XHR | 归一为大写的 HTTP 方法,例如 `GET`、`POST`。静态资源通常没有可用的请求方法,因此缺失。 |
|
|
@@ -206,12 +207,15 @@ Session Span 允许没有 `view.id`:SDK 先建立 Session,再创建初始 Vi
|
|
|
206
207
|
|
|
207
208
|
命中 `allowedTracingUrls` 的请求还会带一条 Span Link,用于关联后端 Trace。Trace 来源不记在 Span Attributes 上,而是记在 Link Attributes 上:
|
|
208
209
|
|
|
209
|
-
| 字段 | 类型
|
|
210
|
-
| ----------- |
|
|
211
|
-
| `format` | string
|
|
212
|
-
|
|
|
210
|
+
| 字段 | 类型 | 条件 | 说明 |
|
|
211
|
+
| ----------- | ------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
212
|
+
| `format` | string | 恒有 | 命中的传播格式,取值为 `traceparent`、`sentry-trace`、`b3`、`b3-multi`、`datadog`、`sw8`。 |
|
|
213
|
+
| `injected` | boolean | 恒有 | 这条 trace context 是否由 SDK 生成并注入。`true` 表示请求原本没有任何 trace Header;`false` 表示业务已自行传播,SDK 未注入。业务自带合法 `traceparent` 时 `format` 与 SDK 注入同值,只能靠该字段区分。 |
|
|
214
|
+
| Header 原名 | string | 该 Header 存在 | 命中格式的原始 Header 名与原始取值,未做补零或进制转换,例如 `traceparent`、`b3`、`x-datadog-trace-id`、`sw8`。仅记录命中格式自己的 Header。 |
|
|
213
215
|
|
|
214
|
-
Link 的 `trace_id` / `span_id` 优先取自解析结果;`sw8` 这类无法映射为合法 OTel id 的格式会补一对随机占位 id,此时后端不存在对应 Trace。
|
|
216
|
+
Link 的 `trace_id` / `span_id` 优先取自解析结果;`sw8` 这类无法映射为合法 OTel id 的格式会补一对随机占位 id,此时后端不存在对应 Trace。
|
|
217
|
+
|
|
218
|
+
两点数据口径需要注意:Link Attributes 不经过 `privacy.redactAttributes` 脱敏;`tracestate` 不做记录,它在本链路上没有消费者,且体积最坏可达数 KB。
|
|
215
219
|
|
|
216
220
|
网络阶段字段均为 number、单位 ms。每个 `*.start` 相对该 Resource Entry 的 `startTime`,每个 `*.duration` 为对应阶段结束值减开始值:
|
|
217
221
|
|
|
@@ -60,9 +60,9 @@ https://rum.example.com/collector/v1/rum
|
|
|
60
60
|
{ "key": "session.type", "value": { "stringValue": "user" } },
|
|
61
61
|
{ "key": "session.has_replay", "value": { "boolValue": false } },
|
|
62
62
|
{ "key": "view.id", "value": { "stringValue": "view-01" } },
|
|
63
|
-
{ "key": "view.name", "value": { "stringValue": "
|
|
63
|
+
{ "key": "view.name", "value": { "stringValue": "订单详情" } },
|
|
64
64
|
{ "key": "view.url", "value": { "stringValue": "https://app.example.com/orders/123" } },
|
|
65
|
-
{ "key": "view.
|
|
65
|
+
{ "key": "view.url_template", "value": { "stringValue": "/orders/:id" } },
|
|
66
66
|
{ "key": "view.loading_type", "value": { "stringValue": "initial_load" } },
|
|
67
67
|
{ "key": "span_type", "value": { "stringValue": "resource" } },
|
|
68
68
|
{ "key": "outcome.type", "value": { "stringValue": "success" } },
|
|
@@ -277,13 +277,13 @@ tracking: {
|
|
|
277
277
|
|
|
278
278
|
跨域还需要服务端 CORS 允许请求头 `traceparent`。如果预检失败,缩小白名单并修复 API 服务的 CORS;不要把所有第三方 URL 加入白名单。
|
|
279
279
|
|
|
280
|
-
命中白名单却依然没有注入时,看 Span Link 的 `attributes.
|
|
280
|
+
命中白名单却依然没有注入时,看 Span Link 的 `attributes.injected`。为 `false` 说明业务已经自行设置了 trace Header,SDK 尊重既有链路而不注入,此时 `attributes.format` 告诉你是哪种格式,同组的原始 Header 也一并记在 Link Attributes 里。注意不能只看 `format`:业务自带合法 `traceparent` 时它同样是 `traceparent`,与 SDK 注入无法区分。
|
|
281
281
|
|
|
282
282
|
## 后端按 `traceparent` 的 trace-id 查不到 RUM Span
|
|
283
283
|
|
|
284
284
|
注入的 trace-id 与 RUM Span 自身的 `traceId` **不是同一个值**,两者通过 Span Link 关联。后端应按 `browser.resource` Span 的 `link.trace_id` 反查,而不是直接用 `traceId` 匹配。
|
|
285
285
|
|
|
286
|
-
如果 Link 的 `attributes.format` 不是 `traceparent`,说明业务用的是 `b3` / `sw8` / Datadog 等格式。后端只解析 W3C `traceparent`,这种情况下后端不会生成 Trace,Link 里的 trace-id 自然查不到。
|
|
286
|
+
如果 Link 的 `attributes.injected` 为 `false` 且 `attributes.format` 不是 `traceparent`,说明业务用的是 `b3` / `sw8` / Datadog 等格式。后端只解析 W3C `traceparent`,这种情况下后端不会生成 Trace,Link 里的 trace-id 自然查不到。
|
|
287
287
|
|
|
288
288
|
`sw8` 以及 `b3: 0` 这类只有采样标记的值,SDK 解析不出合法 OTel id,会补一对**随机占位 id** 让 Link 结构保持统一。这对 id 在后端一定查不到,判断依据仍是 `attributes.format` 与其中的原始 Header。
|
|
289
289
|
|
|
@@ -407,7 +407,7 @@ tracking: {
|
|
|
407
407
|
- pathname 或非纯锚点 hash 变化会触发;
|
|
408
408
|
- Router 同时手动 `startView()` 且使用 auto 会重复;
|
|
409
409
|
- 微前端多个实例会重复;
|
|
410
|
-
-
|
|
410
|
+
- 默认模板只按形状折叠数字 ID、UUID 和长十六进制段,识别不了 `/orders/abc-slug` 这类非数字动态段,需要用 `getUrlTemplate` 显式提供;
|
|
411
411
|
- `setViewName()` 是改名,不创建新 View;
|
|
412
412
|
- Session 续期和 BFCache 恢复会创建具有特定 loading type 的 View。
|
|
413
413
|
|
|
@@ -13,7 +13,7 @@ View 表示一次可独立分析的页面体验。初始文档加载、SPA 路
|
|
|
13
13
|
| `bf_cache` | 从 Back/Forward Cache 恢复 | `view` |
|
|
14
14
|
| `session_renewal` | Session 过期后新 Session 接管当前页面 | `view` |
|
|
15
15
|
|
|
16
|
-
每个 View 都生成新的 `view.id`。View
|
|
16
|
+
每个 View 都生成新的 `view.id`。View 的 URL、路由模板和自定义属性作为运行时上下文挂到其间发生的普通 Span;名称只在业务显式命名后才带上。
|
|
17
17
|
|
|
18
18
|
## 自动路由模式
|
|
19
19
|
|
|
@@ -52,14 +52,16 @@ bkOT.startView({
|
|
|
52
52
|
|
|
53
53
|
`attributes` 会经过 `redactAttributes`,并删除 SDK 所有保留字段;业务无法通过 View attributes 覆盖 `session.*`、`view.*`、`span_type` 或 `outcome.*`。
|
|
54
54
|
|
|
55
|
-
## View
|
|
55
|
+
## View 名称和路由模板
|
|
56
56
|
|
|
57
|
-
默认 `view.
|
|
57
|
+
默认 `view.url_template` 取 URL pathname 并把数字 ID、UUID、长十六进制段折叠为 `:id`。请求 Span 的 `url.template` 复用同一套折叠规则,但走独立的 `tracking.request.getUrlTemplate`。
|
|
58
|
+
|
|
59
|
+
`view.name` 与 `view.url_template` 是两个不同维度:前者是业务给出的可读标签(「订单详情」),后者是路由模板(`/orders/:id`)。**只有显式调用 `startView({ name })` 或 `setViewName()` 时才会上报 `view.name`**,未命名的 View 不带该字段,后端展示时用 `view.name ?? view.url_template` 兜底即可。这样 `view.name` 的存在本身就表示"业务命名过",也不会在每条 Span 上重复一份模板字符串。
|
|
58
60
|
|
|
59
61
|
```ts
|
|
60
62
|
tracking: {
|
|
61
63
|
view: {
|
|
62
|
-
|
|
64
|
+
getUrlTemplate(url) {
|
|
63
65
|
return new URL(url, location.href).pathname
|
|
64
66
|
.replace(/\/orders\/[^/]+/, '/orders/:id')
|
|
65
67
|
.replace(/\/users\/[^/]+/, '/users/:id');
|
|
@@ -68,7 +70,7 @@ tracking: {
|
|
|
68
70
|
}
|
|
69
71
|
```
|
|
70
72
|
|
|
71
|
-
`
|
|
73
|
+
`getUrlTemplate()` 应返回低基数、稳定的路由模板。默认实现已经会把数字 ID、UUID 和长十六进制段替换为 `:id`,但它只能按形状猜:纯数字段无法与语义段区分,`/reports/2024/summary` 会被折成 `/reports/:id/summary`。路由规则明确的应用应显式提供模板,不要依赖猜测。
|
|
72
74
|
|
|
73
75
|
运行期可修改名称:
|
|
74
76
|
|
|
@@ -76,12 +78,12 @@ tracking: {
|
|
|
76
78
|
bkOT.setViewName('订单详情-只读');
|
|
77
79
|
```
|
|
78
80
|
|
|
79
|
-
名称变化不会创建新 View,但会更新运行时上下文并发送 `browser.view` update
|
|
81
|
+
名称变化不会创建新 View,但会更新运行时上下文并发送 `browser.view` update。传入与当前相同名称时不发送更新。首次调用会让此后的 Span 开始带上 `view.name`。
|
|
80
82
|
|
|
81
83
|
## URL 与前序页面
|
|
82
84
|
|
|
83
85
|
- `view.url`:当前 URL,经 `privacy.redactUrl`。
|
|
84
|
-
- `view.
|
|
86
|
+
- `view.url_template`:聚合路由模板。
|
|
85
87
|
- `url.previous`:前一个原始 URL 经脱敏;初始加载为空字符串。
|
|
86
88
|
- `document.referrer`:仅初始自动加载写入并脱敏。
|
|
87
89
|
|