@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.
Files changed (44) hide show
  1. package/package.json +5 -3
  2. package/playground/App.vue +0 -148
  3. package/playground/bk-ot.ts +0 -110
  4. package/playground/components/DemoLogPanel.vue +0 -89
  5. package/playground/composables/use-demo-log.ts +0 -39
  6. package/playground/index.html +0 -13
  7. package/playground/main.ts +0 -36
  8. package/playground/mock/index.ts +0 -43
  9. package/playground/pages/BlankScreenDemo.vue +0 -97
  10. package/playground/pages/BusinessDemo.vue +0 -74
  11. package/playground/pages/CustomPluginDemo.vue +0 -104
  12. package/playground/pages/ErrorDemo.vue +0 -75
  13. package/playground/pages/Home.vue +0 -133
  14. package/playground/pages/HttpDemo.vue +0 -120
  15. package/playground/pages/LongTaskDemo.vue +0 -66
  16. package/playground/pages/WebSocketDemo.vue +0 -100
  17. package/playground/router/index.ts +0 -92
  18. package/playground/style.css +0 -180
  19. package/src/browser.ts +0 -44
  20. package/src/core/config.ts +0 -327
  21. package/src/core/plugin.ts +0 -97
  22. package/src/core/processor.ts +0 -74
  23. package/src/core/route-observer.ts +0 -128
  24. package/src/core/sampling.ts +0 -64
  25. package/src/core/sdk.ts +0 -327
  26. package/src/core/url.ts +0 -66
  27. package/src/index.ts +0 -55
  28. package/src/plugins/blank-screen.ts +0 -170
  29. package/src/plugins/common.ts +0 -131
  30. package/src/plugins/csp-violation.ts +0 -74
  31. package/src/plugins/device.ts +0 -91
  32. package/src/plugins/error.ts +0 -211
  33. package/src/plugins/http-body.ts +0 -437
  34. package/src/plugins/long-task.ts +0 -99
  35. package/src/plugins/page-view.ts +0 -83
  36. package/src/plugins/route-timing.ts +0 -89
  37. package/src/plugins/session.ts +0 -127
  38. package/src/plugins/web-vitals.ts +0 -159
  39. package/src/plugins/websocket.ts +0 -179
  40. package/tsconfig.app.json +0 -27
  41. package/tsconfig.dts.json +0 -13
  42. package/tsconfig.json +0 -7
  43. package/tsconfig.node.json +0 -26
  44. package/vite.config.ts +0 -70
@@ -1,180 +0,0 @@
1
- /*
2
- * 全局基础样式:仅约束布局与排版,组件内细节样式靠 scoped 文件管理
3
- * 主题色统一通过 CSS 变量驱动,避免重复硬编码
4
- */
5
- :root {
6
- --color-bg: #f5f7fa;
7
- --color-surface: #fff;
8
- --color-border: #e2e8f0;
9
- --color-text-primary: #1f2937;
10
- --color-text-secondary: #4b5563;
11
- --color-text-muted: #94a3b8;
12
- --color-primary: #3b82f6;
13
- --color-primary-hover: #2563eb;
14
- --color-success: #10b981;
15
- --color-warning: #f59e0b;
16
- --color-danger: #ef4444;
17
- --color-code-bg: #0f172a;
18
- --color-code-text: #e2e8f0;
19
- --space-xs: 4px;
20
- --space-sm: 8px;
21
- --space-md: 16px;
22
- --space-lg: 24px;
23
- --space-xl: 32px;
24
- --radius-sm: 4px;
25
- --radius-md: 8px;
26
- --radius-lg: 12px;
27
- --shadow-sm: 0 1px 2px rgb(15 23 42 / 6%);
28
- --shadow-md: 0 4px 12px rgb(15 23 42 / 8%);
29
- --font-sans:
30
- -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue', arial, 'PingFang SC', 'Hiragino Sans GB',
31
- 'Microsoft YaHei', sans-serif;
32
- --font-mono: 'SFMono-Regular', menlo, monaco, consolas, 'Liberation Mono', 'Courier New', monospace;
33
- }
34
-
35
- * {
36
- box-sizing: border-box;
37
- }
38
-
39
- html,
40
- body,
41
- #app {
42
- height: 100%;
43
- padding: 0;
44
- margin: 0;
45
- }
46
-
47
- body {
48
- font-family: var(--font-sans);
49
- font-size: 14px;
50
- line-height: 1.6;
51
- color: var(--color-text-primary);
52
- background: var(--color-bg);
53
- }
54
-
55
- a {
56
- color: var(--color-primary);
57
- text-decoration: none;
58
- }
59
-
60
- a:hover {
61
- color: var(--color-primary-hover);
62
- }
63
-
64
- button {
65
- font-family: inherit;
66
- font-size: 14px;
67
- cursor: pointer;
68
- }
69
-
70
- code,
71
- pre {
72
- font-family: var(--font-mono);
73
- }
74
-
75
- /* 通用内容块:每个 demo 页面共用 */
76
- .demo-page {
77
- display: flex;
78
- flex-direction: column;
79
- gap: var(--space-lg);
80
- }
81
-
82
- .demo-page__title {
83
- margin: 0;
84
- font-size: 22px;
85
- font-weight: 600;
86
- }
87
-
88
- .demo-page__desc {
89
- margin: 0;
90
- color: var(--color-text-secondary);
91
- }
92
-
93
- .demo-card {
94
- padding: var(--space-lg);
95
- background: var(--color-surface);
96
- border: 1px solid var(--color-border);
97
- border-radius: var(--radius-md);
98
- box-shadow: var(--shadow-sm);
99
- }
100
-
101
- .demo-card__title {
102
- margin: 0 0 var(--space-sm);
103
- font-size: 16px;
104
- font-weight: 600;
105
- }
106
-
107
- .demo-card__hint {
108
- margin: 0 0 var(--space-md);
109
- color: var(--color-text-secondary);
110
- }
111
-
112
- .demo-actions {
113
- display: flex;
114
- flex-wrap: wrap;
115
- gap: var(--space-sm);
116
- }
117
-
118
- .demo-btn {
119
- padding: 8px 16px;
120
- color: #fff;
121
- background: var(--color-primary);
122
- border: none;
123
- border-radius: var(--radius-sm);
124
- transition: background-color 0.15s ease-in-out;
125
- }
126
-
127
- .demo-btn:hover {
128
- background: var(--color-primary-hover);
129
- }
130
-
131
- .demo-btn--success {
132
- background: var(--color-success);
133
- }
134
-
135
- .demo-btn--warning {
136
- background: var(--color-warning);
137
- }
138
-
139
- .demo-btn--danger {
140
- background: var(--color-danger);
141
- }
142
-
143
- .demo-btn--ghost {
144
- color: var(--color-text-primary);
145
- background: transparent;
146
- border: 1px solid var(--color-border);
147
- }
148
-
149
- .demo-btn--ghost:hover {
150
- background: var(--color-bg);
151
- }
152
-
153
- .demo-log {
154
- max-height: 240px;
155
- padding: var(--space-md);
156
- overflow: auto;
157
- font-size: 12px;
158
- color: var(--color-code-text);
159
- background: var(--color-code-bg);
160
- border-radius: var(--radius-sm);
161
- }
162
-
163
- .demo-log__line {
164
- margin: 0;
165
- word-break: break-all;
166
- white-space: pre-wrap;
167
- }
168
-
169
- .demo-log__line + .demo-log__line {
170
- margin-top: 4px;
171
- }
172
-
173
- .demo-snippet {
174
- padding: var(--space-md);
175
- overflow: auto;
176
- font-size: 12px;
177
- color: var(--color-code-text);
178
- background: var(--color-code-bg);
179
- border-radius: var(--radius-sm);
180
- }
package/src/browser.ts DELETED
@@ -1,44 +0,0 @@
1
- /*
2
- * Tencent is pleased to support the open source community by making
3
- * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.
4
- *
5
- * Copyright (C) 2021 THL A29 Limited, a Tencent company. 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 { createPlugin } from './core/plugin';
28
- import { createBkOT, initBkOT } from './core/sdk';
29
-
30
- export * from './index';
31
-
32
- const BkOpenTelemetry = {
33
- createBkOT,
34
- createPlugin,
35
- initBkOT,
36
- };
37
-
38
- if (typeof window !== 'undefined') {
39
- Object.assign(window, {
40
- BkOpenTelemetry,
41
- });
42
- }
43
-
44
- export { BkOpenTelemetry };
@@ -1,327 +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 { BkOTPlugin } from './plugin';
28
- import type { Attributes } from '@opentelemetry/api';
29
-
30
- export interface BkOTAttributesConfig {
31
- custom?: () => Attributes;
32
- error?: () => Attributes;
33
- metric?: () => Attributes;
34
- page?: () => Attributes;
35
- }
36
-
37
- export type BkOTAttributeValue = boolean | number | string;
38
-
39
- export interface BkOTBatchConfig {
40
- exportTimeoutMillis?: number;
41
- maxExportBatchSize?: number;
42
- maxQueueSize?: number;
43
- scheduledDelayMillis?: number;
44
- }
45
-
46
- export interface BkOTConfig {
47
- attributes?: BkOTAttributesConfig;
48
- autoStart?: boolean;
49
- debug?: boolean;
50
- enabled?: boolean;
51
- endpoint?: string;
52
- environment?: string;
53
- headers?: Record<string, string>;
54
- plugins?: BkOTPlugin[];
55
- redact?: BkOTRedactConfig;
56
- rum?: BkOTRumConfig;
57
- sampleRate?: number;
58
- spanBatch?: BkOTBatchConfig;
59
- token?: string;
60
- }
61
-
62
- export interface BkOTCustomEventPayload {
63
- attributes?: Attributes;
64
- error?: Error;
65
- name: string;
66
- }
67
-
68
- export interface BkOTHttpBodyConfig {
69
- maxBodySize?: number;
70
- redact?: (payload: BkOTHttpBodyRedactPayload) => string;
71
- }
72
-
73
- export interface BkOTHttpBodyRedactPayload {
74
- body: string;
75
- contentType?: string;
76
- method: string;
77
- status?: number;
78
- truncated: boolean;
79
- type: 'request' | 'response';
80
- url: string;
81
- }
82
-
83
- export interface BkOTInstrumentationsConfig {
84
- documentLoad?: boolean;
85
- fetch?: boolean;
86
- userInteraction?: boolean | { eventNames?: string[] };
87
- xhr?: boolean;
88
- }
89
-
90
- export interface BkOTRedactConfig {
91
- // 用于隐私脱敏:在所有 RUM 自定义插件 emit 之前过滤一次属性
92
- attributes?: (attributes: Attributes) => Attributes;
93
- // 用于隐私脱敏:所有上报到 attribute 的 URL 在写入前会经过此函数
94
- url?: (url: string) => string;
95
- }
96
-
97
- export interface BkOTRumConfig extends BkOTInstrumentationsConfig {
98
- cspViolation?: boolean;
99
- device?: boolean | { storageKey?: string };
100
- httpBody?: BkOTHttpBodyConfig | boolean;
101
- pageView?: boolean;
102
- routeTiming?: boolean;
103
- websocket?: boolean;
104
- webVitals?: boolean;
105
- blankScreen?:
106
- | {
107
- checkDelay?: number;
108
- // 自定义"页面已渲染"忽略选择器,命中即认为是 loading 占位、非空白
109
- ignoreSelectors?: string[];
110
- rootSelector?: string;
111
- threshold?: number;
112
- }
113
- | boolean;
114
- error?:
115
- | {
116
- // 同 hash 错误窗口内最多上报多少条,默认 5
117
- maxPerWindow?: number;
118
- // 节流窗口长度(ms),默认 60_000
119
- windowMs?: number;
120
- }
121
- | boolean;
122
- longTask?:
123
- | {
124
- // 任务时长阈值(ms),低于该值的 longtask 不上报,默认 50
125
- threshold?: number;
126
- }
127
- | boolean;
128
- session?:
129
- | {
130
- // 不活跃多久后视为新会话,默认 30 分钟
131
- inactivityMs?: number;
132
- storageKey?: string;
133
- }
134
- | boolean;
135
- }
136
-
137
- export interface NormalizedBkOTConfig extends Omit<
138
- BkOTConfig,
139
- 'attributes' | 'autoStart' | 'debug' | 'enabled' | 'endpoint' | 'environment' | 'plugins' | 'redact' | 'token'
140
- > {
141
- autoStart: boolean;
142
- debug: boolean;
143
- enabled: boolean;
144
- endpoint: string;
145
- environment: string;
146
- logs: SignalExporterConfig;
147
- metricIntervalMillis: number;
148
- metrics: SignalExporterConfig;
149
- plugins: BkOTPlugin[];
150
- resourceAttributes: Attributes;
151
- sampleRate: number;
152
- traces: SignalExporterConfig;
153
- getCustomAttributes: () => Attributes;
154
- getErrorAttributes: () => Attributes;
155
- getMetricAttributes: () => Attributes;
156
- getPageAttributes: () => Attributes;
157
- redactAttributes: (attributes: Attributes) => Attributes;
158
- redactUrl: (url: string) => string;
159
- instrumentations: Required<Pick<BkOTInstrumentationsConfig, 'documentLoad' | 'fetch' | 'xhr'>> & {
160
- userInteraction: BkOTInstrumentationsConfig['userInteraction'];
161
- };
162
- rum: Omit<Required<BkOTRumConfig>, 'documentLoad' | 'fetch' | 'httpBody' | 'userInteraction' | 'xhr'> & {
163
- httpBody: false | Required<BkOTHttpBodyConfig>;
164
- };
165
- }
166
-
167
- export interface SignalExporterConfig {
168
- concurrencyLimit?: number;
169
- endpoint: string;
170
- headers?: Record<string, string>;
171
- timeoutMillis?: number;
172
- }
173
-
174
- const DEFAULT_OTLP_ENDPOINT = 'http://localhost:4318'; // 默认上报到本机 OTLP collector
175
- const DEFAULT_METRIC_INTERVAL_MILLIS = 10 * 1000; // 10s 上报一次
176
-
177
- const trimTrailingSlash = (value: string) => value.replace(/\/+$/, '');
178
-
179
- const resolveSignalEndpoint = (endpoint: string | undefined, signalPath: 'logs' | 'metrics' | 'traces') => {
180
- const normalized = trimTrailingSlash(endpoint || DEFAULT_OTLP_ENDPOINT);
181
- if (normalized.endsWith(`/v1/${signalPath}`)) {
182
- return normalized;
183
- }
184
- if (normalized.endsWith('/v1')) {
185
- return `${normalized}/${signalPath}`;
186
- }
187
- return `${normalized}/v1/${signalPath}`;
188
- };
189
-
190
- const resolveSignalConfig = (base: BkOTConfig, signalPath: 'logs' | 'metrics' | 'traces'): SignalExporterConfig => {
191
- // token 只负责提供默认鉴权头;headers 保持显式配置优先,便于特殊场景覆盖。
192
- const mergedHeaders =
193
- base.token || base.headers
194
- ? {
195
- ...(base.token ? { Authorization: `Bearer ${base.token}` } : {}),
196
- ...(base.headers ?? {}),
197
- }
198
- : undefined;
199
-
200
- return {
201
- endpoint: resolveSignalEndpoint(base.endpoint, signalPath),
202
- headers: mergedHeaders,
203
- };
204
- };
205
-
206
- const clampSampleRate = (sampleRate?: number) => {
207
- if (typeof sampleRate !== 'number' || !Number.isFinite(sampleRate)) {
208
- return 1;
209
- }
210
- return Math.max(0, Math.min(1, sampleRate));
211
- };
212
-
213
- const positiveNumber = (value: number | undefined, fallback: number) =>
214
- typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;
215
-
216
- const nonNegativeNumber = (value: number | undefined, fallback: number) =>
217
- typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;
218
-
219
- const boundedRatio = (value: number | undefined, fallback: number) => {
220
- if (typeof value !== 'number' || !Number.isFinite(value)) {
221
- return fallback;
222
- }
223
- return Math.max(0, Math.min(1, value));
224
- };
225
-
226
- const identityRedactHttpBody = (payload: BkOTHttpBodyRedactPayload) => payload.body;
227
-
228
- const normalizeHttpBodyConfig = (httpBody: BkOTRumConfig['httpBody']): false | Required<BkOTHttpBodyConfig> => {
229
- if (!httpBody) {
230
- return false;
231
- }
232
- if (typeof httpBody === 'boolean') {
233
- return {
234
- maxBodySize: 10 * 1024,
235
- redact: identityRedactHttpBody,
236
- };
237
- }
238
- return {
239
- maxBodySize: positiveNumber(httpBody.maxBodySize, 10 * 1024),
240
- redact: httpBody.redact ?? identityRedactHttpBody,
241
- };
242
- };
243
-
244
- const normalizeRumConfig = (rum: BkOTConfig['rum']): NormalizedBkOTConfig['rum'] => ({
245
- device: rum?.device ?? true,
246
- httpBody: normalizeHttpBodyConfig(rum?.httpBody),
247
- session:
248
- typeof rum?.session === 'object'
249
- ? {
250
- ...rum.session,
251
- inactivityMs: positiveNumber(rum.session.inactivityMs, 30 * 60 * 1000),
252
- }
253
- : (rum?.session ?? true),
254
- pageView: rum?.pageView ?? true,
255
- error:
256
- typeof rum?.error === 'object'
257
- ? {
258
- ...rum.error,
259
- maxPerWindow: positiveNumber(rum.error.maxPerWindow, 5),
260
- windowMs: positiveNumber(rum.error.windowMs, 60_000),
261
- }
262
- : (rum?.error ?? true),
263
- webVitals: rum?.webVitals ?? true,
264
- blankScreen:
265
- typeof rum?.blankScreen === 'object'
266
- ? {
267
- ...rum.blankScreen,
268
- checkDelay: nonNegativeNumber(rum.blankScreen.checkDelay, 3000),
269
- threshold: boundedRatio(rum.blankScreen.threshold, 0.8),
270
- }
271
- : (rum?.blankScreen ?? true),
272
- websocket: rum?.websocket ?? true,
273
- longTask:
274
- typeof rum?.longTask === 'object'
275
- ? {
276
- ...rum.longTask,
277
- threshold: nonNegativeNumber(rum.longTask.threshold, 50),
278
- }
279
- : (rum?.longTask ?? false),
280
- cspViolation: rum?.cspViolation ?? false,
281
- routeTiming: rum?.routeTiming ?? false,
282
- });
283
-
284
- const identityRedactAttributes = (attributes: Attributes) => attributes;
285
- const identityRedactUrl = (url: string) => url;
286
-
287
- export const normalizeConfig = (config: BkOTConfig): NormalizedBkOTConfig => {
288
- const resourceAttributes: Attributes = {
289
- 'deployment.environment.name': config.environment ?? 'production',
290
- 'rum.provider': 'blueking',
291
- 'telemetry.sdk.language': 'webjs',
292
- };
293
-
294
- return {
295
- ...config,
296
- debug: config.debug ?? false,
297
- enabled: config.enabled ?? true,
298
- environment: config.environment ?? 'production',
299
- endpoint: trimTrailingSlash(config.endpoint || DEFAULT_OTLP_ENDPOINT),
300
- traces: resolveSignalConfig(config, 'traces'),
301
- metrics: resolveSignalConfig(config, 'metrics'),
302
- logs: resolveSignalConfig(config, 'logs'),
303
- sampleRate: clampSampleRate(config.sampleRate),
304
- resourceAttributes,
305
- metricIntervalMillis: DEFAULT_METRIC_INTERVAL_MILLIS,
306
- instrumentations: {
307
- documentLoad: config.rum?.documentLoad ?? true,
308
- fetch: config.rum?.fetch ?? true,
309
- xhr: config.rum?.xhr ?? true,
310
- userInteraction: config.rum?.userInteraction ?? true,
311
- },
312
- rum: normalizeRumConfig(config.rum),
313
- plugins: config.plugins ?? [],
314
- autoStart: config.autoStart ?? true,
315
- getPageAttributes:
316
- config.attributes?.page ??
317
- (() => ({
318
- 'rum.page.host': typeof window === 'undefined' ? '' : window.location.host,
319
- 'rum.page.path': typeof window === 'undefined' ? '' : window.location.pathname,
320
- })),
321
- getMetricAttributes: config.attributes?.metric ?? (() => ({})),
322
- getErrorAttributes: config.attributes?.error ?? (() => ({})),
323
- getCustomAttributes: config.attributes?.custom ?? (() => ({})),
324
- redactAttributes: config.redact?.attributes ?? identityRedactAttributes,
325
- redactUrl: config.redact?.url ?? identityRedactUrl,
326
- };
327
- };
@@ -1,97 +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 { NormalizedBkOTConfig } from './config';
28
- import type { Attributes, Meter, Span, Tracer } from '@opentelemetry/api';
29
- import type { Logger, LogRecord } from '@opentelemetry/api-logs';
30
-
31
- export interface BkOTPlugin {
32
- enabled?: ((config: NormalizedBkOTConfig) => boolean) | boolean;
33
- name: string;
34
- flush?: () => Promise<void> | void;
35
- init: (context: BkOTRuntimeContext) => Promise<void> | void;
36
- shutdown?: () => Promise<void> | void;
37
- }
38
-
39
- export interface BkOTRuntimeContext {
40
- config: NormalizedBkOTConfig;
41
- logger: Logger;
42
- meter: Meter;
43
- tracer: Tracer;
44
- /** 对外提供的属性脱敏入口,所有插件在 emit 前都应过一次 */
45
- applyRedact: (attributes: Attributes) => Attributes;
46
- /** 包装 logger.emit,自动应用 redact 与 runtime attributes */
47
- emitLog: (record: LogRecord) => void;
48
- getRuntimeAttributes: () => Attributes;
49
- setRuntimeAttributes: (attributes: Attributes) => void;
50
- startSpan: (name: string, attributes?: Attributes) => Span;
51
- }
52
-
53
- export const isPluginEnabled = (plugin: BkOTPlugin, config: NormalizedBkOTConfig) => {
54
- if (typeof plugin.enabled === 'function') {
55
- return plugin.enabled(config);
56
- }
57
- return plugin.enabled !== false;
58
- };
59
-
60
- export const createPlugin = (plugin: BkOTPlugin) => plugin;
61
-
62
- export class PluginManager {
63
- private readonly plugins: BkOTPlugin[];
64
- private startedPlugins: BkOTPlugin[] = [];
65
-
66
- public constructor(plugins: BkOTPlugin[]) {
67
- this.plugins = plugins;
68
- }
69
-
70
- public async flush() {
71
- // 并行 flush,避免单个慢插件拖累整体
72
- await Promise.all(this.startedPlugins.map(plugin => Promise.resolve().then(() => plugin.flush?.())));
73
- }
74
-
75
- public async shutdown() {
76
- const plugins = [...this.startedPlugins].reverse();
77
- for (const plugin of plugins) {
78
- await plugin.shutdown?.();
79
- }
80
- this.startedPlugins = [];
81
- }
82
-
83
- public async start(context: BkOTRuntimeContext) {
84
- try {
85
- for (const plugin of this.plugins) {
86
- if (!isPluginEnabled(plugin, context.config)) {
87
- continue;
88
- }
89
- await plugin.init(context);
90
- this.startedPlugins.push(plugin);
91
- }
92
- } catch (error) {
93
- await this.shutdown();
94
- throw error;
95
- }
96
- }
97
- }