@daniel.stefan/metalink 1.3.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/README.md +160 -0
- package/package.json +96 -0
- package/packages/cli/dist/bin/cli.d.ts +3 -0
- package/packages/cli/dist/bin/cli.d.ts.map +1 -0
- package/packages/cli/dist/bin/cli.js +4 -0
- package/packages/cli/dist/bin/cli.js.map +1 -0
- package/packages/cli/dist/commands/config/init.d.ts +9 -0
- package/packages/cli/dist/commands/config/init.d.ts.map +1 -0
- package/packages/cli/dist/commands/config/init.js +38 -0
- package/packages/cli/dist/commands/config/init.js.map +1 -0
- package/packages/cli/dist/commands/config/validate.d.ts +9 -0
- package/packages/cli/dist/commands/config/validate.d.ts.map +1 -0
- package/packages/cli/dist/commands/config/validate.js +34 -0
- package/packages/cli/dist/commands/config/validate.js.map +1 -0
- package/packages/cli/dist/commands/daemon/restart.d.ts +15 -0
- package/packages/cli/dist/commands/daemon/restart.d.ts.map +1 -0
- package/packages/cli/dist/commands/daemon/restart.js +184 -0
- package/packages/cli/dist/commands/daemon/restart.js.map +1 -0
- package/packages/cli/dist/commands/daemon/start.d.ts +7 -0
- package/packages/cli/dist/commands/daemon/start.d.ts.map +1 -0
- package/packages/cli/dist/commands/daemon/start.js +85 -0
- package/packages/cli/dist/commands/daemon/start.js.map +1 -0
- package/packages/cli/dist/commands/daemon/status.d.ts +7 -0
- package/packages/cli/dist/commands/daemon/status.d.ts.map +1 -0
- package/packages/cli/dist/commands/daemon/status.js +69 -0
- package/packages/cli/dist/commands/daemon/status.js.map +1 -0
- package/packages/cli/dist/commands/daemon/stop.d.ts +8 -0
- package/packages/cli/dist/commands/daemon/stop.d.ts.map +1 -0
- package/packages/cli/dist/commands/daemon/stop.js +77 -0
- package/packages/cli/dist/commands/daemon/stop.js.map +1 -0
- package/packages/cli/dist/commands/import/mcpm.d.ts +10 -0
- package/packages/cli/dist/commands/import/mcpm.d.ts.map +1 -0
- package/packages/cli/dist/commands/import/mcpm.js +58 -0
- package/packages/cli/dist/commands/import/mcpm.js.map +1 -0
- package/packages/cli/dist/commands/safety/add-risky-pattern.d.ts +16 -0
- package/packages/cli/dist/commands/safety/add-risky-pattern.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/add-risky-pattern.js +72 -0
- package/packages/cli/dist/commands/safety/add-risky-pattern.js.map +1 -0
- package/packages/cli/dist/commands/safety/add-risky.d.ts +12 -0
- package/packages/cli/dist/commands/safety/add-risky.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/add-risky.js +52 -0
- package/packages/cli/dist/commands/safety/add-risky.js.map +1 -0
- package/packages/cli/dist/commands/safety/add-safe-pattern.d.ts +16 -0
- package/packages/cli/dist/commands/safety/add-safe-pattern.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/add-safe-pattern.js +72 -0
- package/packages/cli/dist/commands/safety/add-safe-pattern.js.map +1 -0
- package/packages/cli/dist/commands/safety/add-safe.d.ts +12 -0
- package/packages/cli/dist/commands/safety/add-safe.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/add-safe.js +52 -0
- package/packages/cli/dist/commands/safety/add-safe.js.map +1 -0
- package/packages/cli/dist/commands/safety/check.d.ts +9 -0
- package/packages/cli/dist/commands/safety/check.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/check.js +36 -0
- package/packages/cli/dist/commands/safety/check.js.map +1 -0
- package/packages/cli/dist/commands/safety/export.d.ts +10 -0
- package/packages/cli/dist/commands/safety/export.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/export.js +48 -0
- package/packages/cli/dist/commands/safety/export.js.map +1 -0
- package/packages/cli/dist/commands/safety/import.d.ts +12 -0
- package/packages/cli/dist/commands/safety/import.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/import.js +78 -0
- package/packages/cli/dist/commands/safety/import.js.map +1 -0
- package/packages/cli/dist/commands/safety/index.d.ts +8 -0
- package/packages/cli/dist/commands/safety/index.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/index.js +46 -0
- package/packages/cli/dist/commands/safety/index.js.map +1 -0
- package/packages/cli/dist/commands/safety/list.d.ts +6 -0
- package/packages/cli/dist/commands/safety/list.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/list.js +77 -0
- package/packages/cli/dist/commands/safety/list.js.map +1 -0
- package/packages/cli/dist/commands/safety/remove.d.ts +9 -0
- package/packages/cli/dist/commands/safety/remove.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/remove.js +46 -0
- package/packages/cli/dist/commands/safety/remove.js.map +1 -0
- package/packages/cli/dist/commands/safety/reset.d.ts +9 -0
- package/packages/cli/dist/commands/safety/reset.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/reset.js +46 -0
- package/packages/cli/dist/commands/safety/reset.js.map +1 -0
- package/packages/cli/dist/commands/safety/validate.d.ts +9 -0
- package/packages/cli/dist/commands/safety/validate.d.ts.map +1 -0
- package/packages/cli/dist/commands/safety/validate.js +51 -0
- package/packages/cli/dist/commands/safety/validate.js.map +1 -0
- package/packages/cli/dist/commands/secret/get.d.ts +9 -0
- package/packages/cli/dist/commands/secret/get.d.ts.map +1 -0
- package/packages/cli/dist/commands/secret/get.js +26 -0
- package/packages/cli/dist/commands/secret/get.js.map +1 -0
- package/packages/cli/dist/commands/secret/set.d.ts +10 -0
- package/packages/cli/dist/commands/secret/set.d.ts.map +1 -0
- package/packages/cli/dist/commands/secret/set.js +22 -0
- package/packages/cli/dist/commands/secret/set.js.map +1 -0
- package/packages/cli/dist/commands/server/__tests__/server-management-e2e.test.d.ts +2 -0
- package/packages/cli/dist/commands/server/__tests__/server-management-e2e.test.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/__tests__/server-management-e2e.test.js +234 -0
- package/packages/cli/dist/commands/server/__tests__/server-management-e2e.test.js.map +1 -0
- package/packages/cli/dist/commands/server/add.d.ts +14 -0
- package/packages/cli/dist/commands/server/add.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/add.js +86 -0
- package/packages/cli/dist/commands/server/add.js.map +1 -0
- package/packages/cli/dist/commands/server/available.d.ts +10 -0
- package/packages/cli/dist/commands/server/available.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/available.js +62 -0
- package/packages/cli/dist/commands/server/available.js.map +1 -0
- package/packages/cli/dist/commands/server/debug.d.ts +18 -0
- package/packages/cli/dist/commands/server/debug.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/debug.js +165 -0
- package/packages/cli/dist/commands/server/debug.js.map +1 -0
- package/packages/cli/dist/commands/server/info.d.ts +13 -0
- package/packages/cli/dist/commands/server/info.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/info.js +62 -0
- package/packages/cli/dist/commands/server/info.js.map +1 -0
- package/packages/cli/dist/commands/server/list.d.ts +10 -0
- package/packages/cli/dist/commands/server/list.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/list.js +105 -0
- package/packages/cli/dist/commands/server/list.js.map +1 -0
- package/packages/cli/dist/commands/server/refresh-tools.d.ts +13 -0
- package/packages/cli/dist/commands/server/refresh-tools.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/refresh-tools.js +46 -0
- package/packages/cli/dist/commands/server/refresh-tools.js.map +1 -0
- package/packages/cli/dist/commands/server/remove.d.ts +12 -0
- package/packages/cli/dist/commands/server/remove.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/remove.js +39 -0
- package/packages/cli/dist/commands/server/remove.js.map +1 -0
- package/packages/cli/dist/commands/server/restart.d.ts +9 -0
- package/packages/cli/dist/commands/server/restart.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/restart.js +30 -0
- package/packages/cli/dist/commands/server/restart.js.map +1 -0
- package/packages/cli/dist/commands/server/start.d.ts +9 -0
- package/packages/cli/dist/commands/server/start.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/start.js +37 -0
- package/packages/cli/dist/commands/server/start.js.map +1 -0
- package/packages/cli/dist/commands/server/status.d.ts +9 -0
- package/packages/cli/dist/commands/server/status.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/status.js +30 -0
- package/packages/cli/dist/commands/server/status.js.map +1 -0
- package/packages/cli/dist/commands/server/stop.d.ts +9 -0
- package/packages/cli/dist/commands/server/stop.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/stop.js +31 -0
- package/packages/cli/dist/commands/server/stop.js.map +1 -0
- package/packages/cli/dist/commands/server/validate.d.ts +15 -0
- package/packages/cli/dist/commands/server/validate.d.ts.map +1 -0
- package/packages/cli/dist/commands/server/validate.js +87 -0
- package/packages/cli/dist/commands/server/validate.js.map +1 -0
- package/packages/cli/dist/commands/stdio.d.ts +36 -0
- package/packages/cli/dist/commands/stdio.d.ts.map +1 -0
- package/packages/cli/dist/commands/stdio.js +85 -0
- package/packages/cli/dist/commands/stdio.js.map +1 -0
- package/packages/cli/dist/commands/tool/execute-confirm.d.ts +12 -0
- package/packages/cli/dist/commands/tool/execute-confirm.d.ts.map +1 -0
- package/packages/cli/dist/commands/tool/execute-confirm.js +98 -0
- package/packages/cli/dist/commands/tool/execute-confirm.js.map +1 -0
- package/packages/cli/dist/commands/tool/execute.d.ts +12 -0
- package/packages/cli/dist/commands/tool/execute.d.ts.map +1 -0
- package/packages/cli/dist/commands/tool/execute.js +55 -0
- package/packages/cli/dist/commands/tool/execute.js.map +1 -0
- package/packages/cli/dist/commands/tool/list.d.ts +13 -0
- package/packages/cli/dist/commands/tool/list.d.ts.map +1 -0
- package/packages/cli/dist/commands/tool/list.js +91 -0
- package/packages/cli/dist/commands/tool/list.js.map +1 -0
- package/packages/cli/dist/commands/tool/search.d.ts +12 -0
- package/packages/cli/dist/commands/tool/search.d.ts.map +1 -0
- package/packages/cli/dist/commands/tool/search.js +87 -0
- package/packages/cli/dist/commands/tool/search.js.map +1 -0
- package/packages/cli/dist/index.d.ts +2 -0
- package/packages/cli/dist/index.d.ts.map +1 -0
- package/packages/cli/dist/index.js +9 -0
- package/packages/cli/dist/index.js.map +1 -0
- package/packages/cli/dist/utils/daemon-checker.d.ts +18 -0
- package/packages/cli/dist/utils/daemon-checker.d.ts.map +1 -0
- package/packages/cli/dist/utils/daemon-checker.js +69 -0
- package/packages/cli/dist/utils/daemon-checker.js.map +1 -0
- package/packages/cli/dist/utils/daemon-endpoint.d.ts +7 -0
- package/packages/cli/dist/utils/daemon-endpoint.d.ts.map +1 -0
- package/packages/cli/dist/utils/daemon-endpoint.js +13 -0
- package/packages/cli/dist/utils/daemon-endpoint.js.map +1 -0
- package/packages/cli/dist/utils/get-configured-port.d.ts +43 -0
- package/packages/cli/dist/utils/get-configured-port.d.ts.map +1 -0
- package/packages/cli/dist/utils/get-configured-port.js +141 -0
- package/packages/cli/dist/utils/get-configured-port.js.map +1 -0
- package/packages/cli/dist/utils/stdio-bridge.d.ts +48 -0
- package/packages/cli/dist/utils/stdio-bridge.d.ts.map +1 -0
- package/packages/cli/dist/utils/stdio-bridge.js +181 -0
- package/packages/cli/dist/utils/stdio-bridge.js.map +1 -0
- package/packages/cli/package.json +48 -0
- package/packages/core/dist/config/defaults.d.ts +36 -0
- package/packages/core/dist/config/defaults.d.ts.map +1 -0
- package/packages/core/dist/config/defaults.js +324 -0
- package/packages/core/dist/config/defaults.js.map +1 -0
- package/packages/core/dist/config/index.d.ts +9 -0
- package/packages/core/dist/config/index.d.ts.map +1 -0
- package/packages/core/dist/config/index.js +14 -0
- package/packages/core/dist/config/index.js.map +1 -0
- package/packages/core/dist/config/loader.d.ts +269 -0
- package/packages/core/dist/config/loader.d.ts.map +1 -0
- package/packages/core/dist/config/loader.js +777 -0
- package/packages/core/dist/config/loader.js.map +1 -0
- package/packages/core/dist/config/registry.d.ts +212 -0
- package/packages/core/dist/config/registry.d.ts.map +1 -0
- package/packages/core/dist/config/registry.js +754 -0
- package/packages/core/dist/config/registry.js.map +1 -0
- package/packages/core/dist/config/schema.d.ts +4352 -0
- package/packages/core/dist/config/schema.d.ts.map +1 -0
- package/packages/core/dist/config/schema.js +267 -0
- package/packages/core/dist/config/schema.js.map +1 -0
- package/packages/core/dist/daemon.d.ts +7 -0
- package/packages/core/dist/daemon.d.ts.map +1 -0
- package/packages/core/dist/daemon.js +116 -0
- package/packages/core/dist/daemon.js.map +1 -0
- package/packages/core/dist/http-client-retry.d.ts +67 -0
- package/packages/core/dist/http-client-retry.d.ts.map +1 -0
- package/packages/core/dist/http-client-retry.js +133 -0
- package/packages/core/dist/http-client-retry.js.map +1 -0
- package/packages/core/dist/http-client-updated.d.ts +147 -0
- package/packages/core/dist/http-client-updated.d.ts.map +1 -0
- package/packages/core/dist/http-client-updated.js +452 -0
- package/packages/core/dist/http-client-updated.js.map +1 -0
- package/packages/core/dist/http-client.d.ts +207 -0
- package/packages/core/dist/http-client.d.ts.map +1 -0
- package/packages/core/dist/http-client.js +704 -0
- package/packages/core/dist/http-client.js.map +1 -0
- package/packages/core/dist/index.d.ts +13 -0
- package/packages/core/dist/index.d.ts.map +1 -0
- package/packages/core/dist/index.js +23 -0
- package/packages/core/dist/index.js.map +1 -0
- package/packages/core/dist/logging/index.d.ts +46 -0
- package/packages/core/dist/logging/index.d.ts.map +1 -0
- package/packages/core/dist/logging/index.js +74 -0
- package/packages/core/dist/logging/index.js.map +1 -0
- package/packages/core/dist/metrics/index.d.ts +339 -0
- package/packages/core/dist/metrics/index.d.ts.map +1 -0
- package/packages/core/dist/metrics/index.js +792 -0
- package/packages/core/dist/metrics/index.js.map +1 -0
- package/packages/core/dist/plugins/index.d.ts +49 -0
- package/packages/core/dist/plugins/index.d.ts.map +1 -0
- package/packages/core/dist/plugins/index.js +82 -0
- package/packages/core/dist/plugins/index.js.map +1 -0
- package/packages/core/dist/secrets/index.d.ts +6 -0
- package/packages/core/dist/secrets/index.d.ts.map +1 -0
- package/packages/core/dist/secrets/index.js +5 -0
- package/packages/core/dist/secrets/index.js.map +1 -0
- package/packages/core/dist/secrets/keyring.d.ts +54 -0
- package/packages/core/dist/secrets/keyring.d.ts.map +1 -0
- package/packages/core/dist/secrets/keyring.js +141 -0
- package/packages/core/dist/secrets/keyring.js.map +1 -0
- package/packages/core/dist/server/batch-executor.d.ts +83 -0
- package/packages/core/dist/server/batch-executor.d.ts.map +1 -0
- package/packages/core/dist/server/batch-executor.js +291 -0
- package/packages/core/dist/server/batch-executor.js.map +1 -0
- package/packages/core/dist/server/circuit-breaker.d.ts +215 -0
- package/packages/core/dist/server/circuit-breaker.d.ts.map +1 -0
- package/packages/core/dist/server/circuit-breaker.js +330 -0
- package/packages/core/dist/server/circuit-breaker.js.map +1 -0
- package/packages/core/dist/server/client-detection.d.ts +40 -0
- package/packages/core/dist/server/client-detection.d.ts.map +1 -0
- package/packages/core/dist/server/client-detection.js +242 -0
- package/packages/core/dist/server/client-detection.js.map +1 -0
- package/packages/core/dist/server/client-profiles.d.ts +102 -0
- package/packages/core/dist/server/client-profiles.d.ts.map +1 -0
- package/packages/core/dist/server/client-profiles.js +254 -0
- package/packages/core/dist/server/client-profiles.js.map +1 -0
- package/packages/core/dist/server/http.d.ts +386 -0
- package/packages/core/dist/server/http.d.ts.map +1 -0
- package/packages/core/dist/server/http.js +4253 -0
- package/packages/core/dist/server/http.js.map +1 -0
- package/packages/core/dist/server/index.d.ts +7 -0
- package/packages/core/dist/server/index.d.ts.map +1 -0
- package/packages/core/dist/server/index.js +6 -0
- package/packages/core/dist/server/index.js.map +1 -0
- package/packages/core/dist/server/manager.d.ts +458 -0
- package/packages/core/dist/server/manager.d.ts.map +1 -0
- package/packages/core/dist/server/manager.js +3255 -0
- package/packages/core/dist/server/manager.js.map +1 -0
- package/packages/core/dist/server/managers/HttpConnectionManager.d.ts +69 -0
- package/packages/core/dist/server/managers/HttpConnectionManager.d.ts.map +1 -0
- package/packages/core/dist/server/managers/HttpConnectionManager.js +214 -0
- package/packages/core/dist/server/managers/HttpConnectionManager.js.map +1 -0
- package/packages/core/dist/server/managers/ProcessManager.d.ts +128 -0
- package/packages/core/dist/server/managers/ProcessManager.d.ts.map +1 -0
- package/packages/core/dist/server/managers/ProcessManager.js +443 -0
- package/packages/core/dist/server/managers/ProcessManager.js.map +1 -0
- package/packages/core/dist/server/managers/SchemaCacheManager.d.ts +152 -0
- package/packages/core/dist/server/managers/SchemaCacheManager.d.ts.map +1 -0
- package/packages/core/dist/server/managers/SchemaCacheManager.js +426 -0
- package/packages/core/dist/server/managers/SchemaCacheManager.js.map +1 -0
- package/packages/core/dist/server/managers/index.d.ts +9 -0
- package/packages/core/dist/server/managers/index.d.ts.map +1 -0
- package/packages/core/dist/server/managers/index.js +9 -0
- package/packages/core/dist/server/managers/index.js.map +1 -0
- package/packages/core/dist/server/metrics.d.ts +134 -0
- package/packages/core/dist/server/metrics.d.ts.map +1 -0
- package/packages/core/dist/server/metrics.js +273 -0
- package/packages/core/dist/server/metrics.js.map +1 -0
- package/packages/core/dist/server/prompts.d.ts +58 -0
- package/packages/core/dist/server/prompts.d.ts.map +1 -0
- package/packages/core/dist/server/prompts.js +405 -0
- package/packages/core/dist/server/prompts.js.map +1 -0
- package/packages/core/dist/server/protocol-versions.d.ts +49 -0
- package/packages/core/dist/server/protocol-versions.d.ts.map +1 -0
- package/packages/core/dist/server/protocol-versions.js +173 -0
- package/packages/core/dist/server/protocol-versions.js.map +1 -0
- package/packages/core/dist/server/resources.d.ts +64 -0
- package/packages/core/dist/server/resources.d.ts.map +1 -0
- package/packages/core/dist/server/resources.js +243 -0
- package/packages/core/dist/server/resources.js.map +1 -0
- package/packages/core/dist/server/schema-store.d.ts +84 -0
- package/packages/core/dist/server/schema-store.d.ts.map +1 -0
- package/packages/core/dist/server/schema-store.js +234 -0
- package/packages/core/dist/server/schema-store.js.map +1 -0
- package/packages/core/dist/server/schema-validator.d.ts +51 -0
- package/packages/core/dist/server/schema-validator.d.ts.map +1 -0
- package/packages/core/dist/server/schema-validator.js +208 -0
- package/packages/core/dist/server/schema-validator.js.map +1 -0
- package/packages/core/dist/server/token-calculator.d.ts +44 -0
- package/packages/core/dist/server/token-calculator.d.ts.map +1 -0
- package/packages/core/dist/server/token-calculator.js +53 -0
- package/packages/core/dist/server/token-calculator.js.map +1 -0
- package/packages/core/dist/server/types.d.ts +45 -0
- package/packages/core/dist/server/types.d.ts.map +1 -0
- package/packages/core/dist/server/types.js +5 -0
- package/packages/core/dist/server/types.js.map +1 -0
- package/packages/core/dist/utils/file-lock.d.ts +73 -0
- package/packages/core/dist/utils/file-lock.d.ts.map +1 -0
- package/packages/core/dist/utils/file-lock.js +235 -0
- package/packages/core/dist/utils/file-lock.js.map +1 -0
- package/packages/core/package.json +36 -0
- package/packages/dashboard/dist/assets/index-B7hvkCMu.css +1 -0
- package/packages/dashboard/dist/assets/index-yZhLPpzr.js +1 -0
- package/packages/dashboard/dist/index.html +14 -0
- package/packages/dashboard/package.json +24 -0
- package/packages/shared/dist/version.d.ts +2 -0
- package/packages/shared/dist/version.d.ts.map +1 -0
- package/packages/shared/dist/version.js +2 -0
- package/packages/shared/dist/version.js.map +1 -0
- package/packages/shared/package.json +18 -0
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Collection and Reporting
|
|
3
|
+
* Tracks server performance and API usage
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import { promises as fsPromises } from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
/**
|
|
9
|
+
* Metrics Collector
|
|
10
|
+
*/
|
|
11
|
+
export class MetricsCollector {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.metrics = new Map();
|
|
14
|
+
this.serverMetrics = new Map();
|
|
15
|
+
this.toolMetrics = new Map(); // Key: "serverName-toolName"
|
|
16
|
+
this.errorRecords = []; // Keep last 1000 errors
|
|
17
|
+
this.toolCallCounts = new Map(); // Track total calls per tool
|
|
18
|
+
this.toolErrorCounts = new Map(); // Track error counts per tool
|
|
19
|
+
this.apiMetrics = {
|
|
20
|
+
requests: 0,
|
|
21
|
+
responses: 0,
|
|
22
|
+
errors: 0,
|
|
23
|
+
avgResponseTime: 0,
|
|
24
|
+
lastRequest: 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Increment counter metric
|
|
29
|
+
*/
|
|
30
|
+
incrementCounter(name, unit = '') {
|
|
31
|
+
if (!this.metrics.has(name)) {
|
|
32
|
+
this.metrics.set(name, {
|
|
33
|
+
name,
|
|
34
|
+
type: 'counter',
|
|
35
|
+
unit,
|
|
36
|
+
value: 0,
|
|
37
|
+
history: [],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const metric = this.metrics.get(name);
|
|
41
|
+
metric.value++;
|
|
42
|
+
metric.history.push({
|
|
43
|
+
timestamp: Date.now(),
|
|
44
|
+
value: metric.value,
|
|
45
|
+
});
|
|
46
|
+
// Keep only last 1000 data points
|
|
47
|
+
if (metric.history.length > 1000) {
|
|
48
|
+
metric.history = metric.history.slice(-1000);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set gauge metric
|
|
53
|
+
*/
|
|
54
|
+
setGauge(name, value, unit = '') {
|
|
55
|
+
if (!this.metrics.has(name)) {
|
|
56
|
+
this.metrics.set(name, {
|
|
57
|
+
name,
|
|
58
|
+
type: 'gauge',
|
|
59
|
+
unit,
|
|
60
|
+
value,
|
|
61
|
+
history: [],
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const metric = this.metrics.get(name);
|
|
65
|
+
metric.value = value;
|
|
66
|
+
metric.history.push({
|
|
67
|
+
timestamp: Date.now(),
|
|
68
|
+
value,
|
|
69
|
+
});
|
|
70
|
+
// Keep only last 1000 data points
|
|
71
|
+
if (metric.history.length > 1000) {
|
|
72
|
+
metric.history = metric.history.slice(-1000);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Record server startup
|
|
77
|
+
*/
|
|
78
|
+
recordServerStart(serverName) {
|
|
79
|
+
this.serverMetrics.set(serverName, {
|
|
80
|
+
serverName,
|
|
81
|
+
startTime: Date.now(),
|
|
82
|
+
uptime: 0,
|
|
83
|
+
restarts: (this.serverMetrics.get(serverName)?.restarts || 0) + 1,
|
|
84
|
+
errors: 0,
|
|
85
|
+
tools: { total: 0, executed: 0, failed: 0 },
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Record server error
|
|
90
|
+
*/
|
|
91
|
+
recordServerError(serverName, error, errorType) {
|
|
92
|
+
const metrics = this.serverMetrics.get(serverName);
|
|
93
|
+
if (metrics) {
|
|
94
|
+
metrics.errors++;
|
|
95
|
+
metrics.lastError = error;
|
|
96
|
+
}
|
|
97
|
+
// If errorType provided, also record detailed error for analytics
|
|
98
|
+
if (errorType) {
|
|
99
|
+
this.recordToolError(error, undefined, serverName);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Record API request
|
|
104
|
+
*/
|
|
105
|
+
recordApiRequest() {
|
|
106
|
+
this.apiMetrics.requests++;
|
|
107
|
+
this.apiMetrics.lastRequest = Date.now();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Record API response
|
|
111
|
+
*/
|
|
112
|
+
recordApiResponse(responseTime) {
|
|
113
|
+
this.apiMetrics.responses++;
|
|
114
|
+
// Calculate running average
|
|
115
|
+
const totalTime = this.apiMetrics.avgResponseTime * (this.apiMetrics.responses - 1) + responseTime;
|
|
116
|
+
this.apiMetrics.avgResponseTime = totalTime / this.apiMetrics.responses;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Record API error
|
|
120
|
+
*/
|
|
121
|
+
recordApiError() {
|
|
122
|
+
this.apiMetrics.errors++;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Record tool execution (success)
|
|
126
|
+
* @param serverName - Server name (e.g., "memory", "time")
|
|
127
|
+
* @param toolName - Tool name (e.g., "create_entities", "get_current_time")
|
|
128
|
+
* @param latency - Execution time in milliseconds
|
|
129
|
+
*/
|
|
130
|
+
recordToolExecution(serverName, toolName, latency) {
|
|
131
|
+
const key = `${serverName}-${toolName}`;
|
|
132
|
+
if (!this.toolMetrics.has(key)) {
|
|
133
|
+
this.toolMetrics.set(key, {
|
|
134
|
+
toolName,
|
|
135
|
+
serverName,
|
|
136
|
+
calls: 0,
|
|
137
|
+
successes: 0,
|
|
138
|
+
failures: 0,
|
|
139
|
+
totalLatency: 0,
|
|
140
|
+
minLatency: Infinity,
|
|
141
|
+
maxLatency: 0,
|
|
142
|
+
avgLatency: 0,
|
|
143
|
+
latencyHistory: [],
|
|
144
|
+
lastCall: 0,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
const metrics = this.toolMetrics.get(key);
|
|
148
|
+
metrics.calls++;
|
|
149
|
+
metrics.successes++;
|
|
150
|
+
metrics.totalLatency += latency;
|
|
151
|
+
metrics.minLatency = Math.min(metrics.minLatency, latency);
|
|
152
|
+
metrics.maxLatency = Math.max(metrics.maxLatency, latency);
|
|
153
|
+
metrics.avgLatency = metrics.totalLatency / metrics.successes;
|
|
154
|
+
metrics.lastCall = Date.now();
|
|
155
|
+
// Keep last 1000 latencies for percentile calculation
|
|
156
|
+
metrics.latencyHistory.push(latency);
|
|
157
|
+
if (metrics.latencyHistory.length > 1000) {
|
|
158
|
+
metrics.latencyHistory = metrics.latencyHistory.slice(-1000);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Record tool execution failure
|
|
163
|
+
* @param serverName - Server name
|
|
164
|
+
* @param toolName - Tool name
|
|
165
|
+
* @param error - Error message
|
|
166
|
+
*/
|
|
167
|
+
recordToolFailure(serverName, toolName, error) {
|
|
168
|
+
const key = `${serverName}-${toolName}`;
|
|
169
|
+
if (!this.toolMetrics.has(key)) {
|
|
170
|
+
this.toolMetrics.set(key, {
|
|
171
|
+
toolName,
|
|
172
|
+
serverName,
|
|
173
|
+
calls: 0,
|
|
174
|
+
successes: 0,
|
|
175
|
+
failures: 0,
|
|
176
|
+
totalLatency: 0,
|
|
177
|
+
minLatency: Infinity,
|
|
178
|
+
maxLatency: 0,
|
|
179
|
+
avgLatency: 0,
|
|
180
|
+
latencyHistory: [],
|
|
181
|
+
lastCall: 0,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const metrics = this.toolMetrics.get(key);
|
|
185
|
+
metrics.calls++;
|
|
186
|
+
metrics.failures++;
|
|
187
|
+
metrics.lastCall = Date.now();
|
|
188
|
+
metrics.lastError = error;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Calculate percentile from sorted array
|
|
192
|
+
* @param sortedArray - Sorted array of numbers
|
|
193
|
+
* @param percentile - Percentile to calculate (0-100)
|
|
194
|
+
*/
|
|
195
|
+
calculatePercentile(sortedArray, percentile) {
|
|
196
|
+
if (sortedArray.length === 0)
|
|
197
|
+
return 0;
|
|
198
|
+
const index = (percentile / 100) * (sortedArray.length - 1);
|
|
199
|
+
const lower = Math.floor(index);
|
|
200
|
+
const upper = Math.ceil(index);
|
|
201
|
+
const weight = index % 1;
|
|
202
|
+
if (lower === upper) {
|
|
203
|
+
return sortedArray[lower];
|
|
204
|
+
}
|
|
205
|
+
return sortedArray[lower] * (1 - weight) + sortedArray[upper] * weight;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get all tool metrics with percentiles
|
|
209
|
+
*/
|
|
210
|
+
getAllToolMetrics() {
|
|
211
|
+
return Array.from(this.toolMetrics.values()).map((metrics) => {
|
|
212
|
+
const sortedLatencies = [...metrics.latencyHistory].sort((a, b) => a - b);
|
|
213
|
+
return {
|
|
214
|
+
toolName: metrics.toolName,
|
|
215
|
+
serverName: metrics.serverName,
|
|
216
|
+
calls: metrics.calls,
|
|
217
|
+
successRate: metrics.calls > 0 ? (metrics.successes / metrics.calls) * 100 : 0,
|
|
218
|
+
failureRate: metrics.calls > 0 ? (metrics.failures / metrics.calls) * 100 : 0,
|
|
219
|
+
latency: {
|
|
220
|
+
min: metrics.minLatency === Infinity ? 0 : metrics.minLatency,
|
|
221
|
+
max: metrics.maxLatency,
|
|
222
|
+
avg: metrics.avgLatency,
|
|
223
|
+
p50: this.calculatePercentile(sortedLatencies, 50),
|
|
224
|
+
p95: this.calculatePercentile(sortedLatencies, 95),
|
|
225
|
+
p99: this.calculatePercentile(sortedLatencies, 99),
|
|
226
|
+
},
|
|
227
|
+
lastCall: metrics.lastCall,
|
|
228
|
+
lastError: metrics.lastError,
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get tool metrics for a specific tool
|
|
234
|
+
* @param serverName - Server name
|
|
235
|
+
* @param toolName - Tool name
|
|
236
|
+
*/
|
|
237
|
+
getToolMetrics(serverName, toolName) {
|
|
238
|
+
const key = `${serverName}-${toolName}`;
|
|
239
|
+
const metrics = this.toolMetrics.get(key);
|
|
240
|
+
if (!metrics) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
const sortedLatencies = [...metrics.latencyHistory].sort((a, b) => a - b);
|
|
244
|
+
return {
|
|
245
|
+
toolName: metrics.toolName,
|
|
246
|
+
serverName: metrics.serverName,
|
|
247
|
+
calls: metrics.calls,
|
|
248
|
+
successRate: metrics.calls > 0 ? (metrics.successes / metrics.calls) * 100 : 0,
|
|
249
|
+
failureRate: metrics.calls > 0 ? (metrics.failures / metrics.calls) * 100 : 0,
|
|
250
|
+
latency: {
|
|
251
|
+
min: metrics.minLatency === Infinity ? 0 : metrics.minLatency,
|
|
252
|
+
max: metrics.maxLatency,
|
|
253
|
+
avg: metrics.avgLatency,
|
|
254
|
+
p50: this.calculatePercentile(sortedLatencies, 50),
|
|
255
|
+
p95: this.calculatePercentile(sortedLatencies, 95),
|
|
256
|
+
p99: this.calculatePercentile(sortedLatencies, 99),
|
|
257
|
+
},
|
|
258
|
+
lastCall: metrics.lastCall,
|
|
259
|
+
lastError: metrics.lastError,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get top N slowest tools by P95 latency
|
|
264
|
+
* @param limit - Number of tools to return (default: 10)
|
|
265
|
+
*/
|
|
266
|
+
getSlowestTools(limit = 10) {
|
|
267
|
+
const allMetrics = this.getAllToolMetrics();
|
|
268
|
+
return allMetrics
|
|
269
|
+
.sort((a, b) => b.latency.p95 - a.latency.p95)
|
|
270
|
+
.slice(0, limit);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get tools with high error rates
|
|
274
|
+
* @param threshold - Error rate threshold percentage (default: 5%)
|
|
275
|
+
*/
|
|
276
|
+
getHighErrorRateTools(threshold = 5) {
|
|
277
|
+
const allMetrics = this.getAllToolMetrics();
|
|
278
|
+
return allMetrics
|
|
279
|
+
.filter((m) => m.failureRate >= threshold && m.calls >= 5) // At least 5 calls to be meaningful
|
|
280
|
+
.sort((a, b) => b.failureRate - a.failureRate);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Classify error type from error message
|
|
284
|
+
* Public method to allow external error classification
|
|
285
|
+
*/
|
|
286
|
+
classifyErrorType(error) {
|
|
287
|
+
const message = typeof error === 'string' ? error : error.message;
|
|
288
|
+
const lowerMessage = message.toLowerCase();
|
|
289
|
+
if (lowerMessage.includes('invalid') || lowerMessage.includes('validation') || lowerMessage.includes('required')) {
|
|
290
|
+
return 'validation';
|
|
291
|
+
}
|
|
292
|
+
if (lowerMessage.includes('timeout') || lowerMessage.includes('timed out')) {
|
|
293
|
+
return 'timeout';
|
|
294
|
+
}
|
|
295
|
+
if (lowerMessage.includes('econnrefused') || lowerMessage.includes('connection') || lowerMessage.includes('enotfound')) {
|
|
296
|
+
return 'connection';
|
|
297
|
+
}
|
|
298
|
+
if (lowerMessage.includes('rate limit')) {
|
|
299
|
+
return 'rate_limit';
|
|
300
|
+
}
|
|
301
|
+
if (lowerMessage.includes('permission') || lowerMessage.includes('unauthorized') || lowerMessage.includes('forbidden')) {
|
|
302
|
+
return 'permission';
|
|
303
|
+
}
|
|
304
|
+
if (lowerMessage.includes('not found') || lowerMessage.includes('does not exist')) {
|
|
305
|
+
return 'not_found';
|
|
306
|
+
}
|
|
307
|
+
if (lowerMessage.includes('internal') || lowerMessage.includes('crash')) {
|
|
308
|
+
return 'internal';
|
|
309
|
+
}
|
|
310
|
+
return 'unknown';
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Record tool call (success or failure)
|
|
314
|
+
*/
|
|
315
|
+
recordToolCall(toolName, serverName) {
|
|
316
|
+
const key = serverName ? `${serverName}-${toolName}` : toolName;
|
|
317
|
+
this.toolCallCounts.set(key, (this.toolCallCounts.get(key) || 0) + 1);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Record tool error with detailed tracking
|
|
321
|
+
*/
|
|
322
|
+
recordToolError(error, toolName, serverName) {
|
|
323
|
+
const errorType = this.classifyErrorType(error);
|
|
324
|
+
const errorMessage = typeof error === 'string' ? error : error.message;
|
|
325
|
+
const stack = typeof error === 'string' ? undefined : error.stack;
|
|
326
|
+
const errorRecord = {
|
|
327
|
+
timestamp: Date.now(),
|
|
328
|
+
errorType,
|
|
329
|
+
message: errorMessage,
|
|
330
|
+
toolName,
|
|
331
|
+
serverName,
|
|
332
|
+
stack,
|
|
333
|
+
};
|
|
334
|
+
// Add to error records (keep last 1000)
|
|
335
|
+
this.errorRecords.push(errorRecord);
|
|
336
|
+
if (this.errorRecords.length > 1000) {
|
|
337
|
+
this.errorRecords = this.errorRecords.slice(-1000);
|
|
338
|
+
}
|
|
339
|
+
// Track error counts per tool
|
|
340
|
+
if (toolName) {
|
|
341
|
+
const key = serverName ? `${serverName}-${toolName}` : toolName;
|
|
342
|
+
this.toolErrorCounts.set(key, (this.toolErrorCounts.get(key) || 0) + 1);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get error analytics for a specific tool
|
|
347
|
+
*/
|
|
348
|
+
getToolErrorMetrics(toolName, serverName) {
|
|
349
|
+
const key = serverName ? `${serverName}-${toolName}` : toolName;
|
|
350
|
+
const totalCalls = this.toolCallCounts.get(key) || 0;
|
|
351
|
+
const totalErrors = this.toolErrorCounts.get(key) || 0;
|
|
352
|
+
if (totalCalls === 0) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
// Get errors for this tool
|
|
356
|
+
const toolErrors = this.errorRecords.filter((e) => e.toolName === toolName && (!serverName || e.serverName === serverName));
|
|
357
|
+
// Count errors by type
|
|
358
|
+
const errorsByType = {
|
|
359
|
+
validation: 0,
|
|
360
|
+
timeout: 0,
|
|
361
|
+
connection: 0,
|
|
362
|
+
internal: 0,
|
|
363
|
+
rate_limit: 0,
|
|
364
|
+
permission: 0,
|
|
365
|
+
not_found: 0,
|
|
366
|
+
unknown: 0,
|
|
367
|
+
};
|
|
368
|
+
for (const error of toolErrors) {
|
|
369
|
+
errorsByType[error.errorType]++;
|
|
370
|
+
}
|
|
371
|
+
// Calculate error patterns
|
|
372
|
+
const errorPatterns = Object.entries(errorsByType)
|
|
373
|
+
.filter(([_, count]) => count > 0)
|
|
374
|
+
.map(([type, count]) => ({
|
|
375
|
+
type: type,
|
|
376
|
+
count,
|
|
377
|
+
percentage: totalErrors > 0 ? (count / totalErrors) * 100 : 0,
|
|
378
|
+
}))
|
|
379
|
+
.sort((a, b) => b.count - a.count);
|
|
380
|
+
return {
|
|
381
|
+
toolName,
|
|
382
|
+
serverName: serverName || 'unknown',
|
|
383
|
+
totalCalls,
|
|
384
|
+
totalErrors,
|
|
385
|
+
errorRate: totalCalls > 0 ? (totalErrors / totalCalls) * 100 : 0,
|
|
386
|
+
errorsByType,
|
|
387
|
+
recentErrors: toolErrors.slice(-10), // Last 10 errors
|
|
388
|
+
lastError: toolErrors[toolErrors.length - 1],
|
|
389
|
+
errorPatterns,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get aggregated error analytics across all tools
|
|
394
|
+
*/
|
|
395
|
+
getErrorAnalytics() {
|
|
396
|
+
const totalCalls = Array.from(this.toolCallCounts.values()).reduce((sum, count) => sum + count, 0);
|
|
397
|
+
const totalErrors = this.errorRecords.length;
|
|
398
|
+
// Count errors by type
|
|
399
|
+
const errorsByType = {
|
|
400
|
+
validation: 0,
|
|
401
|
+
timeout: 0,
|
|
402
|
+
connection: 0,
|
|
403
|
+
internal: 0,
|
|
404
|
+
rate_limit: 0,
|
|
405
|
+
permission: 0,
|
|
406
|
+
not_found: 0,
|
|
407
|
+
unknown: 0,
|
|
408
|
+
};
|
|
409
|
+
const errorsByServer = {};
|
|
410
|
+
const errorsByTool = {};
|
|
411
|
+
for (const error of this.errorRecords) {
|
|
412
|
+
errorsByType[error.errorType]++;
|
|
413
|
+
if (error.serverName) {
|
|
414
|
+
errorsByServer[error.serverName] = (errorsByServer[error.serverName] || 0) + 1;
|
|
415
|
+
}
|
|
416
|
+
if (error.toolName) {
|
|
417
|
+
const key = error.serverName ? `${error.serverName}-${error.toolName}` : error.toolName;
|
|
418
|
+
errorsByTool[key] = (errorsByTool[key] || 0) + 1;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// Calculate top failing tools
|
|
422
|
+
const topFailingTools = [];
|
|
423
|
+
for (const [key, errorCount] of this.toolErrorCounts.entries()) {
|
|
424
|
+
const totalCalls = this.toolCallCounts.get(key) || 0;
|
|
425
|
+
if (totalCalls > 0) {
|
|
426
|
+
const [serverName, ...toolParts] = key.split('-');
|
|
427
|
+
const toolName = toolParts.join('-');
|
|
428
|
+
topFailingTools.push({
|
|
429
|
+
toolName,
|
|
430
|
+
serverName,
|
|
431
|
+
errorCount,
|
|
432
|
+
errorRate: (errorCount / totalCalls) * 100,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Sort by error count descending
|
|
437
|
+
topFailingTools.sort((a, b) => b.errorCount - a.errorCount);
|
|
438
|
+
return {
|
|
439
|
+
totalErrors,
|
|
440
|
+
totalCalls,
|
|
441
|
+
errorRate: totalCalls > 0 ? (totalErrors / totalCalls) * 100 : 0,
|
|
442
|
+
errorsByType,
|
|
443
|
+
errorsByServer,
|
|
444
|
+
errorsByTool,
|
|
445
|
+
recentErrors: this.errorRecords.slice(-50), // Last 50 errors
|
|
446
|
+
topFailingTools: topFailingTools.slice(0, 10), // Top 10 failing tools
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Get all metrics
|
|
451
|
+
*/
|
|
452
|
+
getMetrics() {
|
|
453
|
+
return Array.from(this.metrics.values());
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Get metric by name
|
|
457
|
+
*/
|
|
458
|
+
getMetric(name) {
|
|
459
|
+
return this.metrics.get(name);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Get server metrics
|
|
463
|
+
*/
|
|
464
|
+
getServerMetrics(serverName) {
|
|
465
|
+
const metrics = this.serverMetrics.get(serverName);
|
|
466
|
+
if (metrics) {
|
|
467
|
+
metrics.uptime = Date.now() - metrics.startTime;
|
|
468
|
+
}
|
|
469
|
+
return metrics;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Get API metrics
|
|
473
|
+
*/
|
|
474
|
+
getApiMetrics() {
|
|
475
|
+
return { ...this.apiMetrics };
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get all server metrics
|
|
479
|
+
*/
|
|
480
|
+
getAllServerMetrics() {
|
|
481
|
+
return Array.from(this.serverMetrics.values()).map((metrics) => ({
|
|
482
|
+
...metrics,
|
|
483
|
+
uptime: Date.now() - metrics.startTime,
|
|
484
|
+
}));
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Restore metrics from persisted data
|
|
488
|
+
* Used during daemon startup to restore metrics from disk
|
|
489
|
+
*/
|
|
490
|
+
restoreMetrics(data) {
|
|
491
|
+
// Restore custom metrics
|
|
492
|
+
for (const metric of data.metrics) {
|
|
493
|
+
this.metrics.set(metric.name, {
|
|
494
|
+
...metric,
|
|
495
|
+
history: metric.history.slice(-1000), // Keep last 1000 points
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
// Restore server metrics
|
|
499
|
+
for (const serverMetric of data.serverMetrics) {
|
|
500
|
+
this.serverMetrics.set(serverMetric.serverName, {
|
|
501
|
+
...serverMetric,
|
|
502
|
+
// Preserve restarts count and errors, reset runtime values
|
|
503
|
+
startTime: Date.now(), // Reset start time to now
|
|
504
|
+
uptime: 0, // Will be recalculated
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
// Restore tool metrics (optional for backward compatibility)
|
|
508
|
+
if (data.toolMetrics && Array.isArray(data.toolMetrics)) {
|
|
509
|
+
for (const toolMetric of data.toolMetrics) {
|
|
510
|
+
const key = `${toolMetric.serverName}-${toolMetric.toolName}`;
|
|
511
|
+
this.toolMetrics.set(key, {
|
|
512
|
+
...toolMetric,
|
|
513
|
+
latencyHistory: toolMetric.latencyHistory.slice(-1000), // Keep last 1000 points
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
// Restore API metrics
|
|
518
|
+
this.apiMetrics = {
|
|
519
|
+
...data.apiMetrics,
|
|
520
|
+
lastRequest: Date.now(), // Update to current time
|
|
521
|
+
};
|
|
522
|
+
const toolCount = data.toolMetrics ? data.toolMetrics.length : 0;
|
|
523
|
+
console.log(`[MetricsCollector] Restored metrics: ${data.metrics.length} custom, ` +
|
|
524
|
+
`${data.serverMetrics.length} servers, ${toolCount} tools, API metrics loaded`);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Export metrics as Prometheus format
|
|
528
|
+
*/
|
|
529
|
+
exportPrometheus() {
|
|
530
|
+
let output = '';
|
|
531
|
+
// Custom metrics
|
|
532
|
+
for (const metric of this.metrics.values()) {
|
|
533
|
+
output += `# TYPE ${metric.name} ${metric.type}\n`;
|
|
534
|
+
output += `# UNIT ${metric.name} ${metric.unit}\n`;
|
|
535
|
+
output += `${metric.name}{} ${metric.value}\n`;
|
|
536
|
+
}
|
|
537
|
+
// API metrics
|
|
538
|
+
output += `# TYPE api_requests counter\n`;
|
|
539
|
+
output += `api_requests{} ${this.apiMetrics.requests}\n`;
|
|
540
|
+
output += `api_responses{} ${this.apiMetrics.responses}\n`;
|
|
541
|
+
output += `api_errors{} ${this.apiMetrics.errors}\n`;
|
|
542
|
+
output += `api_response_time_ms{} ${this.apiMetrics.avgResponseTime.toFixed(2)}\n`;
|
|
543
|
+
// Server metrics
|
|
544
|
+
for (const metrics of this.serverMetrics.values()) {
|
|
545
|
+
output += `# TYPE server_uptime gauge\n`;
|
|
546
|
+
output += `server_uptime{server="${metrics.serverName}"} ${metrics.uptime}\n`;
|
|
547
|
+
output += `server_restarts{server="${metrics.serverName}"} ${metrics.restarts}\n`;
|
|
548
|
+
output += `server_errors{server="${metrics.serverName}"} ${metrics.errors}\n`;
|
|
549
|
+
}
|
|
550
|
+
// Tool metrics
|
|
551
|
+
const toolMetrics = this.getAllToolMetrics();
|
|
552
|
+
if (toolMetrics.length > 0) {
|
|
553
|
+
output += `# TYPE tool_calls counter\n`;
|
|
554
|
+
output += `# TYPE tool_success_rate gauge\n`;
|
|
555
|
+
output += `# TYPE tool_latency_ms gauge\n`;
|
|
556
|
+
for (const tool of toolMetrics) {
|
|
557
|
+
const labels = `{server="${tool.serverName}",tool="${tool.toolName}"}`;
|
|
558
|
+
output += `tool_calls${labels} ${tool.calls}\n`;
|
|
559
|
+
output += `tool_success_rate${labels} ${tool.successRate.toFixed(2)}\n`;
|
|
560
|
+
output += `tool_latency_ms${labels} ${tool.latency.avg.toFixed(2)}\n`;
|
|
561
|
+
output += `tool_latency_p50_ms${labels} ${tool.latency.p50.toFixed(2)}\n`;
|
|
562
|
+
output += `tool_latency_p95_ms${labels} ${tool.latency.p95.toFixed(2)}\n`;
|
|
563
|
+
output += `tool_latency_p99_ms${labels} ${tool.latency.p99.toFixed(2)}\n`;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// Error analytics by type
|
|
567
|
+
const errorAnalytics = this.getErrorAnalytics();
|
|
568
|
+
if (errorAnalytics.totalErrors > 0) {
|
|
569
|
+
output += `# TYPE error_total counter\n`;
|
|
570
|
+
output += `error_total{} ${errorAnalytics.totalErrors}\n`;
|
|
571
|
+
output += `# TYPE error_rate gauge\n`;
|
|
572
|
+
output += `error_rate{} ${errorAnalytics.errorRate.toFixed(2)}\n`;
|
|
573
|
+
// Errors by type
|
|
574
|
+
output += `# TYPE errors_by_type counter\n`;
|
|
575
|
+
for (const [errorType, count] of Object.entries(errorAnalytics.errorsByType)) {
|
|
576
|
+
if (count > 0) {
|
|
577
|
+
output += `errors_by_type{type="${errorType}"} ${count}\n`;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// Errors by server
|
|
581
|
+
if (Object.keys(errorAnalytics.errorsByServer).length > 0) {
|
|
582
|
+
output += `# TYPE errors_by_server counter\n`;
|
|
583
|
+
for (const [serverName, count] of Object.entries(errorAnalytics.errorsByServer)) {
|
|
584
|
+
output += `errors_by_server{server="${serverName}"} ${count}\n`;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return output;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
// Global metrics instance
|
|
592
|
+
export const globalMetrics = new MetricsCollector();
|
|
593
|
+
/**
|
|
594
|
+
* MetricsPersistence - Disk persistence for metrics data
|
|
595
|
+
*
|
|
596
|
+
* Saves metrics to disk periodically to enable:
|
|
597
|
+
* - Metrics retention across daemon restarts
|
|
598
|
+
* - Historical analysis
|
|
599
|
+
* - Long-term trending
|
|
600
|
+
*/
|
|
601
|
+
export class MetricsPersistence {
|
|
602
|
+
constructor(baseDir) {
|
|
603
|
+
this.intervalHandle = null;
|
|
604
|
+
// Expand ~ to home directory if needed
|
|
605
|
+
this.persistenceDir = baseDir.replace(/^~/, process.env.HOME || '~');
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Get the path to the metrics file
|
|
609
|
+
*/
|
|
610
|
+
getMetricsPath() {
|
|
611
|
+
// Create directory if it doesn't exist
|
|
612
|
+
if (!fs.existsSync(this.persistenceDir)) {
|
|
613
|
+
fs.mkdirSync(this.persistenceDir, { recursive: true });
|
|
614
|
+
}
|
|
615
|
+
return path.join(this.persistenceDir, 'metrics.json');
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Load metrics from disk
|
|
619
|
+
*/
|
|
620
|
+
async load() {
|
|
621
|
+
try {
|
|
622
|
+
const content = await fsPromises.readFile(this.getMetricsPath(), 'utf8');
|
|
623
|
+
const data = JSON.parse(content);
|
|
624
|
+
console.log(`[MetricsPersistence] Loaded metrics from ${this.getMetricsPath()}`);
|
|
625
|
+
return data;
|
|
626
|
+
}
|
|
627
|
+
catch (error) {
|
|
628
|
+
const errCode = error.code;
|
|
629
|
+
if (errCode === 'ENOENT') {
|
|
630
|
+
// File doesn't exist yet - this is normal on first run
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
throw error;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Save metrics to disk
|
|
638
|
+
*/
|
|
639
|
+
async save(data) {
|
|
640
|
+
try {
|
|
641
|
+
const content = JSON.stringify(data, null, 2);
|
|
642
|
+
await fsPromises.writeFile(this.getMetricsPath(), content, 'utf8');
|
|
643
|
+
console.log(`[MetricsPersistence] Saved metrics to ${this.getMetricsPath()} ` +
|
|
644
|
+
`(${data.metrics.length} metrics, ${data.serverMetrics.length} servers)`);
|
|
645
|
+
}
|
|
646
|
+
catch (error) {
|
|
647
|
+
console.error('[MetricsPersistence] Failed to save metrics:', error);
|
|
648
|
+
throw error;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Start periodic writes
|
|
653
|
+
* @param getData - Function to get current metrics data
|
|
654
|
+
* @param intervalMs - Write interval in milliseconds
|
|
655
|
+
*/
|
|
656
|
+
startPeriodicWrites(getData, intervalMs) {
|
|
657
|
+
if (this.intervalHandle) {
|
|
658
|
+
clearInterval(this.intervalHandle);
|
|
659
|
+
}
|
|
660
|
+
this.intervalHandle = setInterval(async () => {
|
|
661
|
+
try {
|
|
662
|
+
const data = getData();
|
|
663
|
+
await this.save(data);
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
console.error('[MetricsPersistence] Periodic write failed:', error);
|
|
667
|
+
}
|
|
668
|
+
}, intervalMs);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Stop periodic writes
|
|
672
|
+
*/
|
|
673
|
+
stopPeriodicWrites() {
|
|
674
|
+
if (this.intervalHandle) {
|
|
675
|
+
clearInterval(this.intervalHandle);
|
|
676
|
+
this.intervalHandle = null;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* MetricsAggregator - Time-series aggregation for metrics
|
|
682
|
+
*
|
|
683
|
+
* Provides aggregation functions for:
|
|
684
|
+
* - Hourly rollups
|
|
685
|
+
* - Daily rollups
|
|
686
|
+
* - Weekly rollups
|
|
687
|
+
* - Custom time windows
|
|
688
|
+
*/
|
|
689
|
+
export class MetricsAggregator {
|
|
690
|
+
/**
|
|
691
|
+
* Aggregate metrics by hour
|
|
692
|
+
* @param metrics - Array of metrics to aggregate
|
|
693
|
+
* @param hours - Number of hours to aggregate (default: 24)
|
|
694
|
+
*/
|
|
695
|
+
aggregateHourly(metrics, hours = 24) {
|
|
696
|
+
const now = Date.now();
|
|
697
|
+
const hourMs = 60 * 60 * 1000;
|
|
698
|
+
const result = {};
|
|
699
|
+
for (const metric of metrics) {
|
|
700
|
+
const hourlyValues = new Array(hours).fill(0);
|
|
701
|
+
// Process history points
|
|
702
|
+
for (const point of metric.history) {
|
|
703
|
+
const hoursAgo = Math.floor((now - point.timestamp) / hourMs);
|
|
704
|
+
if (hoursAgo >= 0 && hoursAgo < hours) {
|
|
705
|
+
const index = hours - 1 - hoursAgo; // Reverse so newest is last
|
|
706
|
+
if (metric.type === 'counter') {
|
|
707
|
+
hourlyValues[index] = Math.max(hourlyValues[index], point.value);
|
|
708
|
+
}
|
|
709
|
+
else if (metric.type === 'gauge') {
|
|
710
|
+
hourlyValues[index] = point.value; // Latest value wins
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
result[metric.name] = hourlyValues;
|
|
715
|
+
}
|
|
716
|
+
return result;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Aggregate metrics by day
|
|
720
|
+
* @param metrics - Array of metrics to aggregate
|
|
721
|
+
* @param days - Number of days to aggregate (default: 7)
|
|
722
|
+
*/
|
|
723
|
+
aggregateDaily(metrics, days = 7) {
|
|
724
|
+
const now = Date.now();
|
|
725
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
726
|
+
const result = {};
|
|
727
|
+
for (const metric of metrics) {
|
|
728
|
+
const dailyValues = new Array(days).fill(0);
|
|
729
|
+
// Process history points
|
|
730
|
+
for (const point of metric.history) {
|
|
731
|
+
const daysAgo = Math.floor((now - point.timestamp) / dayMs);
|
|
732
|
+
if (daysAgo >= 0 && daysAgo < days) {
|
|
733
|
+
const index = days - 1 - daysAgo; // Reverse so newest is last
|
|
734
|
+
if (metric.type === 'counter') {
|
|
735
|
+
dailyValues[index] = Math.max(dailyValues[index], point.value);
|
|
736
|
+
}
|
|
737
|
+
else if (metric.type === 'gauge') {
|
|
738
|
+
dailyValues[index] = point.value; // Latest value wins
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
result[metric.name] = dailyValues;
|
|
743
|
+
}
|
|
744
|
+
return result;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Aggregate metrics by week
|
|
748
|
+
* @param metrics - Array of metrics to aggregate
|
|
749
|
+
* @param weeks - Number of weeks to aggregate (default: 4)
|
|
750
|
+
*/
|
|
751
|
+
aggregateWeekly(metrics, weeks = 4) {
|
|
752
|
+
const now = Date.now();
|
|
753
|
+
const weekMs = 7 * 24 * 60 * 60 * 1000;
|
|
754
|
+
const result = {};
|
|
755
|
+
for (const metric of metrics) {
|
|
756
|
+
const weeklyValues = new Array(weeks).fill(0);
|
|
757
|
+
// Process history points
|
|
758
|
+
for (const point of metric.history) {
|
|
759
|
+
const weeksAgo = Math.floor((now - point.timestamp) / weekMs);
|
|
760
|
+
if (weeksAgo >= 0 && weeksAgo < weeks) {
|
|
761
|
+
const index = weeks - 1 - weeksAgo; // Reverse so newest is last
|
|
762
|
+
if (metric.type === 'counter') {
|
|
763
|
+
weeklyValues[index] = Math.max(weeklyValues[index], point.value);
|
|
764
|
+
}
|
|
765
|
+
else if (metric.type === 'gauge') {
|
|
766
|
+
weeklyValues[index] = point.value; // Latest value wins
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
result[metric.name] = weeklyValues;
|
|
771
|
+
}
|
|
772
|
+
return result;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Calculate statistics for a metric over a time window
|
|
776
|
+
*/
|
|
777
|
+
calculateStats(metric, windowMs) {
|
|
778
|
+
const now = Date.now();
|
|
779
|
+
const cutoff = now - windowMs;
|
|
780
|
+
const relevantPoints = metric.history.filter((p) => p.timestamp >= cutoff);
|
|
781
|
+
if (relevantPoints.length === 0) {
|
|
782
|
+
return { min: 0, max: 0, avg: 0, count: 0 };
|
|
783
|
+
}
|
|
784
|
+
const values = relevantPoints.map((p) => p.value);
|
|
785
|
+
const min = Math.min(...values);
|
|
786
|
+
const max = Math.max(...values);
|
|
787
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
788
|
+
const avg = sum / values.length;
|
|
789
|
+
return { min, max, avg, count: relevantPoints.length };
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
//# sourceMappingURL=index.js.map
|