@jagilber-org/index-server 1.19.1
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/CHANGELOG.md +1218 -0
- package/CODE_OF_CONDUCT.md +49 -0
- package/CONTRIBUTING.md +75 -0
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/SECURITY.md +50 -0
- package/dist/config/configUtils.d.ts +11 -0
- package/dist/config/configUtils.js +87 -0
- package/dist/config/dashboardConfig.d.ts +45 -0
- package/dist/config/dashboardConfig.js +63 -0
- package/dist/config/defaultValues.d.ts +61 -0
- package/dist/config/defaultValues.js +70 -0
- package/dist/config/dirConstants.d.ts +17 -0
- package/dist/config/dirConstants.js +28 -0
- package/dist/config/featureConfig.d.ts +61 -0
- package/dist/config/featureConfig.js +121 -0
- package/dist/config/runtimeConfig.d.ts +145 -0
- package/dist/config/runtimeConfig.js +334 -0
- package/dist/config/serverConfig.d.ts +90 -0
- package/dist/config/serverConfig.js +164 -0
- package/dist/dashboard/analytics/AnalyticsEngine.d.ts +142 -0
- package/dist/dashboard/analytics/AnalyticsEngine.js +373 -0
- package/dist/dashboard/analytics/BusinessIntelligence.d.ts +187 -0
- package/dist/dashboard/analytics/BusinessIntelligence.js +594 -0
- package/dist/dashboard/client/admin.html +2150 -0
- package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/chunk-SP2CHFBE.mjs +1 -0
- package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/render-T6MDALS3.mjs +27 -0
- package/dist/dashboard/client/css/admin.css +1466 -0
- package/dist/dashboard/client/js/admin.boot.js +359 -0
- package/dist/dashboard/client/js/admin.config.js +196 -0
- package/dist/dashboard/client/js/admin.embeddings.js +425 -0
- package/dist/dashboard/client/js/admin.graph.js +583 -0
- package/dist/dashboard/client/js/admin.instances.js +120 -0
- package/dist/dashboard/client/js/admin.instructions.js +552 -0
- package/dist/dashboard/client/js/admin.logs.js +113 -0
- package/dist/dashboard/client/js/admin.maintenance.js +354 -0
- package/dist/dashboard/client/js/admin.messaging.js +635 -0
- package/dist/dashboard/client/js/admin.monitor.js +181 -0
- package/dist/dashboard/client/js/admin.overview.js +221 -0
- package/dist/dashboard/client/js/admin.performance.js +61 -0
- package/dist/dashboard/client/js/admin.sessions.js +293 -0
- package/dist/dashboard/client/js/admin.sqlite.js +366 -0
- package/dist/dashboard/client/js/admin.utils.js +49 -0
- package/dist/dashboard/client/js/chart.umd.js +14 -0
- package/dist/dashboard/client/js/elk.bundled.js +6696 -0
- package/dist/dashboard/client/js/marked.umd.js +74 -0
- package/dist/dashboard/client/js/mermaid.min.js +3022 -0
- package/dist/dashboard/client/mermaid-layout-elk.esm.min.mjs +1 -0
- package/dist/dashboard/export/DataExporter.d.ts +169 -0
- package/dist/dashboard/export/DataExporter.js +737 -0
- package/dist/dashboard/export/exporters/csvExporter.d.ts +11 -0
- package/dist/dashboard/export/exporters/csvExporter.js +46 -0
- package/dist/dashboard/export/exporters/exportTypes.d.ts +89 -0
- package/dist/dashboard/export/exporters/exportTypes.js +5 -0
- package/dist/dashboard/export/exporters/jsonExporter.d.ts +7 -0
- package/dist/dashboard/export/exporters/jsonExporter.js +22 -0
- package/dist/dashboard/export/exporters/xmlExporter.d.ts +17 -0
- package/dist/dashboard/export/exporters/xmlExporter.js +175 -0
- package/dist/dashboard/integration/APIIntegration.d.ts +41 -0
- package/dist/dashboard/integration/APIIntegration.js +95 -0
- package/dist/dashboard/security/SecurityMonitor.d.ts +167 -0
- package/dist/dashboard/security/SecurityMonitor.js +559 -0
- package/dist/dashboard/server/AdminPanel.d.ts +183 -0
- package/dist/dashboard/server/AdminPanel.js +792 -0
- package/dist/dashboard/server/AdminPanelConfig.d.ts +42 -0
- package/dist/dashboard/server/AdminPanelConfig.js +80 -0
- package/dist/dashboard/server/AdminPanelState.d.ts +47 -0
- package/dist/dashboard/server/AdminPanelState.js +214 -0
- package/dist/dashboard/server/ApiRoutes.d.ts +17 -0
- package/dist/dashboard/server/ApiRoutes.js +149 -0
- package/dist/dashboard/server/DashboardServer.d.ts +49 -0
- package/dist/dashboard/server/DashboardServer.js +159 -0
- package/dist/dashboard/server/FileMetricsStorage.d.ts +49 -0
- package/dist/dashboard/server/FileMetricsStorage.js +195 -0
- package/dist/dashboard/server/HttpTransport.d.ts +23 -0
- package/dist/dashboard/server/HttpTransport.js +116 -0
- package/dist/dashboard/server/InstanceManager.d.ts +53 -0
- package/dist/dashboard/server/InstanceManager.js +284 -0
- package/dist/dashboard/server/KnowledgeStore.d.ts +35 -0
- package/dist/dashboard/server/KnowledgeStore.js +105 -0
- package/dist/dashboard/server/LeaderElection.d.ts +81 -0
- package/dist/dashboard/server/LeaderElection.js +268 -0
- package/dist/dashboard/server/MetricsCollector.d.ts +200 -0
- package/dist/dashboard/server/MetricsCollector.js +803 -0
- package/dist/dashboard/server/SessionPersistenceManager.d.ts +88 -0
- package/dist/dashboard/server/SessionPersistenceManager.js +457 -0
- package/dist/dashboard/server/ThinClient.d.ts +64 -0
- package/dist/dashboard/server/ThinClient.js +237 -0
- package/dist/dashboard/server/WebSocketManager.d.ts +161 -0
- package/dist/dashboard/server/WebSocketManager.js +463 -0
- package/dist/dashboard/server/httpLifecycle.d.ts +17 -0
- package/dist/dashboard/server/httpLifecycle.js +35 -0
- package/dist/dashboard/server/legacyDashboardHtml.d.ts +9 -0
- package/dist/dashboard/server/legacyDashboardHtml.js +618 -0
- package/dist/dashboard/server/legacyDashboardStyles.d.ts +5 -0
- package/dist/dashboard/server/legacyDashboardStyles.js +490 -0
- package/dist/dashboard/server/metricsAggregation.d.ts +252 -0
- package/dist/dashboard/server/metricsAggregation.js +206 -0
- package/dist/dashboard/server/metricsSerializer.d.ts +25 -0
- package/dist/dashboard/server/metricsSerializer.js +195 -0
- package/dist/dashboard/server/routes/admin.routes.d.ts +16 -0
- package/dist/dashboard/server/routes/admin.routes.js +596 -0
- package/dist/dashboard/server/routes/alerts.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/alerts.routes.js +93 -0
- package/dist/dashboard/server/routes/api.feedback.routes.d.ts +73 -0
- package/dist/dashboard/server/routes/api.feedback.routes.js +171 -0
- package/dist/dashboard/server/routes/api.instructions.routes.d.ts +101 -0
- package/dist/dashboard/server/routes/api.instructions.routes.js +213 -0
- package/dist/dashboard/server/routes/api.usage.routes.d.ts +57 -0
- package/dist/dashboard/server/routes/api.usage.routes.js +374 -0
- package/dist/dashboard/server/routes/embeddings.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/embeddings.routes.js +246 -0
- package/dist/dashboard/server/routes/graph.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/graph.routes.js +280 -0
- package/dist/dashboard/server/routes/index.d.ts +38 -0
- package/dist/dashboard/server/routes/index.js +194 -0
- package/dist/dashboard/server/routes/instances.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/instances.routes.js +35 -0
- package/dist/dashboard/server/routes/instructions.routes.d.ts +8 -0
- package/dist/dashboard/server/routes/instructions.routes.js +336 -0
- package/dist/dashboard/server/routes/knowledge.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/knowledge.routes.js +82 -0
- package/dist/dashboard/server/routes/logs.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/logs.routes.js +164 -0
- package/dist/dashboard/server/routes/messaging.routes.d.ts +16 -0
- package/dist/dashboard/server/routes/messaging.routes.js +293 -0
- package/dist/dashboard/server/routes/metrics.routes.d.ts +10 -0
- package/dist/dashboard/server/routes/metrics.routes.js +346 -0
- package/dist/dashboard/server/routes/scripts.routes.d.ts +9 -0
- package/dist/dashboard/server/routes/scripts.routes.js +84 -0
- package/dist/dashboard/server/routes/sqlite.routes.d.ts +9 -0
- package/dist/dashboard/server/routes/sqlite.routes.js +569 -0
- package/dist/dashboard/server/routes/status.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/status.routes.js +183 -0
- package/dist/dashboard/server/routes/synthetic.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/synthetic.routes.js +195 -0
- package/dist/dashboard/server/routes/tools.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/tools.routes.js +46 -0
- package/dist/dashboard/server/routes/usage.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/usage.routes.js +25 -0
- package/dist/dashboard/server/wsInit.d.ts +16 -0
- package/dist/dashboard/server/wsInit.js +35 -0
- package/dist/externalClientLib.d.ts +1 -0
- package/dist/externalClientLib.js +2 -0
- package/dist/minimal/index.d.ts +1 -0
- package/dist/minimal/index.js +140 -0
- package/dist/models/SessionPersistence.d.ts +115 -0
- package/dist/models/SessionPersistence.js +66 -0
- package/dist/models/instruction.d.ts +45 -0
- package/dist/models/instruction.js +2 -0
- package/dist/perf/benchmark.d.ts +1 -0
- package/dist/perf/benchmark.js +50 -0
- package/dist/portableClientWrapper.d.ts +1 -0
- package/dist/portableClientWrapper.js +2 -0
- package/dist/schemas/index.d.ts +128 -0
- package/dist/schemas/index.js +371 -0
- package/dist/scripts/runPerformanceBaseline.d.ts +1 -0
- package/dist/scripts/runPerformanceBaseline.js +17 -0
- package/dist/server/handshakeManager.d.ts +25 -0
- package/dist/server/handshakeManager.js +472 -0
- package/dist/server/index-server.d.ts +56 -0
- package/dist/server/index-server.js +822 -0
- package/dist/server/registry.d.ts +44 -0
- package/dist/server/registry.js +236 -0
- package/dist/server/sdkServer.d.ts +8 -0
- package/dist/server/sdkServer.js +299 -0
- package/dist/server/shutdownGuard.d.ts +41 -0
- package/dist/server/shutdownGuard.js +52 -0
- package/dist/server/thin-client.d.ts +22 -0
- package/dist/server/thin-client.js +111 -0
- package/dist/server/transport.d.ts +41 -0
- package/dist/server/transport.js +312 -0
- package/dist/server/transportFactory.d.ts +21 -0
- package/dist/server/transportFactory.js +429 -0
- package/dist/services/atomicFs.d.ts +22 -0
- package/dist/services/atomicFs.js +103 -0
- package/dist/services/auditLog.d.ts +38 -0
- package/dist/services/auditLog.js +142 -0
- package/dist/services/autoBackup.d.ts +14 -0
- package/dist/services/autoBackup.js +171 -0
- package/dist/services/autoSplit.d.ts +32 -0
- package/dist/services/autoSplit.js +113 -0
- package/dist/services/backupZip.d.ts +25 -0
- package/dist/services/backupZip.js +110 -0
- package/dist/services/bootstrapGating.d.ts +123 -0
- package/dist/services/bootstrapGating.js +221 -0
- package/dist/services/canonical.d.ts +23 -0
- package/dist/services/canonical.js +65 -0
- package/dist/services/categoryRules.d.ts +7 -0
- package/dist/services/categoryRules.js +37 -0
- package/dist/services/classificationService.d.ts +42 -0
- package/dist/services/classificationService.js +168 -0
- package/dist/services/embeddingService.d.ts +62 -0
- package/dist/services/embeddingService.js +259 -0
- package/dist/services/errors.d.ts +22 -0
- package/dist/services/errors.js +31 -0
- package/dist/services/featureFlags.d.ts +25 -0
- package/dist/services/featureFlags.js +89 -0
- package/dist/services/features.d.ts +13 -0
- package/dist/services/features.js +35 -0
- package/dist/services/handlers/instructions.add.d.ts +1 -0
- package/dist/services/handlers/instructions.add.js +496 -0
- package/dist/services/handlers/instructions.groom.d.ts +1 -0
- package/dist/services/handlers/instructions.groom.js +523 -0
- package/dist/services/handlers/instructions.import.d.ts +1 -0
- package/dist/services/handlers/instructions.import.js +173 -0
- package/dist/services/handlers/instructions.patch.d.ts +1 -0
- package/dist/services/handlers/instructions.patch.js +167 -0
- package/dist/services/handlers/instructions.query.d.ts +163 -0
- package/dist/services/handlers/instructions.query.js +522 -0
- package/dist/services/handlers/instructions.reload.d.ts +1 -0
- package/dist/services/handlers/instructions.reload.js +13 -0
- package/dist/services/handlers/instructions.remove.d.ts +1 -0
- package/dist/services/handlers/instructions.remove.js +118 -0
- package/dist/services/handlers/instructions.shared.d.ts +31 -0
- package/dist/services/handlers/instructions.shared.js +124 -0
- package/dist/services/handlers.activation.d.ts +1 -0
- package/dist/services/handlers.activation.js +203 -0
- package/dist/services/handlers.bootstrap.d.ts +1 -0
- package/dist/services/handlers.bootstrap.js +38 -0
- package/dist/services/handlers.dashboardConfig.d.ts +34 -0
- package/dist/services/handlers.dashboardConfig.js +108 -0
- package/dist/services/handlers.diagnostics.d.ts +1 -0
- package/dist/services/handlers.diagnostics.js +64 -0
- package/dist/services/handlers.feedback.d.ts +15 -0
- package/dist/services/handlers.feedback.js +378 -0
- package/dist/services/handlers.gates.d.ts +1 -0
- package/dist/services/handlers.gates.js +46 -0
- package/dist/services/handlers.graph.d.ts +53 -0
- package/dist/services/handlers.graph.js +231 -0
- package/dist/services/handlers.help.d.ts +1 -0
- package/dist/services/handlers.help.js +119 -0
- package/dist/services/handlers.instructionSchema.d.ts +1 -0
- package/dist/services/handlers.instructionSchema.js +227 -0
- package/dist/services/handlers.instructions.d.ts +8 -0
- package/dist/services/handlers.instructions.js +14 -0
- package/dist/services/handlers.instructionsDiagnostics.d.ts +1 -0
- package/dist/services/handlers.instructionsDiagnostics.js +14 -0
- package/dist/services/handlers.integrity.d.ts +1 -0
- package/dist/services/handlers.integrity.js +35 -0
- package/dist/services/handlers.manifest.d.ts +1 -0
- package/dist/services/handlers.manifest.js +24 -0
- package/dist/services/handlers.messaging.d.ts +12 -0
- package/dist/services/handlers.messaging.js +203 -0
- package/dist/services/handlers.metrics.d.ts +1 -0
- package/dist/services/handlers.metrics.js +43 -0
- package/dist/services/handlers.promote.d.ts +1 -0
- package/dist/services/handlers.promote.js +306 -0
- package/dist/services/handlers.prompt.d.ts +1 -0
- package/dist/services/handlers.prompt.js +7 -0
- package/dist/services/handlers.search.d.ts +69 -0
- package/dist/services/handlers.search.js +645 -0
- package/dist/services/handlers.testPrimitive.d.ts +1 -0
- package/dist/services/handlers.testPrimitive.js +5 -0
- package/dist/services/handlers.trace.d.ts +1 -0
- package/dist/services/handlers.trace.js +31 -0
- package/dist/services/handlers.usage.d.ts +1 -0
- package/dist/services/handlers.usage.js +11 -0
- package/dist/services/hotScore.d.ts +137 -0
- package/dist/services/hotScore.js +244 -0
- package/dist/services/indexContext.d.ts +117 -0
- package/dist/services/indexContext.js +968 -0
- package/dist/services/indexLoader.d.ts +44 -0
- package/dist/services/indexLoader.js +921 -0
- package/dist/services/indexRepository.d.ts +32 -0
- package/dist/services/indexRepository.js +71 -0
- package/dist/services/indexingService.d.ts +1 -0
- package/dist/services/indexingService.js +2 -0
- package/dist/services/instructions.dispatcher.d.ts +1 -0
- package/dist/services/instructions.dispatcher.js +231 -0
- package/dist/services/logPrefix.d.ts +1 -0
- package/dist/services/logPrefix.js +30 -0
- package/dist/services/logger.d.ts +52 -0
- package/dist/services/logger.js +268 -0
- package/dist/services/manifestManager.d.ts +82 -0
- package/dist/services/manifestManager.js +200 -0
- package/dist/services/messaging/agentMailbox.d.ts +60 -0
- package/dist/services/messaging/agentMailbox.js +353 -0
- package/dist/services/messaging/messagingPersistence.d.ts +20 -0
- package/dist/services/messaging/messagingPersistence.js +111 -0
- package/dist/services/messaging/messagingTypes.d.ts +150 -0
- package/dist/services/messaging/messagingTypes.js +66 -0
- package/dist/services/ownershipService.d.ts +1 -0
- package/dist/services/ownershipService.js +38 -0
- package/dist/services/performanceBaseline.d.ts +19 -0
- package/dist/services/performanceBaseline.js +210 -0
- package/dist/services/preflight.d.ts +12 -0
- package/dist/services/preflight.js +79 -0
- package/dist/services/promptReviewService.d.ts +44 -0
- package/dist/services/promptReviewService.js +101 -0
- package/dist/services/responseEnvelope.d.ts +6 -0
- package/dist/services/responseEnvelope.js +25 -0
- package/dist/services/seedBootstrap.d.ts +34 -0
- package/dist/services/seedBootstrap.js +427 -0
- package/dist/services/storage/factory.d.ts +17 -0
- package/dist/services/storage/factory.js +35 -0
- package/dist/services/storage/hashUtils.d.ts +11 -0
- package/dist/services/storage/hashUtils.js +35 -0
- package/dist/services/storage/index.d.ts +12 -0
- package/dist/services/storage/index.js +18 -0
- package/dist/services/storage/jsonFileStore.d.ts +32 -0
- package/dist/services/storage/jsonFileStore.js +241 -0
- package/dist/services/storage/migrationEngine.d.ts +35 -0
- package/dist/services/storage/migrationEngine.js +93 -0
- package/dist/services/storage/sqliteMessageStore.d.ts +53 -0
- package/dist/services/storage/sqliteMessageStore.js +146 -0
- package/dist/services/storage/sqliteSchema.d.ts +12 -0
- package/dist/services/storage/sqliteSchema.js +122 -0
- package/dist/services/storage/sqliteStore.d.ts +41 -0
- package/dist/services/storage/sqliteStore.js +339 -0
- package/dist/services/storage/sqliteUsageStore.d.ts +35 -0
- package/dist/services/storage/sqliteUsageStore.js +94 -0
- package/dist/services/storage/types.d.ts +171 -0
- package/dist/services/storage/types.js +12 -0
- package/dist/services/toolHandlers.d.ts +23 -0
- package/dist/services/toolHandlers.js +50 -0
- package/dist/services/toolRegistry.d.ts +20 -0
- package/dist/services/toolRegistry.js +490 -0
- package/dist/services/toolRegistry.zod.d.ts +10 -0
- package/dist/services/toolRegistry.zod.js +323 -0
- package/dist/services/tracing.d.ts +26 -0
- package/dist/services/tracing.js +260 -0
- package/dist/services/usageBuckets.d.ts +161 -0
- package/dist/services/usageBuckets.js +364 -0
- package/dist/services/validationService.d.ts +38 -0
- package/dist/services/validationService.js +125 -0
- package/dist/utils/BufferRing.d.ts +203 -0
- package/dist/utils/BufferRing.js +551 -0
- package/dist/utils/BufferRingExamples.d.ts +55 -0
- package/dist/utils/BufferRingExamples.js +188 -0
- package/dist/utils/envUtils.d.ts +42 -0
- package/dist/utils/envUtils.js +80 -0
- package/dist/utils/memoryMonitor.d.ts +83 -0
- package/dist/utils/memoryMonitor.js +275 -0
- package/dist/versioning/schemaVersion.d.ts +6 -0
- package/dist/versioning/schemaVersion.js +93 -0
- package/package.json +134 -0
- package/schemas/README.md +13 -0
- package/schemas/feedback-entry.schema.json +27 -0
- package/schemas/graph-export-v2.schema.json +60 -0
- package/schemas/index-server.code-schema.json +38477 -0
- package/schemas/instruction.schema.json +262 -0
- package/schemas/json-schema/SessionPersistence-persisted-admin-session.schema.json +54 -0
- package/schemas/json-schema/SessionPersistence-persisted-session-history-entry.schema.json +51 -0
- package/schemas/json-schema/SessionPersistence-persisted-web-socket-connection.schema.json +54 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-config.schema.json +110 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-data.schema.json +229 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-manifest.schema.json +109 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-metadata.schema.json +55 -0
- package/schemas/json-schema/instruction-audience-scope.schema.json +14 -0
- package/schemas/json-schema/instruction-content-type.schema.json +17 -0
- package/schemas/json-schema/instruction-instruction-entry.schema.json +206 -0
- package/schemas/json-schema/instruction-requirement-level.schema.json +16 -0
- package/schemas/manifest.json +78 -0
- package/schemas/manifest.schema.json +33 -0
- package/schemas/usage-batch.schema.json +16 -0
- package/schemas/usage-buckets.schema.json +30 -0
- package/schemas/usage-event.schema.json +17 -0
- package/scripts/copy-dashboard-assets.mjs +170 -0
- package/scripts/setup-hooks.cjs +28 -0
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MetricsCollector — coordinator class (Phase 1–4 Dashboard Foundation).
|
|
4
|
+
*
|
|
5
|
+
* Owns all mutable metrics state and delegates:
|
|
6
|
+
* - pure math to metricsAggregation.ts
|
|
7
|
+
* - output serialisation to metricsSerializer.ts
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.MetricsCollector = void 0;
|
|
14
|
+
exports.getMetricsCollector = getMetricsCollector;
|
|
15
|
+
exports.setMetricsCollector = setMetricsCollector;
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const v8_1 = __importDefault(require("v8"));
|
|
19
|
+
const FileMetricsStorage_js_1 = require("./FileMetricsStorage.js");
|
|
20
|
+
const BufferRing_js_1 = require("../../utils/BufferRing.js");
|
|
21
|
+
const runtimeConfig_1 = require("../../config/runtimeConfig");
|
|
22
|
+
const metricsAggregation_js_1 = require("./metricsAggregation.js");
|
|
23
|
+
const metricsSerializer_js_1 = require("./metricsSerializer.js");
|
|
24
|
+
class MetricsCollector {
|
|
25
|
+
tools = new Map();
|
|
26
|
+
// Resource usage samples (CPU/Memory) for leak/trend analysis
|
|
27
|
+
resourceSamples;
|
|
28
|
+
lastCpuUsageSample = null;
|
|
29
|
+
lastCpuSampleTime = 0;
|
|
30
|
+
snapshots = []; // Keep small in-memory cache for real-time queries
|
|
31
|
+
connections = new Set();
|
|
32
|
+
disconnectedCount = 0;
|
|
33
|
+
totalSessionTime = 0;
|
|
34
|
+
sessionStartTimes = new Map();
|
|
35
|
+
startTime = Date.now();
|
|
36
|
+
options;
|
|
37
|
+
collectTimer;
|
|
38
|
+
lastCpuUsage;
|
|
39
|
+
// Phase 4: Advanced features
|
|
40
|
+
recentAlerts = [];
|
|
41
|
+
activeConnections = 0;
|
|
42
|
+
// Rolling timestamp buffer for recent tool calls (used for stable RPM calculation)
|
|
43
|
+
recentCallTimestamps = [];
|
|
44
|
+
static MAX_RECENT_CALLS = 10000; // cap to avoid unbounded growth
|
|
45
|
+
static MAX_MEMORY_SNAPSHOTS = 60; // Keep only 1 hour in memory
|
|
46
|
+
static MAX_TOOL_METRICS = 1000; // cap tool metrics to prevent memory leaks
|
|
47
|
+
// File storage for historical data (optional)
|
|
48
|
+
fileStorage = null;
|
|
49
|
+
useFileStorage;
|
|
50
|
+
// BufferRing-Enhanced Storage
|
|
51
|
+
historicalSnapshots;
|
|
52
|
+
toolCallEvents;
|
|
53
|
+
// Persistence throttling state for tool call events (defined explicitly to avoid dynamic props)
|
|
54
|
+
_lastToolPersist = 0;
|
|
55
|
+
_pendingToolPersist = 0;
|
|
56
|
+
performanceMetrics;
|
|
57
|
+
bufferConfig;
|
|
58
|
+
// Append/segment logging state (optional)
|
|
59
|
+
appendMode = false;
|
|
60
|
+
appendLogPath = null;
|
|
61
|
+
pendingAppendEvents = [];
|
|
62
|
+
lastAppendFlush = 0;
|
|
63
|
+
lastAppendCompact = 0;
|
|
64
|
+
appendChunkSize = 250;
|
|
65
|
+
appendFlushMs = 5000;
|
|
66
|
+
appendCompactMs = 5 * 60 * 1000; // 5 min default
|
|
67
|
+
constructor(options = {}) {
|
|
68
|
+
this.options = {
|
|
69
|
+
retentionMinutes: options.retentionMinutes ?? 60,
|
|
70
|
+
maxSnapshots: options.maxSnapshots ?? 720, // 12 hours at 1-minute intervals
|
|
71
|
+
collectInterval: options.collectInterval ?? 60000, // 1 minute
|
|
72
|
+
};
|
|
73
|
+
const metricsConfig = (0, runtimeConfig_1.getRuntimeConfig)().metrics;
|
|
74
|
+
// Initialize resource sampling buffer (default capacity ~1h at 5s interval = 720)
|
|
75
|
+
const resourceCapacity = Math.max(1, metricsConfig.resourceCapacity || 720);
|
|
76
|
+
this.resourceSamples = new BufferRing_js_1.BufferRing({
|
|
77
|
+
capacity: resourceCapacity,
|
|
78
|
+
overflowStrategy: BufferRing_js_1.OverflowStrategy.DROP_OLDEST,
|
|
79
|
+
autoPersist: false,
|
|
80
|
+
enableIntegrityCheck: false
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
const intervalMs = Math.max(100, metricsConfig.sampleIntervalMs || 5000);
|
|
84
|
+
setInterval(() => this.sampleResources(), intervalMs).unref();
|
|
85
|
+
}
|
|
86
|
+
catch { /* ignore */ }
|
|
87
|
+
// Configure BufferRing settings
|
|
88
|
+
const metricsDir = metricsConfig.dir || path_1.default.join(process.cwd(), 'metrics');
|
|
89
|
+
this.bufferConfig = {
|
|
90
|
+
historicalSnapshots: {
|
|
91
|
+
capacity: this.options.maxSnapshots,
|
|
92
|
+
retentionMinutes: this.options.retentionMinutes * 12, // Keep 12x longer than original
|
|
93
|
+
persistenceFile: path_1.default.join(metricsDir, 'historical-snapshots.json')
|
|
94
|
+
},
|
|
95
|
+
toolCallEvents: {
|
|
96
|
+
capacity: 10000, // Store last 10k tool calls
|
|
97
|
+
retentionMinutes: this.options.retentionMinutes * 2, // 2 hours of tool calls
|
|
98
|
+
persistenceFile: path_1.default.join(metricsDir, 'tool-call-events.json')
|
|
99
|
+
},
|
|
100
|
+
performanceMetrics: {
|
|
101
|
+
capacity: 1440, // Store 24 hours worth of minute-by-minute metrics
|
|
102
|
+
persistenceFile: path_1.default.join(metricsDir, 'performance-metrics.json')
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
// Check if file storage should be enabled (accept "true", "1", "yes", "on")
|
|
106
|
+
this.useFileStorage = metricsConfig.fileStorage;
|
|
107
|
+
// Initialize BufferRing storage
|
|
108
|
+
this.historicalSnapshots = new BufferRing_js_1.BufferRing({
|
|
109
|
+
capacity: this.bufferConfig.historicalSnapshots.capacity,
|
|
110
|
+
overflowStrategy: BufferRing_js_1.OverflowStrategy.DROP_OLDEST,
|
|
111
|
+
persistPath: this.useFileStorage ? this.bufferConfig.historicalSnapshots.persistenceFile : undefined,
|
|
112
|
+
autoPersist: this.useFileStorage
|
|
113
|
+
});
|
|
114
|
+
this.toolCallEvents = new BufferRing_js_1.BufferRing({
|
|
115
|
+
capacity: this.bufferConfig.toolCallEvents.capacity,
|
|
116
|
+
overflowStrategy: BufferRing_js_1.OverflowStrategy.DROP_OLDEST,
|
|
117
|
+
persistPath: this.useFileStorage ? this.bufferConfig.toolCallEvents.persistenceFile : undefined,
|
|
118
|
+
autoPersist: false, // we'll manage chunked persistence manually for performance
|
|
119
|
+
suppressPersistLog: true
|
|
120
|
+
});
|
|
121
|
+
this.performanceMetrics = new BufferRing_js_1.BufferRing({
|
|
122
|
+
capacity: this.bufferConfig.performanceMetrics.capacity,
|
|
123
|
+
overflowStrategy: BufferRing_js_1.OverflowStrategy.DROP_OLDEST,
|
|
124
|
+
persistPath: this.useFileStorage ? this.bufferConfig.performanceMetrics.persistenceFile : undefined,
|
|
125
|
+
autoPersist: this.useFileStorage
|
|
126
|
+
});
|
|
127
|
+
// Configure optional append-only logging for tool call events (reduces large snapshot writes)
|
|
128
|
+
if (this.useFileStorage) {
|
|
129
|
+
this.appendMode = metricsConfig.toolcall.appendLogEnabled;
|
|
130
|
+
if (this.appendMode) {
|
|
131
|
+
this.appendLogPath = path_1.default.join(path_1.default.dirname(this.bufferConfig.toolCallEvents.persistenceFile), 'tool-call-events.ndjson');
|
|
132
|
+
this.appendChunkSize = Math.max(1, metricsConfig.toolcall.chunkSize || this.appendChunkSize);
|
|
133
|
+
this.appendFlushMs = Math.max(1, metricsConfig.toolcall.flushMs || this.appendFlushMs);
|
|
134
|
+
this.appendCompactMs = Math.max(1, metricsConfig.toolcall.compactMs || this.appendCompactMs);
|
|
135
|
+
try {
|
|
136
|
+
// Load any un-compacted append log tail (best-effort)
|
|
137
|
+
if (this.appendLogPath && fs_1.default.existsSync(this.appendLogPath)) {
|
|
138
|
+
const stat = fs_1.default.statSync(this.appendLogPath);
|
|
139
|
+
if (stat.size < 25 * 1024 * 1024) { // safety cap 25MB
|
|
140
|
+
const raw = fs_1.default.readFileSync(this.appendLogPath, 'utf8');
|
|
141
|
+
const lines = raw.split(/\r?\n/).filter(l => l.trim().length > 0);
|
|
142
|
+
for (const line of lines) {
|
|
143
|
+
try {
|
|
144
|
+
const evt = JSON.parse(line);
|
|
145
|
+
this.toolCallEvents.add(evt);
|
|
146
|
+
}
|
|
147
|
+
catch { /* ignore bad line */ }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.warn('tool-call-events.ndjson too large to preload (>25MB); will rely on last snapshot');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
console.warn('Failed to preload append log', err);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (this.useFileStorage) {
|
|
161
|
+
// Initialize legacy file storage for backward compatibility
|
|
162
|
+
this.fileStorage = (0, FileMetricsStorage_js_1.getFileMetricsStorage)({
|
|
163
|
+
storageDir: metricsDir,
|
|
164
|
+
maxFiles: this.options.maxSnapshots,
|
|
165
|
+
retentionMinutes: this.options.retentionMinutes,
|
|
166
|
+
});
|
|
167
|
+
console.error('📊 MetricsCollector: BufferRing + File storage enabled');
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
console.error('📊 MetricsCollector: BufferRing memory-only mode (set INDEX_SERVER_METRICS_FILE_STORAGE=1|true|yes|on for persistence)');
|
|
171
|
+
}
|
|
172
|
+
// Start periodic collection
|
|
173
|
+
this.startCollection();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Record a tool call event
|
|
177
|
+
*/
|
|
178
|
+
recordToolCall(toolName, success, responseTimeMs, errorType, clientId) {
|
|
179
|
+
const now = Date.now();
|
|
180
|
+
if (!this.tools.has(toolName)) {
|
|
181
|
+
this.tools.set(toolName, {
|
|
182
|
+
callCount: 0,
|
|
183
|
+
successCount: 0,
|
|
184
|
+
errorCount: 0,
|
|
185
|
+
totalResponseTime: 0,
|
|
186
|
+
errorTypes: {},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const metrics = this.tools.get(toolName);
|
|
190
|
+
metrics.callCount++;
|
|
191
|
+
metrics.totalResponseTime += responseTimeMs;
|
|
192
|
+
metrics.lastCalled = now;
|
|
193
|
+
if (success) {
|
|
194
|
+
metrics.successCount++;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
metrics.errorCount++;
|
|
198
|
+
if (errorType) {
|
|
199
|
+
metrics.errorTypes[errorType] = (metrics.errorTypes[errorType] || 0) + 1;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Store detailed tool call event in BufferRing
|
|
203
|
+
this.toolCallEvents.add({
|
|
204
|
+
timestamp: now,
|
|
205
|
+
toolName,
|
|
206
|
+
success,
|
|
207
|
+
responseTimeMs,
|
|
208
|
+
errorType,
|
|
209
|
+
clientId
|
|
210
|
+
});
|
|
211
|
+
if (this.useFileStorage) {
|
|
212
|
+
if (this.appendMode) {
|
|
213
|
+
this.pendingAppendEvents.push({ timestamp: now, toolName, success, responseTimeMs, errorType, clientId });
|
|
214
|
+
this.flushToolCallEvents(false); // schedule conditional flush
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// legacy snapshot batching (retain previous throttling fields)
|
|
218
|
+
this._pendingToolPersist++;
|
|
219
|
+
const dueTime = now - this._lastToolPersist > this.appendFlushMs;
|
|
220
|
+
if (this._pendingToolPersist >= this.appendChunkSize || dueTime) {
|
|
221
|
+
setTimeout(() => {
|
|
222
|
+
this.toolCallEvents.saveToDisk().catch(() => { });
|
|
223
|
+
this._lastToolPersist = Date.now();
|
|
224
|
+
this._pendingToolPersist = 0;
|
|
225
|
+
}, 0).unref?.();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Track call timestamp for rolling RPM calculation (last 60s window)
|
|
230
|
+
this.recentCallTimestamps.push(now);
|
|
231
|
+
// Prune anything older than 5 minutes to constrain memory
|
|
232
|
+
const cutoff = now - 5 * 60 * 1000;
|
|
233
|
+
if (this.recentCallTimestamps.length > MetricsCollector.MAX_RECENT_CALLS || (this.recentCallTimestamps.length % 100) === 0) {
|
|
234
|
+
// Periodically prune (on every 100th push or when over cap)
|
|
235
|
+
let firstValidIdx = 0;
|
|
236
|
+
while (firstValidIdx < this.recentCallTimestamps.length && this.recentCallTimestamps[firstValidIdx] < cutoff)
|
|
237
|
+
firstValidIdx++;
|
|
238
|
+
if (firstValidIdx > 0)
|
|
239
|
+
this.recentCallTimestamps.splice(0, firstValidIdx);
|
|
240
|
+
// Hard cap safeguard
|
|
241
|
+
if (this.recentCallTimestamps.length > MetricsCollector.MAX_RECENT_CALLS) {
|
|
242
|
+
this.recentCallTimestamps.splice(0, this.recentCallTimestamps.length - MetricsCollector.MAX_RECENT_CALLS);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// Prevent unbounded tool metrics growth - cleanup old/unused tools after adding the new tool
|
|
246
|
+
if (this.tools.size > MetricsCollector.MAX_TOOL_METRICS) {
|
|
247
|
+
this.cleanupOldToolMetrics();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** Flush tool call events (append or snapshot) */
|
|
251
|
+
flushToolCallEvents(force) {
|
|
252
|
+
if (!this.useFileStorage)
|
|
253
|
+
return;
|
|
254
|
+
const now = Date.now();
|
|
255
|
+
if (this.appendMode) {
|
|
256
|
+
const timeDue = (now - this.lastAppendFlush) >= this.appendFlushMs;
|
|
257
|
+
if (!force && this.pendingAppendEvents.length < this.appendChunkSize && !timeDue)
|
|
258
|
+
return;
|
|
259
|
+
if (!this.appendLogPath || this.pendingAppendEvents.length === 0)
|
|
260
|
+
return;
|
|
261
|
+
const toWrite = this.pendingAppendEvents.splice(0, this.pendingAppendEvents.length);
|
|
262
|
+
const lines = toWrite.map(e => JSON.stringify(e)).join('\n') + '\n';
|
|
263
|
+
fs_1.default.promises.appendFile(this.appendLogPath, lines).catch(() => { });
|
|
264
|
+
this.lastAppendFlush = now;
|
|
265
|
+
// Periodic compaction: write full snapshot & truncate log
|
|
266
|
+
if ((now - this.lastAppendCompact) >= this.appendCompactMs || force) {
|
|
267
|
+
this.toolCallEvents.saveToDisk().catch(() => { });
|
|
268
|
+
this.lastAppendCompact = now;
|
|
269
|
+
if (this.appendLogPath) {
|
|
270
|
+
fs_1.default.promises.writeFile(this.appendLogPath, '').catch(() => { }); // truncate
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// snapshot mode manual force
|
|
276
|
+
if (force) {
|
|
277
|
+
this.toolCallEvents.saveToDisk().catch(() => { });
|
|
278
|
+
this._lastToolPersist = now;
|
|
279
|
+
this._pendingToolPersist = 0;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Record client connection
|
|
285
|
+
*/
|
|
286
|
+
recordConnection(clientId) {
|
|
287
|
+
this.connections.add(clientId);
|
|
288
|
+
this.sessionStartTimes.set(clientId, Date.now());
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Record client disconnection
|
|
292
|
+
*/
|
|
293
|
+
recordDisconnection(clientId) {
|
|
294
|
+
if (this.connections.has(clientId)) {
|
|
295
|
+
this.connections.delete(clientId);
|
|
296
|
+
this.disconnectedCount++;
|
|
297
|
+
const sessionStart = this.sessionStartTimes.get(clientId);
|
|
298
|
+
if (sessionStart) {
|
|
299
|
+
this.totalSessionTime += Date.now() - sessionStart;
|
|
300
|
+
this.sessionStartTimes.delete(clientId);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get current metrics snapshot
|
|
306
|
+
*/
|
|
307
|
+
getCurrentSnapshot() {
|
|
308
|
+
const now = Date.now();
|
|
309
|
+
const uptime = now - this.startTime;
|
|
310
|
+
// Calculate performance metrics
|
|
311
|
+
const totalCalls = Array.from(this.tools.values()).reduce((sum, tool) => sum + tool.callCount, 0);
|
|
312
|
+
const totalSuccesses = Array.from(this.tools.values()).reduce((sum, tool) => sum + tool.successCount, 0);
|
|
313
|
+
const totalErrors = Array.from(this.tools.values()).reduce((sum, tool) => sum + tool.errorCount, 0);
|
|
314
|
+
const totalResponseTime = Array.from(this.tools.values()).reduce((sum, tool) => sum + tool.totalResponseTime, 0);
|
|
315
|
+
// Stable rolling Requests Per Minute based on last 60s calls (not lifetime average)
|
|
316
|
+
const oneMinuteCutoff = now - 60 * 1000;
|
|
317
|
+
let recentCount = 0;
|
|
318
|
+
// Iterate from end backwards until we exit window (timestamps are append-only & ascending)
|
|
319
|
+
for (let i = this.recentCallTimestamps.length - 1; i >= 0; i--) {
|
|
320
|
+
const ts = this.recentCallTimestamps[i];
|
|
321
|
+
if (ts >= oneMinuteCutoff)
|
|
322
|
+
recentCount++;
|
|
323
|
+
else
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
const requestsPerMinute = recentCount;
|
|
327
|
+
const successRate = totalCalls > 0 ? (totalSuccesses / totalCalls) * 100 : 100;
|
|
328
|
+
const avgResponseTime = totalCalls > 0 ? (totalResponseTime / totalCalls) : 0;
|
|
329
|
+
const errorRate = totalCalls > 0 ? (totalErrors / totalCalls) * 100 : 0;
|
|
330
|
+
// Calculate average session duration
|
|
331
|
+
const activeSessionTime = Array.from(this.sessionStartTimes.values())
|
|
332
|
+
.reduce((sum, startTime) => sum + (now - startTime), 0);
|
|
333
|
+
const totalSessions = this.disconnectedCount + this.connections.size;
|
|
334
|
+
const avgSessionDuration = totalSessions > 0
|
|
335
|
+
? (this.totalSessionTime + activeSessionTime) / totalSessions
|
|
336
|
+
: 0;
|
|
337
|
+
// Get CPU usage (if available)
|
|
338
|
+
let cpuUsage;
|
|
339
|
+
try {
|
|
340
|
+
cpuUsage = process.cpuUsage(this.lastCpuUsage);
|
|
341
|
+
this.lastCpuUsage = process.cpuUsage();
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// CPU usage not available on all platforms
|
|
345
|
+
}
|
|
346
|
+
const memUsage = process.memoryUsage();
|
|
347
|
+
let heapLimit;
|
|
348
|
+
try {
|
|
349
|
+
heapLimit = v8_1.default.getHeapStatistics().heap_size_limit;
|
|
350
|
+
}
|
|
351
|
+
catch { /* v8 not available */ }
|
|
352
|
+
return {
|
|
353
|
+
timestamp: now,
|
|
354
|
+
server: {
|
|
355
|
+
uptime,
|
|
356
|
+
version: this.getVersion(),
|
|
357
|
+
memoryUsage: { ...memUsage, ...(heapLimit ? { heapLimit } : {}) },
|
|
358
|
+
cpuUsage,
|
|
359
|
+
startTime: this.startTime,
|
|
360
|
+
},
|
|
361
|
+
tools: Object.fromEntries(this.tools.entries()),
|
|
362
|
+
connections: {
|
|
363
|
+
activeConnections: this.connections.size,
|
|
364
|
+
totalConnections: this.disconnectedCount + this.connections.size,
|
|
365
|
+
disconnectedConnections: this.disconnectedCount,
|
|
366
|
+
avgSessionDuration,
|
|
367
|
+
},
|
|
368
|
+
performance: {
|
|
369
|
+
requestsPerMinute,
|
|
370
|
+
successRate,
|
|
371
|
+
avgResponseTime,
|
|
372
|
+
errorRate,
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Get historical snapshots (from memory for recent, or from files for historical)
|
|
378
|
+
*/
|
|
379
|
+
getSnapshots(count) {
|
|
380
|
+
if (count) {
|
|
381
|
+
return this.snapshots.slice(-count);
|
|
382
|
+
}
|
|
383
|
+
return [...this.snapshots];
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Get snapshots from file storage (for historical analysis)
|
|
387
|
+
*/
|
|
388
|
+
async getHistoricalSnapshots(count = 720) {
|
|
389
|
+
if (!this.fileStorage) {
|
|
390
|
+
console.warn('File storage not enabled, returning memory snapshots only');
|
|
391
|
+
return this.getSnapshots(count);
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
return await this.fileStorage.getRecentSnapshots(count);
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
console.error('Failed to load historical snapshots:', error);
|
|
398
|
+
return [];
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Get snapshots within a specific time range from files
|
|
403
|
+
*/
|
|
404
|
+
async getSnapshotsInRange(startTime, endTime) {
|
|
405
|
+
if (!this.fileStorage) {
|
|
406
|
+
console.warn('File storage not enabled, filtering memory snapshots');
|
|
407
|
+
return this.snapshots.filter(s => s.timestamp >= startTime && s.timestamp <= endTime);
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
return await this.fileStorage.getSnapshotsInRange(startTime, endTime);
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
console.error('Failed to load snapshots in range:', error);
|
|
414
|
+
return [];
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Get file storage statistics
|
|
419
|
+
*/
|
|
420
|
+
async getStorageStats() {
|
|
421
|
+
if (!this.fileStorage) {
|
|
422
|
+
return {
|
|
423
|
+
fileCount: 0,
|
|
424
|
+
totalSizeKB: 0,
|
|
425
|
+
memorySnapshots: this.snapshots.length,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const fileStats = await this.fileStorage.getStorageStats();
|
|
429
|
+
return {
|
|
430
|
+
...fileStats,
|
|
431
|
+
memorySnapshots: this.snapshots.length,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Get tool-specific metrics
|
|
436
|
+
*/
|
|
437
|
+
getToolMetrics(toolName) {
|
|
438
|
+
if (toolName) {
|
|
439
|
+
return this.tools.get(toolName) || null;
|
|
440
|
+
}
|
|
441
|
+
return Object.fromEntries(this.tools.entries());
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Clear all metrics data (memory and files)
|
|
445
|
+
*/
|
|
446
|
+
async clearMetrics() {
|
|
447
|
+
// Clear in-memory data
|
|
448
|
+
this.tools.clear();
|
|
449
|
+
this.snapshots.length = 0;
|
|
450
|
+
this.connections.clear();
|
|
451
|
+
this.disconnectedCount = 0;
|
|
452
|
+
this.totalSessionTime = 0;
|
|
453
|
+
this.sessionStartTimes.clear();
|
|
454
|
+
this.startTime = Date.now();
|
|
455
|
+
this.recentCallTimestamps.length = 0;
|
|
456
|
+
// Clear file storage if enabled
|
|
457
|
+
if (this.fileStorage) {
|
|
458
|
+
try {
|
|
459
|
+
await this.fileStorage.clearAll();
|
|
460
|
+
}
|
|
461
|
+
catch (error) {
|
|
462
|
+
console.error('Failed to clear file storage:', error);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Clear only memory data (keep files)
|
|
468
|
+
*/
|
|
469
|
+
clearMemoryMetrics() {
|
|
470
|
+
this.tools.clear();
|
|
471
|
+
this.snapshots.length = 0;
|
|
472
|
+
this.connections.clear();
|
|
473
|
+
this.disconnectedCount = 0;
|
|
474
|
+
this.totalSessionTime = 0;
|
|
475
|
+
this.sessionStartTimes.clear();
|
|
476
|
+
this.startTime = Date.now();
|
|
477
|
+
this.recentCallTimestamps.length = 0;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Stop metrics collection
|
|
481
|
+
*/
|
|
482
|
+
stop() {
|
|
483
|
+
if (this.collectTimer) {
|
|
484
|
+
clearInterval(this.collectTimer);
|
|
485
|
+
this.collectTimer = undefined;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
startCollection() {
|
|
489
|
+
// Take initial snapshot
|
|
490
|
+
this.takeSnapshot();
|
|
491
|
+
// Schedule periodic snapshots
|
|
492
|
+
this.collectTimer = setInterval(() => {
|
|
493
|
+
this.takeSnapshot();
|
|
494
|
+
}, this.options.collectInterval);
|
|
495
|
+
}
|
|
496
|
+
takeSnapshot() {
|
|
497
|
+
const snapshot = this.getCurrentSnapshot();
|
|
498
|
+
// Store enhanced snapshot in BufferRing with performance data
|
|
499
|
+
const timeSeriesEntry = {
|
|
500
|
+
timestamp: snapshot.timestamp,
|
|
501
|
+
snapshot,
|
|
502
|
+
performanceData: {
|
|
503
|
+
responseTimeMs: snapshot.performance.avgResponseTime,
|
|
504
|
+
requestCount: Array.from(this.tools.values()).reduce((sum, tool) => sum + tool.callCount, 0),
|
|
505
|
+
errorCount: Array.from(this.tools.values()).reduce((sum, tool) => sum + tool.errorCount, 0),
|
|
506
|
+
connectionCount: snapshot.connections.activeConnections
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
this.historicalSnapshots.add(timeSeriesEntry);
|
|
510
|
+
// Store performance metrics for charting
|
|
511
|
+
this.performanceMetrics.add({
|
|
512
|
+
timestamp: snapshot.timestamp,
|
|
513
|
+
responseTime: snapshot.performance.avgResponseTime,
|
|
514
|
+
throughput: snapshot.performance.requestsPerMinute,
|
|
515
|
+
errorRate: snapshot.performance.errorRate
|
|
516
|
+
});
|
|
517
|
+
// Store to file immediately (async, non-blocking) if file storage enabled
|
|
518
|
+
if (this.fileStorage) {
|
|
519
|
+
this.fileStorage.storeSnapshot(snapshot).catch(error => {
|
|
520
|
+
console.error('Failed to store metrics snapshot to file:', error);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
// Keep limited snapshots in memory for real-time queries
|
|
524
|
+
this.snapshots.push(snapshot);
|
|
525
|
+
// Trim in-memory snapshots to prevent memory accumulation
|
|
526
|
+
const maxMemorySnapshots = this.useFileStorage
|
|
527
|
+
? MetricsCollector.MAX_MEMORY_SNAPSHOTS
|
|
528
|
+
: this.options.maxSnapshots;
|
|
529
|
+
if (this.snapshots.length > maxMemorySnapshots) {
|
|
530
|
+
this.snapshots.splice(0, this.snapshots.length - maxMemorySnapshots);
|
|
531
|
+
}
|
|
532
|
+
// If not using file storage, apply original retention logic
|
|
533
|
+
if (!this.useFileStorage) {
|
|
534
|
+
const cutoff = Date.now() - (this.options.retentionMinutes * 60 * 1000);
|
|
535
|
+
const firstValidIndex = this.snapshots.findIndex(s => s.timestamp >= cutoff);
|
|
536
|
+
if (firstValidIndex > 0) {
|
|
537
|
+
this.snapshots.splice(0, firstValidIndex);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
// Periodically cleanup tool metrics (every 10 snapshots, ~10 minutes)
|
|
541
|
+
if (this.snapshots.length % 10 === 0) {
|
|
542
|
+
this.cleanupOldToolMetrics();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
getVersion() {
|
|
546
|
+
try {
|
|
547
|
+
const candidates = [
|
|
548
|
+
path_1.default.join(process.cwd(), 'package.json'),
|
|
549
|
+
path_1.default.join(__dirname, '..', '..', '..', 'package.json')
|
|
550
|
+
];
|
|
551
|
+
for (const candidate of candidates) {
|
|
552
|
+
if (fs_1.default.existsSync(candidate)) {
|
|
553
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(candidate, 'utf8'));
|
|
554
|
+
if (pkg?.version)
|
|
555
|
+
return pkg.version;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch {
|
|
560
|
+
// Ignore errors
|
|
561
|
+
}
|
|
562
|
+
return '0.0.0';
|
|
563
|
+
}
|
|
564
|
+
// ====== Phase 3: Real-time Chart Data Methods ======
|
|
565
|
+
getRealtimeMetrics() {
|
|
566
|
+
return (0, metricsSerializer_js_1.buildRealtimeMetrics)(this.getCurrentSnapshot(), this.tools);
|
|
567
|
+
}
|
|
568
|
+
getToolUsageChartData(minutes = 60) {
|
|
569
|
+
return (0, metricsSerializer_js_1.buildToolUsageChartData)(this.snapshots, minutes);
|
|
570
|
+
}
|
|
571
|
+
getPerformanceChartData(minutes = 60) {
|
|
572
|
+
return (0, metricsSerializer_js_1.buildPerformanceChartData)(this.snapshots, minutes);
|
|
573
|
+
}
|
|
574
|
+
getTimeRangeMetrics(range) {
|
|
575
|
+
const rangeMinutes = { '1h': 60, '6h': 360, '24h': 1440, '7d': 10080, '30d': 43200 };
|
|
576
|
+
const cutoff = Date.now() - rangeMinutes[range] * 60_000;
|
|
577
|
+
return this.snapshots.filter(s => s.timestamp >= cutoff);
|
|
578
|
+
}
|
|
579
|
+
// ====== Phase 4: Advanced Real-time & Analytics Methods ======
|
|
580
|
+
getRealtimeStreamingData() {
|
|
581
|
+
const recentSnaps10 = this.snapshots.slice(-10);
|
|
582
|
+
const latency = recentSnaps10.length > 0
|
|
583
|
+
? recentSnaps10.reduce((s, snap) => s + snap.performance.avgResponseTime, 0) / recentSnaps10.length
|
|
584
|
+
: 0;
|
|
585
|
+
return {
|
|
586
|
+
timestamp: Date.now(),
|
|
587
|
+
systemHealth: this.getSystemHealth(),
|
|
588
|
+
performanceMetrics: this.getDetailedPerformanceMetrics(),
|
|
589
|
+
recentActivity: (0, metricsSerializer_js_1.buildRecentActivity)(this.tools),
|
|
590
|
+
streamingStats: {
|
|
591
|
+
totalStreamingConnections: this.activeConnections,
|
|
592
|
+
dataTransferRate: this.connections.size * 0.1 + Math.random() * 0.5,
|
|
593
|
+
latency,
|
|
594
|
+
compressionRatio: 0.7,
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
getSystemHealth() {
|
|
599
|
+
const cpu = (0, metricsAggregation_js_1.estimateCPUUsage)(this.snapshots.slice(-5));
|
|
600
|
+
const memory = (0, metricsAggregation_js_1.estimateMemoryUsage)(this.connections.size, this.snapshots.length);
|
|
601
|
+
return {
|
|
602
|
+
cpuUsage: cpu,
|
|
603
|
+
memoryUsage: memory,
|
|
604
|
+
diskUsage: (0, metricsAggregation_js_1.estimateDiskUsage)(this.snapshots.length),
|
|
605
|
+
networkLatency: (0, metricsAggregation_js_1.getAverageResponseTime)(this.tools),
|
|
606
|
+
uptime: Date.now() - this.startTime,
|
|
607
|
+
lastHealthCheck: new Date(),
|
|
608
|
+
status: (0, metricsAggregation_js_1.getOverallHealthStatus)(cpu, memory, (0, metricsAggregation_js_1.getErrorRate)(this.tools)),
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
getDetailedPerformanceMetrics() {
|
|
612
|
+
const totalRequests = (0, metricsAggregation_js_1.getTotalRequests)(this.tools);
|
|
613
|
+
const avg = (0, metricsAggregation_js_1.getAverageResponseTime)(this.tools);
|
|
614
|
+
const rps = (0, metricsAggregation_js_1.calculateRequestsPerSecond)(this.snapshots);
|
|
615
|
+
return {
|
|
616
|
+
requestThroughput: rps * 60,
|
|
617
|
+
averageResponseTime: avg,
|
|
618
|
+
p95ResponseTime: (0, metricsAggregation_js_1.calculatePercentileFromAvg)(avg, 95),
|
|
619
|
+
p99ResponseTime: (0, metricsAggregation_js_1.calculatePercentileFromAvg)(avg, 99),
|
|
620
|
+
errorRate: (0, metricsAggregation_js_1.getErrorRate)(this.tools),
|
|
621
|
+
concurrentConnections: this.activeConnections,
|
|
622
|
+
totalRequests,
|
|
623
|
+
successfulRequests: totalRequests - (0, metricsAggregation_js_1.getTotalErrors)(this.tools),
|
|
624
|
+
requestsPerSecond: rps,
|
|
625
|
+
bytesTransferred: totalRequests * 1024 * 2,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
getAdvancedAnalytics(timeRange = '1h') {
|
|
629
|
+
return (0, metricsSerializer_js_1.buildAdvancedAnalytics)(timeRange, this.snapshots, this.tools, (0, metricsAggregation_js_1.getErrorRate)(this.tools), (0, metricsAggregation_js_1.detectAnomalies)(this.snapshots.slice(-20)));
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Generate real-time alert
|
|
633
|
+
*/
|
|
634
|
+
generateRealTimeAlert(type, severity, message, value, threshold) {
|
|
635
|
+
const alert = {
|
|
636
|
+
id: `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
637
|
+
type: type,
|
|
638
|
+
severity: severity,
|
|
639
|
+
message,
|
|
640
|
+
timestamp: new Date(),
|
|
641
|
+
resolved: false,
|
|
642
|
+
value,
|
|
643
|
+
threshold,
|
|
644
|
+
source: 'MetricsCollector',
|
|
645
|
+
category: (0, metricsAggregation_js_1.categorizeAlert)(type)
|
|
646
|
+
};
|
|
647
|
+
this.recentAlerts.unshift(alert);
|
|
648
|
+
if (this.recentAlerts.length > 100) {
|
|
649
|
+
this.recentAlerts = this.recentAlerts.slice(0, 100);
|
|
650
|
+
}
|
|
651
|
+
return alert;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Get active alerts
|
|
655
|
+
*/
|
|
656
|
+
getActiveAlerts() {
|
|
657
|
+
return this.recentAlerts.filter(alert => !alert.resolved);
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Resolve alert by ID
|
|
661
|
+
*/
|
|
662
|
+
resolveAlert(alertId) {
|
|
663
|
+
const alert = this.recentAlerts.find(a => a.id === alertId);
|
|
664
|
+
if (alert) {
|
|
665
|
+
alert.resolved = true;
|
|
666
|
+
alert.resolvedAt = new Date();
|
|
667
|
+
return true;
|
|
668
|
+
}
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
// ===== Resource Sampling / Leak Detection =====
|
|
672
|
+
sampleResources() {
|
|
673
|
+
try {
|
|
674
|
+
const now = Date.now();
|
|
675
|
+
const mem = process.memoryUsage();
|
|
676
|
+
let cpuPercent = 0;
|
|
677
|
+
const curr = process.cpuUsage();
|
|
678
|
+
if (this.lastCpuUsageSample && this.lastCpuSampleTime) {
|
|
679
|
+
const userDiff = curr.user - this.lastCpuUsageSample.user; // microseconds
|
|
680
|
+
const systemDiff = curr.system - this.lastCpuUsageSample.system;
|
|
681
|
+
const elapsedMs = now - this.lastCpuSampleTime;
|
|
682
|
+
if (elapsedMs > 0) {
|
|
683
|
+
// total diff in microseconds / (elapsedMs * 1000) gives fraction of single core; *100 -> percent
|
|
684
|
+
cpuPercent = ((userDiff + systemDiff) / 1000) / elapsedMs * 100;
|
|
685
|
+
// Clamp 0-100 (single process perspective)
|
|
686
|
+
if (cpuPercent < 0)
|
|
687
|
+
cpuPercent = 0;
|
|
688
|
+
else if (cpuPercent > 100)
|
|
689
|
+
cpuPercent = 100;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
this.lastCpuUsageSample = curr;
|
|
693
|
+
this.lastCpuSampleTime = now;
|
|
694
|
+
this.resourceSamples.add({ timestamp: now, cpuPercent, heapUsed: mem.heapUsed, rss: mem.rss });
|
|
695
|
+
}
|
|
696
|
+
catch { /* ignore sampling errors */ }
|
|
697
|
+
}
|
|
698
|
+
getResourceHistory(limit = 200) {
|
|
699
|
+
const all = this.resourceSamples.getAll();
|
|
700
|
+
const samples = limit > 0 ? all.slice(-limit) : all;
|
|
701
|
+
const trend = (0, metricsAggregation_js_1.calculateLinearSlopes)(samples);
|
|
702
|
+
return { samples, trend };
|
|
703
|
+
}
|
|
704
|
+
/** Remove stale / low-activity tool entries to prevent unbounded map growth. */
|
|
705
|
+
cleanupOldToolMetrics() {
|
|
706
|
+
const staleThreshold = Date.now() - 3_600_000; // 1 hour
|
|
707
|
+
const toRemove = (0, metricsAggregation_js_1.computeToolsToCleanup)(this.tools, MetricsCollector.MAX_TOOL_METRICS, staleThreshold);
|
|
708
|
+
let removedCount = 0;
|
|
709
|
+
for (const name of toRemove) {
|
|
710
|
+
if (this.tools.delete(name))
|
|
711
|
+
removedCount++;
|
|
712
|
+
}
|
|
713
|
+
if (removedCount > 0) {
|
|
714
|
+
console.log(`🧹 MetricsCollector: Cleaned up ${removedCount} stale tool metrics (${this.tools.size} remaining)`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
// ====== BufferRing-Enhanced Methods ======
|
|
718
|
+
/**
|
|
719
|
+
* Get historical metrics data for charting
|
|
720
|
+
*/
|
|
721
|
+
getHistoricalMetrics(minutes = 60) {
|
|
722
|
+
const cutoff = Date.now() - (minutes * 60 * 1000);
|
|
723
|
+
return this.historicalSnapshots.filter(entry => entry.timestamp >= cutoff);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Get recent tool call events for analysis
|
|
727
|
+
*/
|
|
728
|
+
getRecentToolCallEvents(minutes = 30) {
|
|
729
|
+
const cutoff = Date.now() - (minutes * 60 * 1000);
|
|
730
|
+
return this.toolCallEvents.filter(event => event.timestamp >= cutoff);
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Get performance metrics time series for dashboard charts (BufferRing-enhanced)
|
|
734
|
+
*/
|
|
735
|
+
getPerformanceTimeSeriesData(minutes = 60) {
|
|
736
|
+
return (0, metricsSerializer_js_1.buildPerformanceTimeSeriesData)(this.performanceMetrics.getAll(), minutes);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Get tool usage analytics from historical data
|
|
740
|
+
*/
|
|
741
|
+
getToolUsageAnalytics(minutes = 60) {
|
|
742
|
+
return (0, metricsSerializer_js_1.buildToolUsageAnalytics)(this.toolCallEvents.getAll(), minutes);
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Get BufferRing statistics for monitoring
|
|
746
|
+
*/
|
|
747
|
+
getBufferRingStats() {
|
|
748
|
+
return {
|
|
749
|
+
historicalSnapshots: this.historicalSnapshots.getStats(),
|
|
750
|
+
toolCallEvents: this.toolCallEvents.getStats(),
|
|
751
|
+
performanceMetrics: this.performanceMetrics.getStats()
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Export metrics data for backup/analysis
|
|
756
|
+
*/
|
|
757
|
+
exportMetricsData(options = {}) {
|
|
758
|
+
const data = {
|
|
759
|
+
timestamp: Date.now(),
|
|
760
|
+
currentSnapshot: this.getCurrentSnapshot(),
|
|
761
|
+
bufferStats: this.getBufferRingStats()
|
|
762
|
+
};
|
|
763
|
+
const result = data;
|
|
764
|
+
if (options.includeHistorical !== false) {
|
|
765
|
+
result.historicalSnapshots = this.historicalSnapshots.getAll();
|
|
766
|
+
}
|
|
767
|
+
if (options.includeEvents !== false) {
|
|
768
|
+
result.toolCallEvents = this.toolCallEvents.getAll();
|
|
769
|
+
}
|
|
770
|
+
if (options.includePerformance !== false) {
|
|
771
|
+
result.performanceMetrics = this.performanceMetrics.getAll();
|
|
772
|
+
}
|
|
773
|
+
return result;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Clear all BufferRing data (for maintenance)
|
|
777
|
+
*/
|
|
778
|
+
clearBufferedData() {
|
|
779
|
+
this.historicalSnapshots.clear();
|
|
780
|
+
this.toolCallEvents.clear();
|
|
781
|
+
this.performanceMetrics.clear();
|
|
782
|
+
console.error('📊 MetricsCollector: Cleared all BufferRing data');
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
exports.MetricsCollector = MetricsCollector;
|
|
786
|
+
// Global singleton instance
|
|
787
|
+
let globalCollector = null;
|
|
788
|
+
/**
|
|
789
|
+
* Get or create the global metrics collector instance
|
|
790
|
+
*/
|
|
791
|
+
function getMetricsCollector() {
|
|
792
|
+
if (!globalCollector) {
|
|
793
|
+
globalCollector = new MetricsCollector();
|
|
794
|
+
}
|
|
795
|
+
return globalCollector;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Set a custom metrics collector instance (useful for testing)
|
|
799
|
+
*/
|
|
800
|
+
function setMetricsCollector(collector) {
|
|
801
|
+
globalCollector = collector;
|
|
802
|
+
}
|
|
803
|
+
// (No changes needed in this file for the current UI fixes)
|