@blueking/open-telemetry 0.0.1 → 0.0.4
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/package.json +5 -3
- package/playground/App.vue +0 -148
- package/playground/bk-ot.ts +0 -110
- package/playground/components/DemoLogPanel.vue +0 -89
- package/playground/composables/use-demo-log.ts +0 -39
- package/playground/index.html +0 -13
- package/playground/main.ts +0 -36
- package/playground/mock/index.ts +0 -43
- package/playground/pages/BlankScreenDemo.vue +0 -97
- package/playground/pages/BusinessDemo.vue +0 -74
- package/playground/pages/CustomPluginDemo.vue +0 -104
- package/playground/pages/ErrorDemo.vue +0 -75
- package/playground/pages/Home.vue +0 -133
- package/playground/pages/HttpDemo.vue +0 -120
- package/playground/pages/LongTaskDemo.vue +0 -66
- package/playground/pages/WebSocketDemo.vue +0 -100
- package/playground/router/index.ts +0 -92
- package/playground/style.css +0 -180
- package/src/browser.ts +0 -44
- package/src/core/config.ts +0 -327
- package/src/core/plugin.ts +0 -97
- package/src/core/processor.ts +0 -74
- package/src/core/route-observer.ts +0 -128
- package/src/core/sampling.ts +0 -64
- package/src/core/sdk.ts +0 -327
- package/src/core/url.ts +0 -66
- package/src/index.ts +0 -55
- package/src/plugins/blank-screen.ts +0 -170
- package/src/plugins/common.ts +0 -131
- package/src/plugins/csp-violation.ts +0 -74
- package/src/plugins/device.ts +0 -91
- package/src/plugins/error.ts +0 -211
- package/src/plugins/http-body.ts +0 -437
- package/src/plugins/long-task.ts +0 -99
- package/src/plugins/page-view.ts +0 -83
- package/src/plugins/route-timing.ts +0 -89
- package/src/plugins/session.ts +0 -127
- package/src/plugins/web-vitals.ts +0 -159
- package/src/plugins/websocket.ts +0 -179
- package/tsconfig.app.json +0 -27
- package/tsconfig.dts.json +0 -13
- package/tsconfig.json +0 -7
- package/tsconfig.node.json +0 -26
- package/vite.config.ts +0 -70
package/src/index.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2017-2025 Tencent. All rights reserved.
|
|
6
|
-
*
|
|
7
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.
|
|
8
|
-
*
|
|
9
|
-
* License for 蓝鲸智云PaaS平台 (BlueKing PaaS):
|
|
10
|
-
*
|
|
11
|
-
* ---------------------------------------------------
|
|
12
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
13
|
-
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
14
|
-
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
15
|
-
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
16
|
-
*
|
|
17
|
-
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
18
|
-
* the Software.
|
|
19
|
-
*
|
|
20
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
21
|
-
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
23
|
-
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
24
|
-
* IN THE SOFTWARE.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
export {
|
|
28
|
-
type BkOTAttributesConfig,
|
|
29
|
-
type BkOTAttributeValue,
|
|
30
|
-
type BkOTBatchConfig,
|
|
31
|
-
type BkOTConfig,
|
|
32
|
-
type BkOTCustomEventPayload,
|
|
33
|
-
type BkOTHttpBodyConfig,
|
|
34
|
-
type BkOTHttpBodyRedactPayload,
|
|
35
|
-
type BkOTRedactConfig,
|
|
36
|
-
type BkOTRumConfig,
|
|
37
|
-
normalizeConfig,
|
|
38
|
-
type NormalizedBkOTConfig,
|
|
39
|
-
type SignalExporterConfig,
|
|
40
|
-
} from './core/config';
|
|
41
|
-
export { type BkOTPlugin, type BkOTRuntimeContext, createPlugin, type PluginManager } from './core/plugin';
|
|
42
|
-
export { FilteringSpanProcessor } from './core/processor';
|
|
43
|
-
export { type BkOTInstance, createBkOT, initBkOT } from './core/sdk';
|
|
44
|
-
export { createBlankScreenPlugin } from './plugins/blank-screen';
|
|
45
|
-
export { createCommonInstrumentationsPlugin } from './plugins/common';
|
|
46
|
-
export { createCspViolationPlugin } from './plugins/csp-violation';
|
|
47
|
-
export { createDevicePlugin } from './plugins/device';
|
|
48
|
-
export { createErrorPlugin } from './plugins/error';
|
|
49
|
-
export { createHttpBodyPlugin } from './plugins/http-body';
|
|
50
|
-
export { createLongTaskPlugin } from './plugins/long-task';
|
|
51
|
-
export { createPageViewPlugin } from './plugins/page-view';
|
|
52
|
-
export { createRouteTimingPlugin } from './plugins/route-timing';
|
|
53
|
-
export { createSessionPlugin } from './plugins/session';
|
|
54
|
-
export { createWebVitalsPlugin } from './plugins/web-vitals';
|
|
55
|
-
export { createWebSocketPlugin } from './plugins/websocket';
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2017-2025 Tencent. All rights reserved.
|
|
6
|
-
*
|
|
7
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.
|
|
8
|
-
*
|
|
9
|
-
* License for 蓝鲸智云PaaS平台 (BlueKing PaaS):
|
|
10
|
-
*
|
|
11
|
-
* ---------------------------------------------------
|
|
12
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
13
|
-
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
14
|
-
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
15
|
-
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
16
|
-
*
|
|
17
|
-
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
18
|
-
* the Software.
|
|
19
|
-
*
|
|
20
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
21
|
-
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
23
|
-
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
24
|
-
* IN THE SOFTWARE.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
import { SeverityNumber } from '@opentelemetry/api-logs';
|
|
28
|
-
|
|
29
|
-
import type { BkOTRumConfig } from '../core/config';
|
|
30
|
-
import type { BkOTPlugin } from '../core/plugin';
|
|
31
|
-
|
|
32
|
-
const DEFAULT_SELECTOR = 'body';
|
|
33
|
-
const DEFAULT_CHECK_DELAY = 3000;
|
|
34
|
-
const DEFAULT_THRESHOLD = 0.8;
|
|
35
|
-
// 常见 loading mask / spinner 选择器,命中说明页面正在加载而非空白
|
|
36
|
-
const DEFAULT_LOADING_SELECTORS = [
|
|
37
|
-
'[data-loading="true"]',
|
|
38
|
-
'[aria-busy="true"]',
|
|
39
|
-
'.loading',
|
|
40
|
-
'.is-loading',
|
|
41
|
-
'.spinner',
|
|
42
|
-
'.skeleton',
|
|
43
|
-
'.bk-loading',
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
const SAMPLE_POINTS: Array<[number, number]> = [
|
|
47
|
-
[0.5, 0.5],
|
|
48
|
-
[0.25, 0.25],
|
|
49
|
-
[0.75, 0.25],
|
|
50
|
-
[0.25, 0.75],
|
|
51
|
-
[0.75, 0.75],
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
const getElementSelector = (element: Element | null) => {
|
|
55
|
-
if (!element) {
|
|
56
|
-
return '';
|
|
57
|
-
}
|
|
58
|
-
const tag = element.tagName.toLowerCase();
|
|
59
|
-
if (element.id) {
|
|
60
|
-
return `${tag}#${element.id}`;
|
|
61
|
-
}
|
|
62
|
-
return tag;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const matchesAny = (element: Element | null, selectors: string[]) => {
|
|
66
|
-
if (!element) return false;
|
|
67
|
-
return selectors.some(selector => {
|
|
68
|
-
try {
|
|
69
|
-
return element.matches(selector) || !!element.closest(selector);
|
|
70
|
-
} catch {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// 页面就绪后再开始计时,避免 SPA / 慢加载场景下检测时机过早
|
|
77
|
-
const whenDocumentReady = (callback: () => void) => {
|
|
78
|
-
if (typeof document === 'undefined') return;
|
|
79
|
-
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
80
|
-
callback();
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const handler = () => {
|
|
84
|
-
document.removeEventListener('DOMContentLoaded', handler);
|
|
85
|
-
callback();
|
|
86
|
-
};
|
|
87
|
-
document.addEventListener('DOMContentLoaded', handler);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const createBlankScreenPlugin = (option: BkOTRumConfig['blankScreen']): BkOTPlugin => {
|
|
91
|
-
let timer: number | undefined;
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
name: 'blank-screen',
|
|
95
|
-
enabled: Boolean(option),
|
|
96
|
-
init(context) {
|
|
97
|
-
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const optionObj = typeof option === 'object' ? option : {};
|
|
102
|
-
const rootSelector = optionObj.rootSelector ?? DEFAULT_SELECTOR;
|
|
103
|
-
const checkDelay = optionObj.checkDelay ?? DEFAULT_CHECK_DELAY;
|
|
104
|
-
const threshold = optionObj.threshold ?? DEFAULT_THRESHOLD;
|
|
105
|
-
const loadingSelectors = [...DEFAULT_LOADING_SELECTORS, ...(optionObj.ignoreSelectors ?? [])];
|
|
106
|
-
|
|
107
|
-
// 仅创建一次 counter,避免每次回调都触发一次 meter lookup
|
|
108
|
-
const counter = context.meter.createCounter('browser.blank_screen.count', {
|
|
109
|
-
description: 'Number of suspected blank screen detections',
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
whenDocumentReady(() => {
|
|
113
|
-
timer = window.setTimeout(() => {
|
|
114
|
-
const root = document.querySelector(rootSelector);
|
|
115
|
-
let emptyCount = 0;
|
|
116
|
-
let loadingCount = 0;
|
|
117
|
-
|
|
118
|
-
for (const [x, y] of SAMPLE_POINTS) {
|
|
119
|
-
const element = document.elementFromPoint(window.innerWidth * x, window.innerHeight * y);
|
|
120
|
-
if (matchesAny(element, loadingSelectors)) {
|
|
121
|
-
loadingCount += 1;
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
if (element === root || element === document.body || element === document.documentElement) {
|
|
125
|
-
emptyCount += 1;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const score = emptyCount / SAMPLE_POINTS.length;
|
|
130
|
-
// 触发 loading mask 的样本算"非空",但若全部点都是 loading,则视为待定不上报
|
|
131
|
-
if (loadingCount === SAMPLE_POINTS.length) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const isBlank = score >= threshold;
|
|
135
|
-
const attributes = {
|
|
136
|
-
'bk.rum.blank_screen.score': score,
|
|
137
|
-
'bk.rum.blank_screen.threshold': threshold,
|
|
138
|
-
'bk.rum.blank_screen.root': rootSelector,
|
|
139
|
-
'bk.rum.blank_screen.detected': isBlank,
|
|
140
|
-
'bk.rum.blank_screen.center_element': getElementSelector(
|
|
141
|
-
document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2),
|
|
142
|
-
),
|
|
143
|
-
'bk.rum.blank_screen.dom_node_count': document.body?.getElementsByTagName('*').length ?? 0,
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
if (isBlank) {
|
|
147
|
-
counter.add(
|
|
148
|
-
1,
|
|
149
|
-
context.applyRedact({
|
|
150
|
-
// 仅放进低基数维度,center_element 等高基数字段只走 log
|
|
151
|
-
'bk.rum.blank_screen.root': rootSelector,
|
|
152
|
-
}),
|
|
153
|
-
);
|
|
154
|
-
context.emitLog({
|
|
155
|
-
severityNumber: SeverityNumber.ERROR,
|
|
156
|
-
severityText: 'ERROR',
|
|
157
|
-
body: 'browser.blank_screen',
|
|
158
|
-
attributes,
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}, checkDelay);
|
|
162
|
-
});
|
|
163
|
-
},
|
|
164
|
-
shutdown() {
|
|
165
|
-
if (timer !== undefined && typeof window !== 'undefined') {
|
|
166
|
-
window.clearTimeout(timer);
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
};
|
package/src/plugins/common.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
3
|
-
/*
|
|
4
|
-
* Tencent is pleased to support the open source community by making
|
|
5
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
|
|
6
|
-
*
|
|
7
|
-
* Copyright (C) 2017-2025 Tencent. All rights reserved.
|
|
8
|
-
*
|
|
9
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.
|
|
10
|
-
*
|
|
11
|
-
* License for 蓝鲸智云PaaS平台 (BlueKing PaaS):
|
|
12
|
-
*
|
|
13
|
-
* ---------------------------------------------------
|
|
14
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
15
|
-
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
16
|
-
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
17
|
-
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
18
|
-
*
|
|
19
|
-
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
20
|
-
* the Software.
|
|
21
|
-
*
|
|
22
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
23
|
-
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
25
|
-
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
26
|
-
* IN THE SOFTWARE.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
import { type Instrumentation, registerInstrumentations } from '@opentelemetry/instrumentation';
|
|
30
|
-
|
|
31
|
-
import { shouldIgnoreUrl, shouldPropagateTraceHeader } from '../core/url';
|
|
32
|
-
|
|
33
|
-
import type { BkOTInstrumentationsConfig } from '../core/config';
|
|
34
|
-
import type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';
|
|
35
|
-
|
|
36
|
-
const URL_KEYS = ['http.url', 'url.full'];
|
|
37
|
-
|
|
38
|
-
// OTel 官方 instrumentation 内部对每个 URL 调用 matcher.test(url),
|
|
39
|
-
// 这里把"用户函数 + 自身 endpoint 过滤"包装成具备 .test 的对象,是与 OTel 一致的扩展用法
|
|
40
|
-
const toUrlPredicateMatcher = (predicate: (url: string) => boolean): RegExp =>
|
|
41
|
-
({ test: predicate }) as unknown as RegExp;
|
|
42
|
-
|
|
43
|
-
// 对官方 instrumentation 创建的 span,统一附加 page attributes 与 URL 脱敏
|
|
44
|
-
const decorateSpan = (
|
|
45
|
-
context: BkOTRuntimeContext,
|
|
46
|
-
span: {
|
|
47
|
-
attributes?: Record<string, any>;
|
|
48
|
-
setAttribute: (key: string, value: any) => void;
|
|
49
|
-
setAttributes: (attrs: Record<string, any>) => void;
|
|
50
|
-
},
|
|
51
|
-
) => {
|
|
52
|
-
span.setAttributes(context.applyRedact(context.config.getPageAttributes()));
|
|
53
|
-
for (const key of URL_KEYS) {
|
|
54
|
-
const value = span.attributes?.[key];
|
|
55
|
-
if (typeof value === 'string') {
|
|
56
|
-
const redactedAttributes = context.applyRedact({ [key]: context.config.redactUrl(value) });
|
|
57
|
-
const redactedUrl = redactedAttributes[key];
|
|
58
|
-
if (typeof redactedUrl === 'string') {
|
|
59
|
-
span.setAttribute(key, redactedUrl);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const createCommonInstrumentationsPlugin = (option: BkOTInstrumentationsConfig): BkOTPlugin => {
|
|
66
|
-
const instrumentations: Instrumentation[] = [];
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
name: 'official-instrumentations',
|
|
70
|
-
enabled: Boolean(option.documentLoad || option.fetch || option.xhr || option.userInteraction),
|
|
71
|
-
async init(context) {
|
|
72
|
-
const loadedInstrumentations: Instrumentation[] = [];
|
|
73
|
-
const ignoreUrls = [toUrlPredicateMatcher(url => shouldIgnoreUrl(context.config, url))];
|
|
74
|
-
const propagateTraceHeaderCorsUrls = [
|
|
75
|
-
toUrlPredicateMatcher(url => shouldPropagateTraceHeader(context.config, url)),
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
if (option.documentLoad) {
|
|
79
|
-
const { DocumentLoadInstrumentation } = await import('@opentelemetry/instrumentation-document-load');
|
|
80
|
-
loadedInstrumentations.push(
|
|
81
|
-
new DocumentLoadInstrumentation({
|
|
82
|
-
semconvStabilityOptIn: 'http',
|
|
83
|
-
}),
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (option.fetch) {
|
|
88
|
-
const { FetchInstrumentation } = await import('@opentelemetry/instrumentation-fetch');
|
|
89
|
-
loadedInstrumentations.push(
|
|
90
|
-
new FetchInstrumentation({
|
|
91
|
-
applyCustomAttributesOnSpan: span => decorateSpan(context, span as any),
|
|
92
|
-
ignoreUrls,
|
|
93
|
-
propagateTraceHeaderCorsUrls,
|
|
94
|
-
semconvStabilityOptIn: 'http',
|
|
95
|
-
ignoreNetworkEvents: false,
|
|
96
|
-
}),
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (option.xhr) {
|
|
101
|
-
const { XMLHttpRequestInstrumentation } = await import('@opentelemetry/instrumentation-xml-http-request');
|
|
102
|
-
loadedInstrumentations.push(
|
|
103
|
-
new XMLHttpRequestInstrumentation({
|
|
104
|
-
applyCustomAttributesOnSpan: span => decorateSpan(context, span as any),
|
|
105
|
-
ignoreUrls,
|
|
106
|
-
propagateTraceHeaderCorsUrls,
|
|
107
|
-
semconvStabilityOptIn: 'http',
|
|
108
|
-
ignoreNetworkEvents: false,
|
|
109
|
-
}),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (option.userInteraction) {
|
|
114
|
-
const { UserInteractionInstrumentation } = await import('@opentelemetry/instrumentation-user-interaction');
|
|
115
|
-
const userInteractionConfig =
|
|
116
|
-
typeof option.userInteraction === 'object'
|
|
117
|
-
? { eventNames: option.userInteraction.eventNames as Array<keyof HTMLElementEventMap> }
|
|
118
|
-
: undefined;
|
|
119
|
-
loadedInstrumentations.push(new UserInteractionInstrumentation(userInteractionConfig));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
instrumentations.push(...loadedInstrumentations);
|
|
123
|
-
registerInstrumentations({ instrumentations: loadedInstrumentations });
|
|
124
|
-
},
|
|
125
|
-
shutdown() {
|
|
126
|
-
while (instrumentations.length) {
|
|
127
|
-
instrumentations.pop()?.disable?.();
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2017-2025 Tencent. All rights reserved.
|
|
6
|
-
*
|
|
7
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.
|
|
8
|
-
*
|
|
9
|
-
* License for 蓝鲸智云PaaS平台 (BlueKing PaaS):
|
|
10
|
-
*
|
|
11
|
-
* ---------------------------------------------------
|
|
12
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
13
|
-
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
14
|
-
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
15
|
-
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
16
|
-
*
|
|
17
|
-
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
18
|
-
* the Software.
|
|
19
|
-
*
|
|
20
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
21
|
-
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
23
|
-
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
24
|
-
* IN THE SOFTWARE.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
import { SeverityNumber } from '@opentelemetry/api-logs';
|
|
28
|
-
|
|
29
|
-
import type { BkOTRumConfig } from '../core/config';
|
|
30
|
-
import type { BkOTPlugin } from '../core/plugin';
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* 监听 CSP 违规事件并以 log 形式上报,便于排查脚本/资源被 CSP 拦截的问题。
|
|
34
|
-
*/
|
|
35
|
-
export const createCspViolationPlugin = (enabled: BkOTRumConfig['cspViolation']): BkOTPlugin => {
|
|
36
|
-
let teardown: (() => void) | undefined;
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
name: 'csp-violation',
|
|
40
|
-
enabled: Boolean(enabled),
|
|
41
|
-
init(context) {
|
|
42
|
-
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handler = (event: SecurityPolicyViolationEvent) => {
|
|
47
|
-
context.emitLog({
|
|
48
|
-
severityNumber: SeverityNumber.WARN,
|
|
49
|
-
severityText: 'WARN',
|
|
50
|
-
body: 'csp.violation',
|
|
51
|
-
attributes: {
|
|
52
|
-
...context.config.getPageAttributes(),
|
|
53
|
-
'csp.blocked_uri': context.config.redactUrl(event.blockedURI || ''),
|
|
54
|
-
'csp.violated_directive': event.violatedDirective,
|
|
55
|
-
'csp.effective_directive': event.effectiveDirective,
|
|
56
|
-
'csp.original_policy': event.originalPolicy,
|
|
57
|
-
'csp.disposition': event.disposition,
|
|
58
|
-
'csp.source_file': context.config.redactUrl(event.sourceFile || ''),
|
|
59
|
-
'csp.line_number': event.lineNumber,
|
|
60
|
-
'csp.column_number': event.columnNumber,
|
|
61
|
-
'csp.status_code': event.statusCode,
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
document.addEventListener('securitypolicyviolation', handler);
|
|
67
|
-
teardown = () => document.removeEventListener('securitypolicyviolation', handler);
|
|
68
|
-
},
|
|
69
|
-
shutdown() {
|
|
70
|
-
teardown?.();
|
|
71
|
-
teardown = undefined;
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
};
|
package/src/plugins/device.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2017-2025 Tencent. All rights reserved.
|
|
6
|
-
*
|
|
7
|
-
* 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.
|
|
8
|
-
*
|
|
9
|
-
* License for 蓝鲸智云PaaS平台 (BlueKing PaaS):
|
|
10
|
-
*
|
|
11
|
-
* ---------------------------------------------------
|
|
12
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
13
|
-
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
14
|
-
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
15
|
-
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
16
|
-
*
|
|
17
|
-
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
18
|
-
* the Software.
|
|
19
|
-
*
|
|
20
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
21
|
-
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
23
|
-
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
24
|
-
* IN THE SOFTWARE.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
import type { BkOTRumConfig } from '../core/config';
|
|
28
|
-
import type { BkOTPlugin } from '../core/plugin';
|
|
29
|
-
import type { Attributes } from '@opentelemetry/api';
|
|
30
|
-
|
|
31
|
-
// 复用旧 session 插件的 storageKey,避免升级后丢失现网累计的设备标识
|
|
32
|
-
const DEFAULT_DEVICE_STORAGE_KEY = 'bk_ot_session_id';
|
|
33
|
-
|
|
34
|
-
const createId = () => {
|
|
35
|
-
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
36
|
-
return crypto.randomUUID();
|
|
37
|
-
}
|
|
38
|
-
return `device-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const readDeviceId = (storageKey: string) => {
|
|
42
|
-
try {
|
|
43
|
-
const existed = window.localStorage.getItem(storageKey);
|
|
44
|
-
if (existed) {
|
|
45
|
-
return existed;
|
|
46
|
-
}
|
|
47
|
-
const deviceId = createId();
|
|
48
|
-
window.localStorage.setItem(storageKey, deviceId);
|
|
49
|
-
return deviceId;
|
|
50
|
-
} catch {
|
|
51
|
-
return createId();
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const getViewportAttributes = (): Attributes => {
|
|
56
|
-
if (typeof window === 'undefined') {
|
|
57
|
-
return {};
|
|
58
|
-
}
|
|
59
|
-
const connection = (
|
|
60
|
-
navigator as Navigator & {
|
|
61
|
-
connection?: { effectiveType?: string; type?: string };
|
|
62
|
-
}
|
|
63
|
-
).connection;
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
'browser.viewport.width': window.innerWidth,
|
|
67
|
-
'browser.viewport.height': window.innerHeight,
|
|
68
|
-
'browser.screen.width': window.screen?.width,
|
|
69
|
-
'browser.screen.height': window.screen?.height,
|
|
70
|
-
'network.effective_type': connection?.effectiveType ?? connection?.type,
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* 设备级永久标识 + 视口 / 网络元数据。
|
|
76
|
-
* 与 session 插件区分:device 跨会话持久,session 有过期与续期。
|
|
77
|
-
*/
|
|
78
|
-
export const createDevicePlugin = (option: BkOTRumConfig['device']): BkOTPlugin => ({
|
|
79
|
-
name: 'device',
|
|
80
|
-
enabled: Boolean(option),
|
|
81
|
-
init(context) {
|
|
82
|
-
const storageKey =
|
|
83
|
-
typeof option === 'object' ? (option.storageKey ?? DEFAULT_DEVICE_STORAGE_KEY) : DEFAULT_DEVICE_STORAGE_KEY;
|
|
84
|
-
const deviceId = typeof window === 'undefined' ? createId() : readDeviceId(storageKey);
|
|
85
|
-
|
|
86
|
-
context.setRuntimeAttributes({
|
|
87
|
-
'device.id': deviceId,
|
|
88
|
-
...getViewportAttributes(),
|
|
89
|
-
});
|
|
90
|
-
},
|
|
91
|
-
});
|