@oas-tools/oas-telemetry 0.7.0-alpha.2 → 0.7.0-alpha.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/.env.example +50 -17
- package/README.md +244 -239
- package/dist/cjs/config/bootConfig.cjs +18 -0
- package/dist/cjs/config/config.cjs +145 -0
- package/dist/cjs/config/config.types.cjs +5 -0
- package/dist/cjs/index.cjs +19 -25
- package/dist/cjs/{tlmRoutes.cjs → routesManager.cjs} +28 -21
- package/dist/cjs/{exporters/InMemoryLogRecordExporter.cjs → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs} +42 -19
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +97 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +118 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginLogExporter.cjs +45 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginMetricExporter.cjs +46 -0
- package/dist/cjs/telemetry/custom-implementations/exporters/PluginSpanExporter.cjs +61 -0
- package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.cjs +70 -0
- package/dist/cjs/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.cjs +70 -0
- package/dist/cjs/{utils → telemetry/custom-implementations/utils}/circular.cjs +39 -49
- package/dist/cjs/telemetry/custom-implementations/wrappers.cjs +175 -0
- package/dist/cjs/telemetry/initializeTelemetry.cjs +74 -0
- package/dist/cjs/telemetry/telemetryConfigurator.cjs +84 -0
- package/dist/cjs/telemetry/telemetryRegistry.cjs +40 -0
- package/dist/cjs/tlm-ai/agent.cjs +82 -63
- package/dist/cjs/tlm-ai/aiController.cjs +5 -4
- package/dist/cjs/tlm-ai/aiRoutes.cjs +9 -6
- package/dist/cjs/tlm-ai/tools.cjs +16 -9
- package/dist/cjs/tlm-auth/authController.cjs +14 -15
- package/dist/cjs/tlm-auth/authMiddleware.cjs +11 -10
- package/dist/cjs/tlm-auth/authRoutes.cjs +9 -7
- package/dist/cjs/tlm-log/logController.cjs +45 -18
- package/dist/cjs/tlm-log/logRoutes.cjs +16 -11
- package/dist/cjs/tlm-metric/metricsController.cjs +37 -12
- package/dist/cjs/tlm-metric/metricsRoutes.cjs +16 -11
- package/dist/cjs/tlm-plugin/pluginController.cjs +114 -75
- package/dist/cjs/tlm-plugin/pluginProcess.cjs +108 -0
- package/dist/cjs/tlm-plugin/pluginRoutes.cjs +11 -6
- package/dist/cjs/tlm-plugin/pluginService.cjs +79 -0
- package/dist/cjs/tlm-trace/traceController.cjs +54 -45
- package/dist/cjs/tlm-trace/traceRoutes.cjs +16 -11
- package/dist/cjs/tlm-ui/uiRoutes.cjs +26 -20
- package/dist/cjs/tlm-util/utilController.cjs +8 -9
- package/dist/cjs/tlm-util/utilRoutes.cjs +22 -19
- package/dist/cjs/types/index.cjs +0 -1
- package/dist/cjs/utils/logger.cjs +3 -5
- package/dist/cjs/utils/regexUtils.cjs +27 -0
- package/dist/esm/config/bootConfig.js +11 -0
- package/dist/esm/config/config.js +126 -0
- package/dist/esm/index.js +18 -29
- package/dist/esm/{tlmRoutes.js → routesManager.js} +27 -22
- package/dist/esm/{exporters/InMemoryLogRecordExporter.js → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js} +31 -17
- package/dist/esm/{exporters/InMemoryDBMetricsExporter.js → telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js} +31 -17
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +105 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginLogExporter.js +36 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginMetricExporter.js +35 -0
- package/dist/esm/telemetry/custom-implementations/exporters/PluginSpanExporter.js +52 -0
- package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.js +64 -0
- package/dist/esm/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.js +64 -0
- package/dist/esm/telemetry/custom-implementations/utils/circular.js +76 -0
- package/dist/esm/telemetry/custom-implementations/wrappers.js +163 -0
- package/dist/esm/telemetry/initializeTelemetry.js +71 -0
- package/dist/esm/telemetry/telemetryConfigurator.js +74 -0
- package/dist/esm/telemetry/telemetryRegistry.js +34 -0
- package/dist/esm/tlm-ai/agent.js +77 -59
- package/dist/esm/tlm-ai/aiController.js +5 -4
- package/dist/esm/tlm-ai/aiRoutes.js +7 -5
- package/dist/esm/tlm-ai/tools.js +18 -9
- package/dist/esm/tlm-auth/authController.js +9 -10
- package/dist/esm/tlm-auth/authMiddleware.js +10 -9
- package/dist/esm/tlm-auth/authRoutes.js +8 -6
- package/dist/esm/tlm-log/logController.js +36 -16
- package/dist/esm/tlm-log/logRoutes.js +15 -11
- package/dist/esm/tlm-metric/metricsController.js +29 -10
- package/dist/esm/tlm-metric/metricsRoutes.js +15 -11
- package/dist/esm/tlm-plugin/pluginController.js +112 -77
- package/dist/esm/tlm-plugin/pluginProcess.js +101 -0
- package/dist/esm/tlm-plugin/pluginRoutes.js +10 -6
- package/dist/esm/tlm-plugin/pluginService.js +73 -0
- package/dist/esm/tlm-trace/traceController.js +40 -35
- package/dist/esm/tlm-trace/traceRoutes.js +15 -11
- package/dist/esm/tlm-ui/uiRoutes.js +24 -19
- package/dist/esm/tlm-util/utilController.js +8 -9
- package/dist/esm/tlm-util/utilRoutes.js +17 -15
- package/dist/esm/types/index.js +0 -1
- package/dist/esm/utils/logger.js +3 -4
- package/dist/esm/utils/regexUtils.js +23 -0
- package/dist/types/config/bootConfig.d.ts +5 -0
- package/dist/types/config/config.d.ts +858 -0
- package/dist/types/config/config.types.d.ts +34 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/routesManager.d.ts +3 -0
- package/dist/types/{exporters/InMemoryLogRecordExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts} +6 -6
- package/dist/types/{exporters/InMemoryDBMetricsExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts} +7 -7
- package/dist/types/{exporters/InMemoryDbExporter.d.ts → telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts} +9 -9
- package/dist/types/telemetry/custom-implementations/exporters/PluginLogExporter.d.ts +8 -0
- package/dist/types/telemetry/custom-implementations/exporters/PluginMetricExporter.d.ts +12 -0
- package/dist/types/telemetry/custom-implementations/exporters/PluginSpanExporter.d.ts +14 -0
- package/dist/types/telemetry/custom-implementations/processors/dynamicMultiLogProcessor.d.ts +32 -0
- package/dist/types/telemetry/custom-implementations/processors/dynamicMultiSpanProcessor.d.ts +34 -0
- package/dist/types/telemetry/custom-implementations/utils/circular.d.ts +27 -0
- package/dist/types/telemetry/custom-implementations/wrappers.d.ts +52 -0
- package/dist/types/telemetry/initializeTelemetry.d.ts +1 -0
- package/dist/types/telemetry/telemetryConfigurator.d.ts +2 -0
- package/dist/types/telemetry/telemetryRegistry.d.ts +20 -0
- package/dist/types/tlm-ai/agent.d.ts +2 -1
- package/dist/types/tlm-ai/aiController.d.ts +4 -3
- package/dist/types/tlm-ai/aiRoutes.d.ts +2 -2
- package/dist/types/tlm-ai/tools.d.ts +3 -1
- package/dist/types/tlm-auth/authController.d.ts +4 -3
- package/dist/types/tlm-auth/authMiddleware.d.ts +2 -1
- package/dist/types/tlm-auth/authRoutes.d.ts +2 -2
- package/dist/types/tlm-log/logController.d.ts +1 -0
- package/dist/types/tlm-log/logRoutes.d.ts +2 -2
- package/dist/types/tlm-metric/metricsController.d.ts +1 -0
- package/dist/types/tlm-metric/metricsRoutes.d.ts +2 -2
- package/dist/types/tlm-plugin/pluginController.d.ts +4 -1
- package/dist/types/tlm-plugin/pluginProcess.d.ts +1 -0
- package/dist/types/tlm-plugin/pluginRoutes.d.ts +1 -2
- package/dist/types/tlm-plugin/pluginService.d.ts +24 -0
- package/dist/types/tlm-trace/traceController.d.ts +7 -6
- package/dist/types/tlm-trace/traceRoutes.d.ts +2 -2
- package/dist/types/tlm-ui/uiRoutes.d.ts +1 -2
- package/dist/types/tlm-util/utilController.d.ts +2 -1
- package/dist/types/tlm-util/utilRoutes.d.ts +2 -2
- package/dist/types/types/index.d.ts +17 -47
- package/dist/types/utils/regexUtils.d.ts +1 -0
- package/dist/ui/assets/index-BzIdRox6.js +1733 -0
- package/dist/ui/assets/index-CkoHzrrt.css +1 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/oas-tlm.svg +185 -0
- package/package.json +12 -7
- package/dist/cjs/config.cjs +0 -31
- package/dist/cjs/exporters/InMemoryDBMetricsExporter.cjs +0 -74
- package/dist/cjs/exporters/InMemoryDbExporter.cjs +0 -102
- package/dist/cjs/exporters/consoleExporter.cjs +0 -47
- package/dist/cjs/exporters/dynamicExporter.cjs +0 -57
- package/dist/cjs/instrumentation/index.cjs +0 -28
- package/dist/cjs/instrumentation/logs.cjs +0 -46
- package/dist/cjs/instrumentation/metrics.cjs +0 -27
- package/dist/cjs/instrumentation/traces.cjs +0 -19
- package/dist/esm/config.js +0 -20
- package/dist/esm/exporters/InMemoryDbExporter.js +0 -102
- package/dist/esm/exporters/consoleExporter.js +0 -38
- package/dist/esm/exporters/dynamicExporter.js +0 -50
- package/dist/esm/instrumentation/index.js +0 -26
- package/dist/esm/instrumentation/logs.js +0 -34
- package/dist/esm/instrumentation/metrics.js +0 -18
- package/dist/esm/instrumentation/traces.js +0 -12
- package/dist/esm/utils/circular.js +0 -84
- package/dist/types/config.d.ts +0 -6
- package/dist/types/exporters/consoleExporter.d.ts +0 -13
- package/dist/types/exporters/dynamicExporter.d.ts +0 -25
- package/dist/types/instrumentation/logs.d.ts +0 -1
- package/dist/types/instrumentation/metrics.d.ts +0 -1
- package/dist/types/instrumentation/traces.d.ts +0 -1
- package/dist/types/tlmRoutes.d.ts +0 -2
- package/dist/types/utils/circular.d.ts +0 -31
- package/dist/ui/assets/index-BNhZBPi2.css +0 -1
- package/dist/ui/assets/index-DxGAMrAl.js +0 -401
- package/dist/ui/vite.svg +0 -1
- /package/dist/{types/instrumentation/index.d.ts → esm/config/config.types.js} +0 -0
package/dist/esm/index.js
CHANGED
|
@@ -1,39 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { Router } from 'express';
|
|
4
|
-
import { InMemoryExporter } from './exporters/InMemoryDbExporter.js';
|
|
1
|
+
import "./config/bootConfig.js"; // Load environment variables before any other imports
|
|
2
|
+
import './telemetry/initializeTelemetry.js'; // Initialize OpenTelemetry instrumentation
|
|
5
3
|
import logger from './utils/logger.js';
|
|
6
|
-
import {
|
|
4
|
+
import { getConfig } from './config/config.js';
|
|
5
|
+
import { Router } from 'express';
|
|
6
|
+
import { configureRoutes } from './routesManager.js';
|
|
7
|
+
import { configureTelemetry } from './telemetry/telemetryConfigurator.js';
|
|
8
|
+
import { bootEnvVariables } from "./config/bootConfig.js";
|
|
7
9
|
/**
|
|
8
|
-
* Returns the
|
|
10
|
+
* Returns the OAS-Telemetry middleware.
|
|
9
11
|
* All parameters are optional. However, either `spec` or `specFileName` must be provided to enable endpoint filtering.
|
|
10
12
|
*/
|
|
11
13
|
export default function oasTelemetry(oasTlmInputConfig) {
|
|
12
14
|
const router = Router();
|
|
13
|
-
|
|
15
|
+
// This environment variable cannot be set via the config object,
|
|
16
|
+
// as it is required to disable OpenTelemetry SDK initialization,
|
|
17
|
+
// which occurs during the first import at the top of this file.
|
|
18
|
+
if (bootEnvVariables.OASTLM_BOOT_MODULE_DISABLED) {
|
|
14
19
|
return router;
|
|
15
20
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
logger.info("BaseURL: ", globalOasTlmConfig.baseURL);
|
|
24
|
-
globalOasTlmConfig.dynamicSpanExporter.changeExporter(globalOasTlmConfig.exporter ?? new InMemoryExporter());
|
|
25
|
-
if (globalOasTlmConfig.spec)
|
|
26
|
-
logger.info(`Spec content provided`);
|
|
27
|
-
else {
|
|
28
|
-
if (globalOasTlmConfig.specFileName != "")
|
|
29
|
-
logger.info(`Spec file used for telemetry: ${globalOasTlmConfig.specFileName}`);
|
|
30
|
-
else {
|
|
31
|
-
console.error("No spec available !");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (globalOasTlmConfig.autoActivate) {
|
|
35
|
-
globalOasTlmConfig.dynamicSpanExporter.exporter?.start();
|
|
36
|
-
}
|
|
37
|
-
configureRoutes(router);
|
|
21
|
+
const oasTlmConfig = getConfig(oasTlmInputConfig);
|
|
22
|
+
logger.info("BaseUrl: ", oasTlmConfig.general.baseUrl);
|
|
23
|
+
if (!oasTlmConfig.general.spec && !oasTlmConfig.general.specFileName)
|
|
24
|
+
logger.warn("No spec provided, endpoint filtering will not be available. Please provide either `spec` or `specFileName` in the configuration.");
|
|
25
|
+
configureTelemetry(oasTlmConfig);
|
|
26
|
+
configureRoutes(router, oasTlmConfig);
|
|
38
27
|
return router;
|
|
39
28
|
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { json } from "express";
|
|
2
2
|
import logger from "./utils/logger.js";
|
|
3
3
|
import cors from 'cors';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { getTraceRoutes } from "./tlm-trace/traceRoutes.js";
|
|
5
|
+
import { getMetricsRoutes } from "./tlm-metric/metricsRoutes.js";
|
|
6
|
+
import { getLogRoutes } from "./tlm-log/logRoutes.js";
|
|
6
7
|
import cookieParser from 'cookie-parser';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
export const configureRoutes = (router) => {
|
|
15
|
-
if (
|
|
8
|
+
import { getAuthRoutes } from './tlm-auth/authRoutes.js';
|
|
9
|
+
import { getUIRoutes } from './tlm-ui/uiRoutes.js';
|
|
10
|
+
import { getAuthMiddleware } from "./tlm-auth/authMiddleware.js";
|
|
11
|
+
import { getUtilsRoutes } from "./tlm-util/utilRoutes.js";
|
|
12
|
+
import { getAIRoutes } from "./tlm-ai/aiRoutes.js";
|
|
13
|
+
import { bootEnvVariables } from "./config/bootConfig.js";
|
|
14
|
+
import { getPluginRoutes } from "./tlm-plugin/pluginRoutes.js";
|
|
15
|
+
export const configureRoutes = (router, oasTlmConfig) => {
|
|
16
|
+
if (bootEnvVariables.OASTLM_BOOT_ENV === 'development') {
|
|
16
17
|
logger.info("Running in development mode, enabling CORS for all origins");
|
|
17
18
|
router.use(cors({
|
|
18
19
|
origin: '*', // Permitir todas las solicitudes en desarrollo
|
|
@@ -26,19 +27,23 @@ export const configureRoutes = (router) => {
|
|
|
26
27
|
}
|
|
27
28
|
return json({ limit: '10mb' })(req, res, next);
|
|
28
29
|
});
|
|
29
|
-
const allAuthMiddlewares = getWrappedMiddlewares(() =>
|
|
30
|
-
const
|
|
31
|
-
router.use(
|
|
30
|
+
const allAuthMiddlewares = getWrappedMiddlewares(() => oasTlmConfig.auth.enabled, [cookieParser(), getAuthRoutes(oasTlmConfig), getAuthMiddleware(oasTlmConfig)]);
|
|
31
|
+
const baseUrl = oasTlmConfig.general.baseUrl;
|
|
32
|
+
router.use(baseUrl, allAuthMiddlewares);
|
|
33
|
+
router.use(baseUrl + "/traces", getTraceRoutes());
|
|
34
|
+
router.use(baseUrl + "/metrics", getMetricsRoutes());
|
|
35
|
+
router.use(baseUrl + "/logs", getLogRoutes());
|
|
36
|
+
router.use(baseUrl + "/ai", getWrappedMiddlewares(() => oasTlmConfig.ai.openAIKey !== null, [getAIRoutes(oasTlmConfig)]));
|
|
32
37
|
// WARNING: This path must be the same as the one used in the UI package App.tsx "oas-telemetry-ui"
|
|
33
|
-
router.use(
|
|
34
|
-
router.use(
|
|
35
|
-
router.use(
|
|
36
|
-
router.
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
router.use(baseUrl + "/oas-telemetry-ui", getUIRoutes());
|
|
39
|
+
router.use(baseUrl + "/utils", getUtilsRoutes(oasTlmConfig));
|
|
40
|
+
router.use(baseUrl + "/plugins", getPluginRoutes());
|
|
41
|
+
router.get(baseUrl + '/health', (_req, res) => {
|
|
42
|
+
res.status(200).send({ status: 'OK' });
|
|
43
|
+
});
|
|
39
44
|
//redirect to the UI when accessing the base URL
|
|
40
|
-
router.get(
|
|
41
|
-
res.redirect(
|
|
45
|
+
router.get(baseUrl, (req, res) => {
|
|
46
|
+
res.redirect(baseUrl + "/oas-telemetry-ui");
|
|
42
47
|
});
|
|
43
48
|
};
|
|
44
49
|
/**
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { hrTimeToMicroseconds } from '@opentelemetry/core';
|
|
2
2
|
import { ExportResultCode } from '@opentelemetry/core';
|
|
3
|
-
import { removeCircularRefs, applyNesting } from '../utils/circular.js';
|
|
4
3
|
import Datastore from '@seald-io/nedb';
|
|
5
4
|
import MiniSearch from 'minisearch';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import { applyNesting, removeCircularRefs } from '../utils/circular.js';
|
|
6
|
+
import { Enabler } from '../wrappers.js';
|
|
7
|
+
import logger from '../../../utils/logger.js';
|
|
8
|
+
export class InMemoryDbLogExporter extends Enabler {
|
|
9
|
+
constructor(retentionTimeInSeconds = 3600) {
|
|
10
|
+
super();
|
|
11
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
12
|
+
this._db = new Datastore({ timestampData: true });
|
|
13
|
+
this._db.ensureIndex({ fieldName: 'createdAt' });
|
|
9
14
|
this._miniSearch = new MiniSearch({
|
|
10
15
|
fields: ['body'],
|
|
11
16
|
storeFields: ['_id'],
|
|
12
17
|
idField: '_id',
|
|
13
18
|
});
|
|
14
|
-
this.
|
|
19
|
+
this._startCleanupJob();
|
|
15
20
|
}
|
|
16
21
|
/*
|
|
17
22
|
* SUPER WARNING:
|
|
@@ -25,7 +30,7 @@ export class InMemoryLogRecordExporter {
|
|
|
25
30
|
* @param resultCallback
|
|
26
31
|
*/
|
|
27
32
|
export(logs, resultCallback) {
|
|
28
|
-
if (this.
|
|
33
|
+
if (!this.isEnabled()) {
|
|
29
34
|
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
30
35
|
return;
|
|
31
36
|
}
|
|
@@ -57,7 +62,7 @@ export class InMemoryLogRecordExporter {
|
|
|
57
62
|
if (messageSearch) {
|
|
58
63
|
const searchResults = this._miniSearch.search(messageSearch);
|
|
59
64
|
const ids = searchResults.map((result) => result._id);
|
|
60
|
-
|
|
65
|
+
logger.debug(`MiniSearch found ${ids.length} results for search term "${messageSearch}"`, { depth: 3 });
|
|
61
66
|
// Add MiniSearch results to the query
|
|
62
67
|
query._id = { $in: ids };
|
|
63
68
|
}
|
|
@@ -68,7 +73,7 @@ export class InMemoryLogRecordExporter {
|
|
|
68
73
|
if (result.code === ExportResultCode.SUCCESS) {
|
|
69
74
|
this._db.find({}, (err, docs) => {
|
|
70
75
|
if (err) {
|
|
71
|
-
|
|
76
|
+
logger.debug(err);
|
|
72
77
|
callback(err, []);
|
|
73
78
|
return;
|
|
74
79
|
}
|
|
@@ -80,15 +85,6 @@ export class InMemoryLogRecordExporter {
|
|
|
80
85
|
}
|
|
81
86
|
});
|
|
82
87
|
}
|
|
83
|
-
start() {
|
|
84
|
-
this._stopped = false;
|
|
85
|
-
}
|
|
86
|
-
stop() {
|
|
87
|
-
this._stopped = true;
|
|
88
|
-
}
|
|
89
|
-
isRunning() {
|
|
90
|
-
return !this._stopped;
|
|
91
|
-
}
|
|
92
88
|
getFinishedLogs() {
|
|
93
89
|
return this._db.getAllData();
|
|
94
90
|
}
|
|
@@ -114,6 +110,10 @@ export class InMemoryLogRecordExporter {
|
|
|
114
110
|
attributes: logRecord.attributes,
|
|
115
111
|
};
|
|
116
112
|
}
|
|
113
|
+
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
114
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
115
|
+
logger.info(`InMemoryDbLogExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
116
|
+
}
|
|
117
117
|
_insertLogs(logsToInsert, resultCallback) {
|
|
118
118
|
this._db.insert(logsToInsert, (err, newDocs) => {
|
|
119
119
|
if (err) {
|
|
@@ -127,4 +127,18 @@ export class InMemoryLogRecordExporter {
|
|
|
127
127
|
});
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
|
+
_startCleanupJob() {
|
|
131
|
+
const interval = 1000;
|
|
132
|
+
setInterval(() => {
|
|
133
|
+
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
134
|
+
this._db.remove({ createdAt: { $lt: expirationDate } }, { multi: true }, (err, numRemoved) => {
|
|
135
|
+
if (err) {
|
|
136
|
+
logger.error('Error in TTL cleanup:', err);
|
|
137
|
+
}
|
|
138
|
+
else if (numRemoved > 0) {
|
|
139
|
+
logger.debug(`TTL cleanup: removed ${numRemoved} expired logs`);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}, interval);
|
|
143
|
+
}
|
|
130
144
|
}
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
2
|
import dataStore from '@seald-io/nedb';
|
|
3
3
|
import { applyNesting } from '../utils/circular.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import { Enabler } from '../wrappers.js';
|
|
5
|
+
import logger from '../../../utils/logger.js';
|
|
6
|
+
export class InMemoryDbMetricExporter extends Enabler {
|
|
7
|
+
constructor(retentionTimeInSeconds = 3600) {
|
|
8
|
+
super();
|
|
9
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
10
|
+
this._metrics = new dataStore({ timestampData: true });
|
|
11
|
+
this._metrics.ensureIndex({ fieldName: 'createdAt' });
|
|
12
|
+
this._startCleanupJob();
|
|
8
13
|
}
|
|
9
14
|
export(metrics, resultCallback) {
|
|
10
15
|
try {
|
|
11
|
-
if (
|
|
16
|
+
if (this.isEnabled()) {
|
|
12
17
|
const scopeMetrics = metrics?.scopeMetrics;
|
|
13
18
|
const cleanMetrics = applyNesting(scopeMetrics);
|
|
14
19
|
this._metrics.insert(cleanMetrics, (err, _newDoc) => {
|
|
15
20
|
if (err) {
|
|
16
|
-
|
|
21
|
+
logger.error('Insertion Error:', err);
|
|
17
22
|
return;
|
|
18
23
|
}
|
|
19
24
|
});
|
|
@@ -21,24 +26,15 @@ export class InMemoryDBMetricsExporter {
|
|
|
21
26
|
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
22
27
|
}
|
|
23
28
|
catch (error) {
|
|
24
|
-
|
|
29
|
+
logger.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
25
30
|
return resultCallback({
|
|
26
31
|
code: ExportResultCode.FAILED,
|
|
27
32
|
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack),
|
|
28
33
|
});
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
|
-
start() {
|
|
32
|
-
this._stopped = false;
|
|
33
|
-
}
|
|
34
|
-
stop() {
|
|
35
|
-
this._stopped = true;
|
|
36
|
-
}
|
|
37
|
-
isRunning() {
|
|
38
|
-
return !this._stopped;
|
|
39
|
-
}
|
|
40
36
|
shutdown() {
|
|
41
|
-
this.
|
|
37
|
+
this._enabled = false;
|
|
42
38
|
this._metrics = new dataStore();
|
|
43
39
|
return this.forceFlush();
|
|
44
40
|
}
|
|
@@ -62,4 +58,22 @@ export class InMemoryDBMetricsExporter {
|
|
|
62
58
|
insert(metrics, callback) {
|
|
63
59
|
this._metrics.insert(metrics, callback);
|
|
64
60
|
}
|
|
61
|
+
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
62
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
63
|
+
logger.info(`InMemoryDbMetricExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
64
|
+
}
|
|
65
|
+
_startCleanupJob() {
|
|
66
|
+
const interval = 1000;
|
|
67
|
+
setInterval(() => {
|
|
68
|
+
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
69
|
+
this._metrics.remove({ createdAt: { $lt: expirationDate } }, { multi: true }, (err, numRemoved) => {
|
|
70
|
+
if (err) {
|
|
71
|
+
logger.error('Error in TTL cleanup:', err);
|
|
72
|
+
}
|
|
73
|
+
else if (numRemoved > 0) {
|
|
74
|
+
logger.debug(`TTL cleanup: removed ${numRemoved} expired metrics`);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}, interval);
|
|
78
|
+
}
|
|
65
79
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import dataStore from '@seald-io/nedb';
|
|
3
|
+
import logger from '../../../utils/logger.js';
|
|
4
|
+
import { applyNesting, removeCircularRefs } from '../utils/circular.js';
|
|
5
|
+
import { Enabler } from '../wrappers.js';
|
|
6
|
+
export class InMemoryDbSpanExporter extends Enabler {
|
|
7
|
+
constructor(retentionTimeInSeconds = 3600) {
|
|
8
|
+
super();
|
|
9
|
+
this._baseUrl = '/telemetry'; // Default base URL, can be overridden by the config
|
|
10
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
11
|
+
this._spans = new dataStore({ timestampData: true });
|
|
12
|
+
this._spans.ensureIndex({ fieldName: 'createdAt' });
|
|
13
|
+
this._startCleanupJob();
|
|
14
|
+
}
|
|
15
|
+
;
|
|
16
|
+
set baseUrl(baseUrl) {
|
|
17
|
+
this._baseUrl = baseUrl;
|
|
18
|
+
}
|
|
19
|
+
set retentionTimeInSeconds(retentionTimeInSeconds) {
|
|
20
|
+
this._retentionTimeInSeconds = retentionTimeInSeconds;
|
|
21
|
+
logger.info(`InMemoryDbSpanExporter retention time set to ${this._retentionTimeInSeconds} seconds`);
|
|
22
|
+
}
|
|
23
|
+
export(readableSpans, resultCallback) {
|
|
24
|
+
logger.debug('InMemoryDbSpanExporter.export called with spans: ', readableSpans.length);
|
|
25
|
+
try {
|
|
26
|
+
if (!this.isEnabled()) {
|
|
27
|
+
logger.debug('InMemoryDbSpanExporter is not enabled. Skipping export.');
|
|
28
|
+
return resultCallback({ code: ExportResultCode.SUCCESS });
|
|
29
|
+
}
|
|
30
|
+
// Prepare spans to be inserted into the in-memory database (remove circular references and convert to nested objects)
|
|
31
|
+
const cleanSpans = readableSpans
|
|
32
|
+
.map(nestedSpan => removeCircularRefs(nestedSpan)) // to avoid JSON parsing error
|
|
33
|
+
.map(span => applyNesting(span)) // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
34
|
+
.filter(span => {
|
|
35
|
+
const target = span?.attributes?.http?.target; // Exclude spans where target includes 'telemetry' but NOT 'telemetry/utils'
|
|
36
|
+
if (target && target.includes(this._baseUrl)) {
|
|
37
|
+
return target.includes(this._baseUrl + '/utils');
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
});
|
|
41
|
+
// Insert spans into the in-memory database
|
|
42
|
+
this._spans.insert(cleanSpans, (err, _newDoc) => {
|
|
43
|
+
if (err) {
|
|
44
|
+
logger.error(err);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
logger.error('Error exporting spans\n' + error.message + '\n' + error.stack);
|
|
52
|
+
return resultCallback({
|
|
53
|
+
code: ExportResultCode.FAILED,
|
|
54
|
+
error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
;
|
|
59
|
+
shutdown() {
|
|
60
|
+
this._spans = new dataStore();
|
|
61
|
+
return this.forceFlush();
|
|
62
|
+
}
|
|
63
|
+
;
|
|
64
|
+
/**
|
|
65
|
+
* Exports any pending spans in the exporter
|
|
66
|
+
*/
|
|
67
|
+
forceFlush() {
|
|
68
|
+
return Promise.resolve();
|
|
69
|
+
}
|
|
70
|
+
;
|
|
71
|
+
//err,docs
|
|
72
|
+
find(search, callback) {
|
|
73
|
+
this._spans.find(search, callback);
|
|
74
|
+
}
|
|
75
|
+
reset() {
|
|
76
|
+
this._spans = new dataStore();
|
|
77
|
+
}
|
|
78
|
+
;
|
|
79
|
+
getFinishedSpans() {
|
|
80
|
+
return this._spans.getAllData();
|
|
81
|
+
}
|
|
82
|
+
;
|
|
83
|
+
/**
|
|
84
|
+
* Inserts spans into the in-memory database.
|
|
85
|
+
* @param spans - The spans to insert.
|
|
86
|
+
* @param callback - The callback to execute after insertion.
|
|
87
|
+
*/
|
|
88
|
+
insert(spans, callback) {
|
|
89
|
+
this._spans.insert(spans, callback);
|
|
90
|
+
}
|
|
91
|
+
_startCleanupJob() {
|
|
92
|
+
const interval = 1000;
|
|
93
|
+
setInterval(() => {
|
|
94
|
+
const expirationDate = new Date(Date.now() - this._retentionTimeInSeconds * 1000);
|
|
95
|
+
this._spans.remove({ createdAt: { $lt: expirationDate } }, { multi: true }, (err, numRemoved) => {
|
|
96
|
+
if (err) {
|
|
97
|
+
logger.error('Error in TTL cleanup:', err);
|
|
98
|
+
}
|
|
99
|
+
else if (numRemoved > 0) {
|
|
100
|
+
logger.debug(`TTL cleanup: removed ${numRemoved} expired spans`);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}, interval);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import logger from '../../../utils/logger.js';
|
|
3
|
+
import { Enabler } from '../wrappers.js';
|
|
4
|
+
import { pluginService } from '../../../tlm-plugin/pluginService.js';
|
|
5
|
+
import { applyNesting, removeCircularRefs } from '../utils/circular.js';
|
|
6
|
+
export class PluginLogExporter extends Enabler {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
}
|
|
10
|
+
export(logs, resultCallback) {
|
|
11
|
+
logger.debug('PluginLogExporter.export called with logs: ', logs.length);
|
|
12
|
+
try {
|
|
13
|
+
if (!this.isEnabled()) {
|
|
14
|
+
logger.debug('PluginLogExporter is not enabled. Skipping export.');
|
|
15
|
+
return resultCallback({ code: ExportResultCode.SUCCESS });
|
|
16
|
+
}
|
|
17
|
+
const cleanLogs = logs
|
|
18
|
+
.map(log => removeCircularRefs(log))
|
|
19
|
+
.map(log => applyNesting(log));
|
|
20
|
+
cleanLogs.forEach(log => {
|
|
21
|
+
pluginService.broadcastLog(log);
|
|
22
|
+
});
|
|
23
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
logger.error('Error exporting logs\n' + error.message + '\n' + error.stack);
|
|
27
|
+
return resultCallback({
|
|
28
|
+
code: ExportResultCode.FAILED,
|
|
29
|
+
error: new Error('Error exporting logs\n' + error.message + '\n' + error.stack),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
shutdown() {
|
|
34
|
+
return Promise.resolve();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import logger from '../../../utils/logger.js';
|
|
3
|
+
import { Enabler } from '../wrappers.js';
|
|
4
|
+
import { pluginService } from '../../../tlm-plugin/pluginService.js';
|
|
5
|
+
import { applyNesting, removeCircularRefs } from '../utils/circular.js';
|
|
6
|
+
export class PluginMetricExporter extends Enabler {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
}
|
|
10
|
+
export(metrics, resultCallback) {
|
|
11
|
+
logger.debug('PluginMetricExporter.export called');
|
|
12
|
+
try {
|
|
13
|
+
if (!this.isEnabled()) {
|
|
14
|
+
logger.debug('PluginMetricExporter is not enabled. Skipping export.');
|
|
15
|
+
return resultCallback({ code: ExportResultCode.SUCCESS });
|
|
16
|
+
}
|
|
17
|
+
const cleanMetrics = applyNesting(removeCircularRefs(metrics));
|
|
18
|
+
pluginService.broadcastMetric(cleanMetrics);
|
|
19
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logger.error('Error exporting metrics\n' + error.message + '\n' + error.stack);
|
|
23
|
+
return resultCallback({
|
|
24
|
+
code: ExportResultCode.FAILED,
|
|
25
|
+
error: new Error('Error exporting metrics\n' + error.message + '\n' + error.stack),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
shutdown() {
|
|
30
|
+
return Promise.resolve();
|
|
31
|
+
}
|
|
32
|
+
forceFlush() {
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import logger from '../../../utils/logger.js';
|
|
3
|
+
import { Enabler } from '../wrappers.js';
|
|
4
|
+
import { pluginService } from '../../../tlm-plugin/pluginService.js';
|
|
5
|
+
import { applyNesting, removeCircularRefs } from '../utils/circular.js';
|
|
6
|
+
export class PluginSpanExporter extends Enabler {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this._baseUrl = '/telemetry'; // Default base URL, can be overridden by the config
|
|
10
|
+
}
|
|
11
|
+
;
|
|
12
|
+
set baseUrl(baseUrl) {
|
|
13
|
+
this._baseUrl = baseUrl;
|
|
14
|
+
}
|
|
15
|
+
export(readableSpans, resultCallback) {
|
|
16
|
+
logger.debug('PluginSpanExporter.export called with spans: ', readableSpans.length);
|
|
17
|
+
try {
|
|
18
|
+
if (!this.isEnabled()) {
|
|
19
|
+
logger.debug('PluginSpanExporter is not enabled. Skipping export.');
|
|
20
|
+
return resultCallback({ code: ExportResultCode.SUCCESS });
|
|
21
|
+
}
|
|
22
|
+
// Prepare spans to be inserted into the in-memory database (remove circular references and convert to nested objects)
|
|
23
|
+
const cleanSpans = readableSpans
|
|
24
|
+
.map(nestedSpan => removeCircularRefs(nestedSpan)) // to avoid JSON parsing error
|
|
25
|
+
.map(span => applyNesting(span)) // to avoid dot notation in keys (neDB does not support dot notation in keys)
|
|
26
|
+
.filter(span => {
|
|
27
|
+
const target = span?.attributes?.http?.target; // Exclude spans where target includes 'telemetry' but NOT 'telemetry/utils'
|
|
28
|
+
if (target && target.includes(this._baseUrl)) {
|
|
29
|
+
return target.includes(this._baseUrl + '/utils');
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
cleanSpans.forEach(span => {
|
|
34
|
+
pluginService.broadcastTrace(span);
|
|
35
|
+
});
|
|
36
|
+
setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger.error('Error exporting spans\n' + error.message + '\n' + error.stack);
|
|
40
|
+
return resultCallback({
|
|
41
|
+
code: ExportResultCode.FAILED,
|
|
42
|
+
error: new Error('Error exporting spans\n' + error.message + '\n' + error.stack),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
shutdown() {
|
|
47
|
+
return this.forceFlush();
|
|
48
|
+
}
|
|
49
|
+
forceFlush() {
|
|
50
|
+
return Promise.resolve();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { callWithTimeout } from '@opentelemetry/core';
|
|
2
|
+
import logger from '../../../utils/logger.js'; // optional if you want logging
|
|
3
|
+
export class DynamicMultiLogRecordProcessor {
|
|
4
|
+
constructor(initialProcessors = [], forceFlushTimeoutMillis = 30000) {
|
|
5
|
+
this._processors = [];
|
|
6
|
+
this._processors = [...initialProcessors];
|
|
7
|
+
this._forceFlushTimeoutMillis = forceFlushTimeoutMillis;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Add a new LogRecordProcessor or an array of LogRecordProcessors at runtime.
|
|
11
|
+
*/
|
|
12
|
+
addProcessors(processor) {
|
|
13
|
+
if (Array.isArray(processor)) {
|
|
14
|
+
this._processors.push(...processor);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
this._processors.push(processor);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Remove a specific LogRecordProcessor.
|
|
22
|
+
*/
|
|
23
|
+
removeProcessor(processor) {
|
|
24
|
+
this._processors = this._processors.filter(p => p !== processor);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Clear all LogRecordProcessors.
|
|
28
|
+
*/
|
|
29
|
+
clearProcessors() {
|
|
30
|
+
this._processors = [];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Called when a log record is emitted.
|
|
34
|
+
*/
|
|
35
|
+
onEmit(logRecord, context) {
|
|
36
|
+
for (const processor of this._processors) {
|
|
37
|
+
try {
|
|
38
|
+
processor.onEmit(logRecord, context);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger?.error?.('Error in onEmit of LogRecordProcessor:', error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Force flush all processors with timeout.
|
|
47
|
+
*/
|
|
48
|
+
async forceFlush() {
|
|
49
|
+
const timeout = this._forceFlushTimeoutMillis;
|
|
50
|
+
const promises = this._processors.map(p => callWithTimeout(p.forceFlush(), timeout));
|
|
51
|
+
try {
|
|
52
|
+
await Promise.all(promises);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
logger?.error?.('Error during forceFlush in DynamicMultiLogRecordProcessor:', error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Shutdown all processors.
|
|
60
|
+
*/
|
|
61
|
+
async shutdown() {
|
|
62
|
+
await Promise.all(this._processors.map(p => p.shutdown()));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import logger from '../../../utils/logger.js';
|
|
2
|
+
export class DynamicMultiSpanProcessor {
|
|
3
|
+
constructor(initialProcessors = []) {
|
|
4
|
+
this._spanProcessors = [];
|
|
5
|
+
this._spanProcessors = [...initialProcessors];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Add a new SpanProcessor or an array of SpanProcessors at runtime.
|
|
9
|
+
*/
|
|
10
|
+
addProcessors(processor) {
|
|
11
|
+
if (Array.isArray(processor)) {
|
|
12
|
+
this._spanProcessors.push(...processor);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this._spanProcessors.push(processor);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Remove a specific SpanProcessor if needed.
|
|
20
|
+
*/
|
|
21
|
+
removeProcessor(processor) {
|
|
22
|
+
this._spanProcessors = this._spanProcessors.filter(p => p !== processor);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Clear all processors.
|
|
26
|
+
*/
|
|
27
|
+
clearProcessors() {
|
|
28
|
+
this._spanProcessors = [];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Called when a span is started.
|
|
32
|
+
*/
|
|
33
|
+
onStart(span, context) {
|
|
34
|
+
for (const processor of this._spanProcessors) {
|
|
35
|
+
processor.onStart(span, context);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Called when a span ends.
|
|
40
|
+
*/
|
|
41
|
+
onEnd(span) {
|
|
42
|
+
for (const processor of this._spanProcessors) {
|
|
43
|
+
processor.onEnd(span);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Force flush all processors.
|
|
48
|
+
*/
|
|
49
|
+
async forceFlush() {
|
|
50
|
+
const promises = this._spanProcessors.map(p => p.forceFlush());
|
|
51
|
+
try {
|
|
52
|
+
await Promise.all(promises);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
logger.error('Error during forceFlush:', error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Shutdown all processors.
|
|
60
|
+
*/
|
|
61
|
+
async shutdown() {
|
|
62
|
+
await Promise.all(this._spanProcessors.map(p => p.shutdown()));
|
|
63
|
+
}
|
|
64
|
+
}
|