@blueking/open-telemetry 0.0.14 → 0.0.16

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 (49) hide show
  1. package/README.md +96 -641
  2. package/dist/bk-rum.global.js +9 -9
  3. package/dist/bk-rum.global.js.map +1 -1
  4. package/dist/core/action-activity.d.ts +28 -0
  5. package/dist/core/config.d.ts +113 -93
  6. package/dist/core/page-activity.d.ts +14 -0
  7. package/dist/core/plugin.d.ts +23 -6
  8. package/dist/core/processor.d.ts +25 -4
  9. package/dist/core/request-timing.d.ts +5 -0
  10. package/dist/core/runtime-context.d.ts +51 -3
  11. package/dist/core/sampling.d.ts +5 -1
  12. package/dist/core/sdk.d.ts +29 -10
  13. package/dist/core/url.d.ts +4 -1
  14. package/dist/index.d.ts +12 -14
  15. package/dist/index.js +2184 -1175
  16. package/dist/index.js.map +1 -1
  17. package/dist/plugins/action.d.ts +6 -2
  18. package/dist/plugins/activity.d.ts +6 -0
  19. package/dist/plugins/blank-screen.d.ts +17 -0
  20. package/dist/plugins/common.d.ts +11 -3
  21. package/dist/plugins/device.d.ts +2 -0
  22. package/dist/plugins/long-task.d.ts +3 -12
  23. package/dist/plugins/page-view.d.ts +1 -0
  24. package/dist/plugins/request-body.d.ts +14 -0
  25. package/dist/plugins/resource.d.ts +17 -1
  26. package/dist/plugins/session-state.d.ts +18 -0
  27. package/dist/plugins/session.d.ts +4 -4
  28. package/dist/plugins/web-vitals.d.ts +74 -0
  29. package/dist/schema/attributes.d.ts +31 -10
  30. package/dist/schema/span.d.ts +4 -12
  31. package/package.json +3 -7
  32. package/skills/bk-rum-otele/SKILL.md +39 -33
  33. package/skills/bk-rum-otele/evals/evals.json +3 -3
  34. package/skills/bk-rum-otele/references/api.md +247 -114
  35. package/skills/bk-rum-otele/references/architecture.md +141 -0
  36. package/skills/bk-rum-otele/references/capabilities.md +100 -0
  37. package/skills/bk-rum-otele/references/concepts.md +40 -111
  38. package/skills/bk-rum-otele/references/configuration.md +202 -254
  39. package/skills/bk-rum-otele/references/custom-plugin.md +22 -7
  40. package/skills/bk-rum-otele/references/data-model.md +17 -10
  41. package/skills/bk-rum-otele/references/framework-integration.md +25 -17
  42. package/skills/bk-rum-otele/references/getting-started.md +42 -86
  43. package/skills/bk-rum-otele/references/plugins.md +232 -138
  44. package/skills/bk-rum-otele/references/privacy.md +47 -34
  45. package/skills/bk-rum-otele/references/telemetry-reference.md +74 -45
  46. package/skills/bk-rum-otele/references/transport-sampling.md +79 -0
  47. package/skills/bk-rum-otele/references/troubleshooting.md +71 -37
  48. package/dist/plugins/http-body.d.ts +0 -3
  49. package/dist/plugins/route-timing.d.ts +0 -2
@@ -1,6 +1,10 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
- export type BkOTActionEventName = 'click' | 'input' | 'keydown' | 'pointerdown' | 'scroll' | 'submit';
3
2
  export interface BkOTActionPluginOptions {
4
- eventNames?: BkOTActionEventName[];
3
+ actionNameAttribute?: string;
4
+ maxDuration?: number;
5
+ /** 默认仅采集显式 data 属性;设为 text 才会读取可访问名称和 DOM 文本。 */
6
+ nameCollection?: 'explicit' | 'text';
5
7
  }
8
+ export declare const getActionNameFromElement: (target: Element, actionNameAttribute?: string, includeText?: boolean) => string;
9
+ export declare const isDeadClickExcluded: (target: Element) => boolean;
6
10
  export declare const createActionPlugin: (options?: BkOTActionPluginOptions) => BkOTPlugin;
@@ -0,0 +1,6 @@
1
+ import type { BkOTPlugin } from '../core/plugin';
2
+ export declare const EXCLUDED_ACTIVITY_MUTATIONS_ATTRIBUTE = "data-bk-excluded-activity-mutations";
3
+ /**
4
+ * 页面级 DOM 活动只观察一次,再通过运行时活动总线分发给 View、Action 和白屏检测。
5
+ */
6
+ export declare const createActivityPlugin: () => BkOTPlugin;
@@ -1,8 +1,25 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
2
  export interface BkOTBlankScreenPluginOptions {
3
+ /** 页面活动稳定后首次检查的延迟,默认 1000ms。 */
3
4
  checkDelay?: number;
5
+ /** 两次空白结果之间的确认间隔,默认 200ms。 */
6
+ confirmationDelay?: number;
7
+ /** loading、骨架屏等不参与空白比例计算的元素。 */
4
8
  ignoreSelectors?: string[];
9
+ /** 应用挂载根节点,默认 body。根节点不存在本身会被判为候选白屏。 */
5
10
  rootSelector?: string;
11
+ /** 空白采样点比例阈值,默认 0.8。 */
6
12
  threshold?: number;
7
13
  }
14
+ interface DetectionResult {
15
+ centerElement: string;
16
+ emptyCount: number;
17
+ ignoredCount: number;
18
+ reason: 'empty_viewport' | 'missing_root';
19
+ rootFound: boolean;
20
+ score: number;
21
+ validCount: number;
22
+ }
23
+ export declare const detectBlankScreen: (rootSelector: string, ignoredSelectors: string[]) => DetectionResult;
8
24
  export declare const createBlankScreenPlugin: (options?: BkOTBlankScreenPluginOptions) => BkOTPlugin;
25
+ export {};
@@ -1,3 +1,11 @@
1
- import type { BkOTInstrumentationsConfig } from '../core/config';
2
- import type { BkOTPlugin } from '../core/plugin';
3
- export declare const createCommonInstrumentationsPlugin: (option?: BkOTInstrumentationsConfig) => BkOTPlugin;
1
+ import { REQUEST_DISCARD_ATTRIBUTE } from '../core/processor';
2
+ import type { BkOTRequestConfig, BkOTRequestContext } from '../core/config';
3
+ import type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';
4
+ import type { Span } from '@opentelemetry/api';
5
+ interface RequestDetails {
6
+ method?: string;
7
+ url?: string;
8
+ }
9
+ export { REQUEST_DISCARD_ATTRIBUTE };
10
+ export declare const decorateRequestSpan: (context: BkOTRuntimeContext, span: Span, subtype: "fetch" | "xhr", domainContext: BkOTRequestContext, details?: RequestDetails, fetchRequest?: Request | RequestInit) => void;
11
+ export declare const createCommonInstrumentationsPlugin: (option: BkOTRequestConfig | boolean | undefined) => BkOTPlugin;
@@ -1,5 +1,7 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
2
  export interface BkOTDevicePluginOptions {
3
+ /** 是否跨页面持久化匿名设备 ID,默认 false。 */
4
+ persistentId?: boolean;
3
5
  storageKey?: string;
4
6
  }
5
7
  /**
@@ -1,17 +1,8 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
2
  export interface BkOTLongTaskPluginOptions {
3
+ /** 采集阈值,默认 50ms。Performance API 本身通常只产生大于 50ms 的条目。 */
3
4
  threshold?: number;
5
+ /** 标记 warning 的阈值,默认 100ms。 */
6
+ warningThreshold?: number;
4
7
  }
5
- /**
6
- * Long Task 监控插件,通过 PerformanceObserver 捕获主线程上 >= threshold(默认 50ms)的长任务,
7
- * 上报为 metric(counter + duration histogram),用于评估页面卡顿趋势。
8
- *
9
- * 使用建议:
10
- * - 默认关闭,建议在性能敏感模块按需开启。
11
- * - PerformanceObserver 使用 `buffered: true`,能拿到 observer 创建之前已发生的 longtask,避免漏掉早期阶段。
12
- *
13
- * 兼容性:
14
- * - 仅在 PerformanceObserver 与 `supportedEntryTypes` 包含 `longtask` 的浏览器上启用,否则 init 直接 return;
15
- * Firefox 当前不支持 longtask,会自动跳过。
16
- */
17
8
  export declare const createLongTaskPlugin: (options?: BkOTLongTaskPluginOptions) => BkOTPlugin;
@@ -1,2 +1,3 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
+ export declare const isViewLocationChange: (fromUrl: string, toUrl: string) => boolean;
2
3
  export declare const createPageViewPlugin: () => BkOTPlugin;
@@ -0,0 +1,14 @@
1
+ import type { BkOTRequestBodyConfig, BkOTRequestContext, BkOTRequestEvent } from '../core/config';
2
+ import type { BkOTRuntimeContext } from '../core/plugin';
3
+ import type { Span } from '@opentelemetry/api';
4
+ interface CaptureRequestBodyLogOptions {
5
+ bodyConfig: BkOTRequestBodyConfig;
6
+ domainContext: BkOTRequestContext;
7
+ event: BkOTRequestEvent;
8
+ fetchRequest?: Request | RequestInit;
9
+ runtimeContext: Pick<BkOTRuntimeContext, 'emitLog'>;
10
+ span: Span;
11
+ }
12
+ export declare const prepareFetchRequestBodySource: (request: Request | RequestInit) => Request | RequestInit | undefined;
13
+ export declare const captureRequestBodyLog: ({ bodyConfig, domainContext, event, fetchRequest, runtimeContext, span, }: CaptureRequestBodyLogOptions) => Promise<void>;
14
+ export {};
@@ -1,2 +1,18 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
- export declare const createResourcePlugin: () => BkOTPlugin;
2
+ type ResourceTimingWithStatus = PerformanceResourceTiming & {
3
+ deliveryType?: string;
4
+ renderBlockingStatus?: string;
5
+ responseStatus?: number;
6
+ };
7
+ export declare const getResourceTimingAttributes: (entry: ResourceTimingWithStatus) => Record<string, number>;
8
+ export declare const getResourcePerformanceAttributes: (entry: ResourceTimingWithStatus) => {
9
+ 'resource.encoded_body_size': number;
10
+ 'resource.decoded_body_size': number;
11
+ 'resource.render_blocking_status'?: string | undefined;
12
+ 'resource.delivery_type'?: string | undefined;
13
+ transfer_size: number;
14
+ "resource.cache.hit": boolean | undefined;
15
+ "resource.protocol": string;
16
+ };
17
+ export declare const createResourcePlugin: (emitResourceSpans?: boolean) => BkOTPlugin;
18
+ export {};
@@ -0,0 +1,18 @@
1
+ export interface ActiveSessionRecord {
2
+ expiresAt: number;
3
+ id: string;
4
+ startedAt: number;
5
+ status: 'active';
6
+ }
7
+ export interface ExpiredSessionRecord {
8
+ expiredAt: number;
9
+ previousId: string;
10
+ reason: SessionExpireReason;
11
+ status: 'expired';
12
+ }
13
+ export type SessionExpireReason = 'inactivity' | 'maxLifetime';
14
+ export type SessionRecord = ActiveSessionRecord | ExpiredSessionRecord;
15
+ export declare const createActiveSessionRecord: (id: string, now: number, idleTimeoutMs: number, maxDurationMs: number) => ActiveSessionRecord;
16
+ export declare const getSessionExpireReason: (record: ActiveSessionRecord, now: number, maxDurationMs: number) => SessionExpireReason | undefined;
17
+ export declare const expandActiveSession: (record: ActiveSessionRecord, now: number, idleTimeoutMs: number, maxDurationMs: number) => ActiveSessionRecord;
18
+ export declare const parseSessionRecord: (raw: null | string, now: number, maxDurationMs: number) => null | SessionRecord;
@@ -1,7 +1,7 @@
1
1
  import type { BkOTPlugin } from '../core/plugin';
2
- export interface BkOTSessionPluginOptions {
3
- inactivityMs?: number;
4
- maxLifetimeMs?: number;
2
+ export interface BkOTSessionConfig {
3
+ /** 以 0~1 表示的 Session 采样率,默认 1。 */
4
+ sampleRate?: number;
5
5
  storageKey?: string;
6
6
  }
7
- export declare const createSessionPlugin: (options?: BkOTSessionPluginOptions) => BkOTPlugin;
7
+ export declare const createSessionPlugin: (options?: BkOTSessionConfig) => BkOTPlugin;
@@ -1,2 +1,76 @@
1
+ /**
2
+ * Web Vitals 插件
3
+ *
4
+ * 基于 google/web-vitals 库(attribution 版本)采集 Core Web Vitals:
5
+ * CLS / FCP / INP / LCP / TTFB
6
+ *
7
+ * 维度分层(关键设计):
8
+ * - metric (histogram):仅带低基数维度(`view.url_path_group` / navigation.type / vital.name / vital.rating),
9
+ * 适合做 P50 / P75 / P99 聚合统计,避免维度爆炸
10
+ * - span (browser.web_vital):带 vital.id(唯一)、vital.value 与 attribution 详情
11
+ * (LCP 元素 url / CLS shift target / INP interaction target 等高基数字段),
12
+ * 方便按个例排查"哪个元素拖累了 LCP"
13
+ *
14
+ * Histogram 设计:
15
+ * - browser.web_vital.cls:单位 '1'(无量纲),CLS 是累积分数,不能与 ms 混用
16
+ * - browser.web_vital.duration:单位 'ms',FCP/INP/LCP/TTFB 共享,靠 vital.metric 维度区分
17
+ *
18
+ * Navigation Type:
19
+ * 优先使用 metric.navigationType(web-vitals 内部计算,含 'back-forward-cache' 等准确值),
20
+ * fallback 到 PerformanceNavigationTiming.type(注意 web-vitals 用连字符 'back-forward',
21
+ * PerformanceNavigationTiming 用下划线 'back_forward',统一成连字符)。
22
+ *
23
+ * View 边界:FCP/LCP/TTFB 使用 web-vitals 的条目时间回查历史 View;CLS/INP 按 SDK View 重置,
24
+ * CLS 使用 session window,INP 使用当前 View 的 p98 交互候选。
25
+ *
26
+ * 生命周期保护:
27
+ * - disposed 标志位:shutdown 后所有回调入口 early return,避免向已销毁的 provider 上报
28
+ * - dynamic import 完成后再次检查 disposed:处理"start() 完成前 shutdown()"的 race
29
+ * - dynamic import 自身 try/catch:与 PluginManager 的 per-plugin 隔离形成纵深防御,
30
+ * 即使加载失败也不影响整体启动
31
+ */
32
+ import { type Attributes } from '@opentelemetry/api';
1
33
  import type { BkOTPlugin } from '../core/plugin';
34
+ interface EventTimingEntry extends PerformanceEntry {
35
+ interactionId?: number;
36
+ processingEnd?: number;
37
+ processingStart?: number;
38
+ target?: EventTarget | null;
39
+ }
40
+ interface LayoutShiftEntry extends PerformanceEntry {
41
+ hadRecentInput?: boolean;
42
+ sources?: Array<{
43
+ node?: Node | null;
44
+ }>;
45
+ value?: number;
46
+ }
47
+ interface ViewVitalState {
48
+ cls: number;
49
+ clsWindowEnd?: number;
50
+ clsWindowLargestShiftTarget?: string;
51
+ clsWindowLargestShiftValue: number;
52
+ clsWindowStart?: number;
53
+ clsWindowValue: number;
54
+ interactionCountAtStart?: number;
55
+ interactionIdMax: number;
56
+ interactionIdMin: number;
57
+ inpCandidates: InpCandidate[];
58
+ largestShiftTarget?: string;
59
+ largestShiftValue: number;
60
+ runtimeAttributes: Attributes;
61
+ startedAt: number;
62
+ }
63
+ interface InpCandidate {
64
+ duration: number;
65
+ inputDelay: number;
66
+ interactionId: number;
67
+ interactionTarget?: string;
68
+ interactionType: string;
69
+ presentationDelay: number;
70
+ processingDuration: number;
71
+ }
72
+ export declare const updateViewCls: (view: ViewVitalState, entry: LayoutShiftEntry) => void;
73
+ export declare const updateViewInp: (view: ViewVitalState, entry: EventTimingEntry) => void;
74
+ export declare const getViewInp: (view: ViewVitalState) => InpCandidate | undefined;
2
75
  export declare const createWebVitalsPlugin: () => BkOTPlugin;
76
+ export {};
@@ -4,26 +4,42 @@
4
4
  * 插件里不要散落硬编码字符串,后续字段命名调整只改这里,避免采集端与字段文档逐步漂移。
5
5
  */
6
6
  export declare const RUM_ATTRIBUTES: {
7
+ readonly actionErrorCount: "action.error.count";
8
+ readonly actionFrustrationCount: "action.frustration.count";
9
+ readonly actionFrustrationType: "action.frustration.type";
10
+ readonly actionId: "action.id";
11
+ readonly actionLoadingTime: "action.loading_time";
12
+ readonly actionLongTaskCount: "action.long_task.count";
13
+ readonly actionName: "action.name";
14
+ readonly actionResourceCount: "action.resource.count";
15
+ readonly actionTargetName: "action.target.name";
16
+ readonly actionTargetTag: "action.target.tag";
7
17
  readonly actionType: "action.type";
8
18
  readonly deploymentEnvironmentName: "deployment.environment.name";
9
- readonly browserName: "browser_name";
10
- readonly browserVersion: "browser_version";
11
- readonly cacheHit: "cache_hit";
12
- readonly deviceType: "device_type";
19
+ readonly browserName: "browser.name";
20
+ readonly browserVersion: "browser.version";
21
+ readonly cacheHit: "resource.cache.hit";
22
+ readonly deviceType: "device.type";
13
23
  readonly durationBucket: "duration_bucket";
14
24
  readonly errorType: "error_type";
15
25
  readonly eventLabel: "event_label";
16
26
  readonly exceptionFingerprint: "exception.fingerprint";
17
27
  readonly exceptionMessageShort: "exception.message_short";
18
28
  readonly exceptionStackTopFrame: "exception.stack_top_frame";
19
- readonly longtaskAttributionScript: "longtask.attribution_script";
20
- readonly longtaskBlockingDuration: "longtask.blocking_duration";
29
+ readonly longTaskBlockingDuration: "long_task.blocking_duration";
30
+ readonly longTaskCulprit: "long_task.culprit";
31
+ readonly longTaskDuration: "long_task.duration";
32
+ readonly longTaskEntryType: "long_task.entry_type";
33
+ readonly longTaskId: "long_task.id";
34
+ readonly longTaskIsFrozenFrame: "long_task.is_frozen_frame";
35
+ readonly longTaskScriptCount: "long_task.script.count";
36
+ readonly longTaskStartTime: "long_task.start_time";
21
37
  readonly networkEffectiveType: "network.effective_type";
22
- readonly nextHopProtocol: "next_hop_protocol";
38
+ readonly nextHopProtocol: "resource.protocol";
23
39
  readonly result: "result";
24
40
  readonly serviceName: "service.name";
25
41
  readonly serviceVersion: "service.version";
26
- readonly osName: "os_name";
42
+ readonly osName: "os.name";
27
43
  readonly sessionHasReplay: "session.has_replay";
28
44
  readonly sessionId: "session.id";
29
45
  readonly sessionStartTime: "session.start_time";
@@ -33,8 +49,6 @@ export declare const RUM_ATTRIBUTES: {
33
49
  readonly targetDomain: "target_domain";
34
50
  readonly targetLabel: "target_label";
35
51
  readonly targetPathTemplate: "target_path_template";
36
- readonly targetTag: "target.tag";
37
- readonly targetTextShort: "target.text_short";
38
52
  readonly targetValue: "target_value";
39
53
  readonly traceScene: "trace_scene";
40
54
  readonly transferSize: "transfer_size";
@@ -42,8 +56,15 @@ export declare const RUM_ATTRIBUTES: {
42
56
  readonly vitalMetric: "vital.metric";
43
57
  readonly vitalRating: "vital.rating";
44
58
  readonly vitalValue: "vital.value";
59
+ readonly viewDomComplete: "view.dom_complete";
60
+ readonly viewDomContentLoaded: "view.dom_content_loaded";
61
+ readonly viewDomInteractive: "view.dom_interactive";
62
+ readonly viewFirstByte: "view.first_byte";
45
63
  readonly viewId: "view.id";
64
+ readonly viewLoadEvent: "view.load_event";
65
+ readonly viewLoadingTime: "view.loading_time";
46
66
  readonly viewLoadingType: "view.loading_type";
67
+ readonly viewName: "view.name";
47
68
  readonly viewUrl: "view.url";
48
69
  readonly viewUrlPathGroup: "view.url_path_group";
49
70
  };
@@ -11,23 +11,16 @@ export declare const RUM_SPAN_TYPE: {
11
11
  readonly custom: "custom";
12
12
  readonly document: "document";
13
13
  readonly error: "error";
14
- readonly http: "http";
15
14
  readonly longtask: "longtask";
16
15
  readonly resource: "resource";
17
16
  readonly route: "route";
18
17
  readonly vital: "vital";
19
18
  };
20
- export interface RumHttpSpanInput {
21
- duration?: number;
22
- method?: string;
23
- statusCode?: number;
24
- subtype: 'fetch' | 'xhr';
25
- url?: string;
26
- urlPathTemplate?: string;
27
- }
28
19
  export interface RumResourceSpanInput {
29
- duration: number;
20
+ duration?: number;
30
21
  initiatorType?: string;
22
+ method?: string;
23
+ networkError?: boolean;
31
24
  responseStatus?: number;
32
25
  transferSize?: number;
33
26
  url: string;
@@ -58,5 +51,4 @@ export declare const getHttpErrorType: (statusCode: number | undefined) => "none
58
51
  export declare const getVitalResult: (rating: string | undefined) => RumSpanResult;
59
52
  export declare const getUrlTarget: (url: string | undefined, pathTemplate?: string) => RumUrlTarget;
60
53
  export declare const buildRumSpanAttributes: ({ duration, errorType, eventLabel, result, spanSubtype, spanType, targetLabel, targetValue, traceScene, }: RumSpanClassification) => Attributes;
61
- export declare const buildRumHttpSpanAttributes: ({ duration, method, statusCode, subtype, url, urlPathTemplate, }: RumHttpSpanInput) => Attributes;
62
- export declare const buildRumResourceSpanAttributes: ({ duration, initiatorType, responseStatus, transferSize, url, urlPathTemplate, }: RumResourceSpanInput) => Attributes;
54
+ export declare const buildRumResourceSpanAttributes: ({ duration, initiatorType, method, networkError, responseStatus, transferSize, url, urlPathTemplate, }: RumResourceSpanInput) => Attributes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueking/open-telemetry",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "OpenTelemetry browser SDK for BK RUM",
5
5
  "author": "TencentCloud Real User Monitoring",
6
6
  "main": "dist/index.js",
@@ -21,22 +21,18 @@
21
21
  "docs:dev": "vitepress dev wikis",
22
22
  "docs:preview": "vitepress preview wikis",
23
23
  "dev": "vite dev",
24
- "dts": "vue-tsc --project tsconfig.dts.json"
24
+ "dts": "vue-tsc --project tsconfig.dts.json",
25
+ "test:rum-context": "node --experimental-default-type=module --experimental-strip-types --test tests/action-plugin.test.mjs tests/consent.test.mjs tests/experience-plugins.test.mjs tests/request-model.test.mjs tests/runtime-context.test.mjs tests/sampling.test.mjs tests/session-state.test.ts tests/session-plugin.test.mjs tests/session-page-view.test.mjs tests/session-processors.test.mjs tests/web-vitals.test.mjs"
25
26
  },
26
27
  "dependencies": {
27
28
  "@opentelemetry/api": "^1.9.1",
28
29
  "@opentelemetry/api-logs": "^0.217.0",
29
- "@opentelemetry/auto-instrumentations-web": "^0.62.0",
30
30
  "@opentelemetry/context-zone": "2.7.1",
31
31
  "@opentelemetry/core": "^2.7.1",
32
32
  "@opentelemetry/exporter-logs-otlp-http": "^0.217.0",
33
33
  "@opentelemetry/exporter-metrics-otlp-http": "^0.217.0",
34
34
  "@opentelemetry/exporter-trace-otlp-http": "^0.217.0",
35
35
  "@opentelemetry/instrumentation": "^0.217.0",
36
- "@opentelemetry/instrumentation-document-load": "^0.62.0",
37
- "@opentelemetry/instrumentation-fetch": "^0.217.0",
38
- "@opentelemetry/instrumentation-user-interaction": "^0.61.0",
39
- "@opentelemetry/instrumentation-xml-http-request": "^0.217.0",
40
36
  "@opentelemetry/resources": "^2.7.1",
41
37
  "@opentelemetry/sdk-logs": "^0.217.0",
42
38
  "@opentelemetry/sdk-metrics": "^2.7.1",
@@ -11,7 +11,7 @@ description: 帮助业务方在前端应用里接入、使用和配置蓝鲸 RUM
11
11
 
12
12
  ## 怎么用本 skill
13
13
 
14
- 1. 先读下面的「核心心智模型」,它是理解一切配置的前提,尤其是 Instrumentation 与 Plugin 在采样上的差异——这是最容易踩坑的地方。
14
+ 1. 先读下面的「核心心智模型」,它是理解入口分组、采样和信号关联的前提。
15
15
  2. 再按「任务路由」跳到对应的 `references/*.md` 拿完整细节和可复制的代码示例。不要凭记忆写配置,`references` 是权威来源。
16
16
  3. 给出配置时,默认从最小接入起步,再按用户实际诉求逐项打开能力,避免一次性堆满所有插件。
17
17
 
@@ -19,19 +19,22 @@ description: 帮助业务方在前端应用里接入、使用和配置蓝鲸 RUM
19
19
 
20
20
  根据用户诉求,读取对应参考文件(都在本 skill 的 `references/` 下):
21
21
 
22
- | 用户想做的事 | 读取 |
23
- | --- | --- |
24
- | 第一次接入、安装、最小示例、CDN、生产推荐配置 | `references/getting-started.md` |
25
- | 搞懂三类信号、Instrumentation vs Plugin、采样、数据归一、运行时上下文 | `references/concepts.md` |
26
- | 查配置项、默认值、transport/endpoint、采样、批量上报、traceparent 透传 | `references/configuration.md` |
27
- | 开关某个采集能力、看插件清单和各插件参数(error/blankScreen/httpBody/longTask/websocket 等) | `references/plugins.md` |
28
- | 写自定义插件、接入第三方 OpenTelemetry instrumentation | `references/custom-plugin.md` |
29
- | 查公开 API(start/flush/shutdown/setUser/setView/reportAction/reportCustomEvent 等) | `references/api.md` |
30
- | Vue / React / Vue Router / 微前端 集成 | `references/framework-integration.md` |
31
- | URL 脱敏、属性脱敏、公共属性、低基数路由、user.id 处理 | `references/privacy.md` |
32
- | 了解上报字段、span_type/result/duration_bucket、哪些字段是后端派生 | `references/data-model.md` |
33
- | 查具体的 span 名 / metric 名 / log 事件名、完整属性字典 | `references/telemetry-reference.md` |
34
- | 本地看不到数据、手动事件没上报、白屏误报、接口 span 太多等排障 | `references/troubleshooting.md` |
22
+ | 用户想做的事 | 读取 |
23
+ | ------------------------------------------------------------------------------------------- | ------------------------------------- |
24
+ | 第一次接入、安装、最小示例、CDN、生产推荐配置 | `references/getting-started.md` |
25
+ | 评估 SDK 能力边界、默认开关、浏览器 API、信号产出和降级行为 | `references/capabilities.md` |
26
+ | 理解源码模块、初始化顺序、运行时上下文、过滤链路和 Hook 时机 | `references/architecture.md` |
27
+ | 搞懂三类信号、Instrumentation vs Plugin、采样、数据归一、运行时上下文 | `references/concepts.md` |
28
+ | 查配置项、默认值、Endpoint、插件参数和 Hook | `references/configuration.md` |
29
+ | 查 Transport、单信号开关、批量上报、Session 采样和 traceparent 透传 | `references/transport-sampling.md` |
30
+ | 开关某个采集能力、看请求配置和各插件参数(request/error/blankScreen/longTask/websocket 等) | `references/plugins.md` |
31
+ | 写自定义插件、接入第三方 OpenTelemetry instrumentation | `references/custom-plugin.md` |
32
+ | 查公开 API(start/flush/shutdown/setUser/setView/reportAction/reportCustomEvent 等) | `references/api.md` |
33
+ | Vue / React / Vue Router / 微前端 集成 | `references/framework-integration.md` |
34
+ | URL 脱敏、属性脱敏、公共属性、低基数路由、user.id 处理 | `references/privacy.md` |
35
+ | 了解上报字段、span_type/result/duration_bucket、哪些字段是后端派生 | `references/data-model.md` |
36
+ | 查具体的 span 名 / metric 名 / log 事件名、完整属性字典 | `references/telemetry-reference.md` |
37
+ | 本地看不到数据、手动事件没上报、白屏误报、接口 span 太多等排障 | `references/troubleshooting.md` |
35
38
 
36
39
  > `references/` 由 `packages/open-telemetry/scripts/gen-skill-references.mjs` 从 SDK 的 `wikis/` 自动生成,请勿手改。如内容过期,让维护者重新执行 `pnpm --filter @blueking/open-telemetry skill:refs`。
37
40
 
@@ -43,24 +46,24 @@ description: 帮助业务方在前端应用里接入、使用和配置蓝鲸 RUM
43
46
  - **Metric**:可聚合的数值——Web Vitals、长任务数、WebSocket 消息大小、白屏结果。
44
47
  - **Log**:离散事件——错误、CSP 违规、会话生命周期、HTTP body 错误路径。
45
48
 
46
- ### Instrumentation 与 Plugin(最关键区别)
49
+ ### 内置采集与扩展
47
50
 
48
- SDK 把采集能力拆成两类,配置分别挂在顶层 `instrumentations` 和 `plugins` 下:
51
+ SDK 把能力拆成两类:
49
52
 
50
- - **Instrumentation**:OpenTelemetry 官方探针(`documentLoad`、`fetch`、`xhr`、`userInteraction`),负责 patch 浏览器原生 API。**只要 `enabled !== false` 就装载,不受采样影响。**
51
- - **Plugin**:bk-ot 自研的 RUM 能力单元(`pageView`、`resource`、`error`、`webVitals` 等),基于运行时上下文主动产生 RUM 归一数据。**产生 RUM 数据的插件只在会话命中采样时才启动。**
53
+ - **内置采集**:统一放在 `tracking`,包括 View、请求、资源、错误、Web Vitals、Action 等;其中 Fetch/XHR 由 SDK 自有的单一请求生命周期直接 patch,统一创建 `browser.resource` CLIENT Span。
54
+ - **扩展**:接入方的 RUM 插件放在 `extensions.plugins`,标准 OpenTelemetry instrumentation 放在 `extensions.instrumentations`。它们都使用 SDK 私有 provider,并遵循 Consent 生命周期。
52
55
 
53
- ### 会话级 sticky 采样
56
+ ### 会话级确定性采样
54
57
 
55
- `sampling.rate`(0–1,默认 1)是**会话级** sticky 采样,不是 trace 级。一次会话命中后 RUM 插件和手动事件都会上报;未命中时主动产生数据的插件不启动,`reportAction()`、`reportCustomEvent()` 会被静默丢弃。调试时临时设 `rate: 1` 和 `debug: true`。
58
+ `session.sampleRate`(0–1,默认 1)是**会话级确定性采样**,不是 trace 级。决定由 `application.name + session.id` 的稳定 hash 得出,同一 Session 的 span/log/metric 决定一致。插件仍维护必要的浏览器生命周期,但未命中时数据不会导出,`reportAction()`、`reportCustomEvent()` 会被静默丢弃。调试时临时设 `sampleRate: 1` 和 `debug: true`。
56
59
 
57
60
  ### 运行时上下文
58
61
 
59
- SDK 维护公共上下文并自动挂到后续 span/log/metric 上:`user.id`(业务方提供,SDK 原样透传、不 hash 不脱敏)、`session.id`(session 插件生成/轮换)、`view.*`(pageView 插件维护)。运行中可用 `setUser()` / `setView()` 更新。
62
+ SDK 维护公共上下文并自动挂到后续 span/log 上:`user.id`(业务方提供,SDK 原样透传、不 hash 不脱敏)、`session.id`(Session 生成/轮换)、`view.*`(View 管理器维护)。Metric 只保留 `view.url_path_group` 等低基数维度,不携带唯一 `session.id` / `view.id` / `action.id`;精确关联使用对应 span 或 View Snapshot Log。运行中可用 `setUser()` 更新用户;手动 View 使用 `startView()` 划界、`setViewName()` 改名。
60
63
 
61
64
  ### 数据归一
62
65
 
63
- SDK 为 span 补充归一字段便于统一检索:`span_type`(document/http/resource/vital/error/longtask/action/route/custom)、`result`(success/warning/error/timeout/abort)、`duration_bucket`、`target_label` 等。
66
+ SDK 为 span 补充归一字段便于统一检索:`span_type`(document/resource/vital/error/longtask/action/route/custom)、`result`(success/warning/error/timeout/abort)、`duration_bucket`、`target_label` 等。Fetch/XHR 与静态资源统一为 resource,通过 `resource.type` 区分。
64
67
 
65
68
  ## 最小接入速查
66
69
 
@@ -70,9 +73,9 @@ npm:
70
73
  import { BkOpenTelemetry } from '@blueking/open-telemetry';
71
74
 
72
75
  const bkOT = new BkOpenTelemetry({
73
- app: { name: 'demo-app', environment: 'production', version: '1.0.0' },
76
+ application: { name: 'demo-app', environment: 'production', version: '1.0.0' },
74
77
  transport: { endpoint: 'https://your-otlp-collector', token: 'your-report-token' },
75
- user: { id: window.USER_ID },
78
+ context: { user: { id: window.USER_ID } },
76
79
  });
77
80
  ```
78
81
 
@@ -82,27 +85,30 @@ CDN:
82
85
  <script src="https://unpkg.com/@blueking/open-telemetry/dist/bk-rum.global.js"></script>
83
86
  <script>
84
87
  new window.BkOpenTelemetry({
85
- app: { name: 'demo-app', environment: 'production' },
88
+ application: { name: 'demo-app', environment: 'production' },
86
89
  transport: { endpoint: 'https://your-otlp-collector', token: 'your-report-token' },
87
90
  });
88
91
  </script>
89
92
  ```
90
93
 
91
- `transport.endpoint` 填上报根地址(不含路径前缀),SDK 自动拼 `/v1/rum`、`/v1/metrics`、`/v1/logs`;若通过 `transport.signals.endpoints` 或单信号 `endpoint` 自定义了某一类地址,则该信号使用自定义 URL,不再拼接。`token` 作为 `Authorization: Bearer <token>` 默认头。构造后默认 `autoStart: true` 自动启动,无需手动 `start()`。
94
+ `transport.endpoint` 可提供上报根地址(不含路径前缀),SDK 自动拼 `/v1/rum`、`/v1/metrics`、`/v1/logs`;若通过 `transport.signals.{traces|metrics|logs}.endpoint` 自定义某一类地址,则该信号使用完整 URL,不再拼接。当所有已开启信号都有独立地址时,根 endpoint 可省略。三类信号可分别设为 `false` 关闭,但不能全部关闭。`token` 作为 `Authorization: Bearer <token>` 默认头。构造后默认 `autoStart: true` 自动启动,无需手动 `start()`。
92
95
 
93
96
  ## 默认采集能力清单
94
97
 
95
- 只配 `app` + `transport` 即默认开启:
98
+ 只配 `application` + `transport` 即默认开启:
96
99
 
97
- - Instrumentation:`documentLoad`、`fetch`、`xhr`、`userInteraction`
98
- - Plugin:`pageView`、`resource`、`error`、`webVitals`、`blankScreen`、`device`、`session`
100
+ - 基础能力:Session、View;内置采集:`request`、`action`、`resource`、`error`、`webVitals`、`blankScreen`、`device`
99
101
 
100
- 默认关闭、按需打开:`action`、`httpBody`、`longTask`、`routeTiming`、`cspViolation`、`websocket`。关闭默认能力时显式设为 `false`。各插件参数见 `references/plugins.md`。
102
+ View Loading Time 默认开启;默认关闭、按需打开:`longTask`、`cspViolation`、`websocket`。关闭默认能力时显式设为 `false`。各插件参数见 `references/plugins.md`。
101
103
 
102
104
  ## 关键易错点
103
105
 
104
- - **单实例**:`fetch`/`xhr`/`userInteraction`/`websocket` 会 patch 全局 API,同页面只应初始化一个 SDK 实例,微前端只在主应用初始化一次。
106
+ - **单实例**:`fetch`/`xhr`/`action`/`websocket` 会 patch 或监听全局 API,同页面只应初始化一个 SDK 实例,微前端只在主应用初始化一次。
105
107
  - **`use()` / `useInstrumentation()` 必须在 `start()` 之前**:要注册自定义插件或 instrumentation,请设 `autoStart: false` 再手动 `start()`。
106
108
  - **采样影响手动上报**:未命中采样时 `reportAction()` / `reportCustomEvent()` 静默丢弃,排查时先确认采样。
107
- - **隐私要业务显式配置**:SDK 不猜哪些字段敏感,URL、属性、HTTP body 脱敏都需通过 `privacy` / `httpBody.redact` 显式处理;`user.id` 需 hash 的话要在传入前处理。
108
- - **低基数路由**:用 `route.getPathGroup` 把 `/user/123` 归类成 `/user/:id`,避免高基数 URL 污染指标维度。
109
+ - **隐私要业务显式配置**:SDK 不猜哪些字段敏感,URL、属性需通过 `privacy` / `request.beforeSend` 显式处理;HTTP body 默认关闭,显式配置 `request.body` 时必须提供 `redact`,默认只采集错误请求;`user.id` 需 hash 的话要在传入前处理。
110
+ - **Consent**:未授权初始化时配置 `privacy.trackingConsent: 'not-granted'`,用户授权后调用 `setTrackingConsent('granted')`;撤销授权会停止采集并解除 patch。
111
+ - **信号开关**:`transport.signals.traces/metrics/logs` 设为 `false` 可关闭对应导出链路;关闭 Trace 后不会注入 `traceparent`。只开 Metric 时没有精确 View 下钻。
112
+ - **低基数路由**:用 `tracking.view.getPathGroup` 把 `/user/123` 归类成 `/user/:id`,避免高基数 URL 污染指标维度。
113
+ - **手动 View 的时机**:使用 `autoStart: false`,先 `await start()` 建立 Session,再调用 `startView()`;启动前调用会因没有有效采样 Session 而被忽略。
114
+ - **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 接入代码:app/transport(endpoint+token)、sampling.rate=0.2、blankScreen.rootSelector='#app'、privacy.redactUrl 脱敏 token、通过 route.getPathGroup 或 vue-router afterEach + setView 追踪 SPA 路由。API/配置项名称需与 SDK 实际一致。",
8
+ "expected_output": "给出使用 @blueking/open-telemetry 的 BkOpenTelemetry 接入代码:application/transport(endpoint+token)、session.sampleRate=0.2、tracking.blankScreen.rootSelector='#app'、privacy.redactUrl 脱敏 token、通过 tracking.view.getPathGroup 自动追踪或 manual + await start() + startView() 对接 vue-router。API/配置项名称需与 SDK 实际一致。",
9
9
  "files": [],
10
10
  "assertions": []
11
11
  },
@@ -13,7 +13,7 @@
13
13
  "id": 1,
14
14
  "name": "local-no-data-troubleshoot",
15
15
  "prompt": "我按文档接了 bk-rum,本地起了 collector 在 4318,但 Network 里没看到 /rum 请求,reportCustomEvent 也没上报,debug 我也开了。可能是什么问题?怎么排查?",
16
- "expected_output": "排障应覆盖:sampling.rate 是会话级 sticky 采样、未命中时插件不启动且手动事件静默丢弃(建议调试设 rate:1);enabled 是否为 false;建议 spanProcessor:'simple' 便于本地看数据;检查 collector 是否监听 4318、endpoint 是否正确。",
16
+ "expected_output": "排障应覆盖:session.sampleRate 是会话级确定性采样,未命中时手动事件静默丢弃(建议调试设 sampleRate:1);enabled/Consent/有效 View 是否正常;建议 transport.signals.traces.processor:'simple';检查 collector、endpoint 与 Network 中 /v1/rum、/v1/metrics、/v1/logs。",
17
17
  "files": [],
18
18
  "assertions": []
19
19
  },
@@ -21,7 +21,7 @@
21
21
  "id": 2,
22
22
  "name": "instrumentation-vs-plugin-httpbody",
23
23
  "prompt": "配置里有 instrumentations 和 plugins 两块,fetch、error 这些好像两边都能配?它们到底有什么区别?另外我想采集接口报错时的请求/响应 body 来排查问题,该怎么配、要注意什么?",
24
- "expected_output": "正确区分 Instrumentation(官方探针,patch 原生 API,不受采样影响)与 Plugin(自研 RUM 数据,受会话级采样影响);指出 fetch/xhr 属 instrumentations、error 属 plugins;httpBody 默认关闭、只在错误路径(>=400/抛错)采集 body,需配 maxBodySize 与 redact 脱敏,提醒敏感信息处理。",
24
+ "expected_output": "正确区分内置 tracking、RUM Plugin 与额外 OTel Instrumentation;指出当前 request 是 SDK 自有 Fetch/XHR patch,生成 browser.resource CLIENT Span,不使用官方 Fetch/XHR instrumentation;说明 excludedUrls、allowedTracingUrls、request.beforeSend;HTTP body 默认关闭,显式配置 tracking.request.body 后默认只采集错误请求,必须配置 redact,并限制 Content-Type 和大小。",
25
25
  "files": [],
26
26
  "assertions": []
27
27
  }