@ceon-oy/monitor-sdk 1.3.0 → 1.4.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ceon Monitor SDK
2
2
 
3
- Lightweight client SDK for integrating with the Ceon Monitor service. Provides error reporting, technology tracking, vulnerability auditing, and security event monitoring.
3
+ Lightweight client SDK for integrating with the Ceon Monitor service. Provides error reporting, technology tracking, vulnerability auditing, system metrics collection (CPU, RAM, disk), and security event monitoring.
4
4
 
5
5
  ## Table of Contents
6
6
 
@@ -12,6 +12,7 @@ Lightweight client SDK for integrating with the Ceon Monitor service. Provides e
12
12
  - [Technology Tracking](#technology-tracking)
13
13
  - [Vulnerability Auditing](#vulnerability-auditing)
14
14
  - [SDK-Based Health Checks](#sdk-based-health-checks)
15
+ - [System Metrics](#system-metrics)
15
16
  - [Security Events](#security-events)
16
17
  - [Framework Examples](#framework-examples)
17
18
  - [Express.js](#expressjs)
@@ -490,6 +491,75 @@ const results = [
490
491
  await monitor.submitHealthResults(results);
491
492
  ```
492
493
 
494
+ ### System Metrics
495
+
496
+ The SDK automatically collects and reports server resource usage — CPU, RAM, and disk — to Ceon Monitor. No SDK configuration flag is needed; the feature activates based on the project settings configured in the Ceon Monitor dashboard.
497
+
498
+ #### How It Works
499
+
500
+ When the `MonitorClient` is created, it fetches your project settings from the server. If the project has **Enable Metric Collection** turned on, the SDK:
501
+
502
+ 1. Reads `metricsIntervalSeconds` from project settings (configured in the dashboard)
503
+ 2. Reads `metricsDiskPaths` from project settings (e.g. `["/", "/data"]`)
504
+ 3. Starts collecting metrics at that interval automatically
505
+ 4. POSTs metrics to the server — no manual calls needed
506
+
507
+ #### What Is Collected
508
+
509
+ | Metric | Method | Notes |
510
+ |--------|--------|-------|
511
+ | CPU usage % | Dual `os.cpus()` sample with 500 ms gap | Accurate active-cycle average |
512
+ | RAM total | `os.totalmem()` | Bytes |
513
+ | RAM used | `os.totalmem() - os.freemem()` | Bytes |
514
+ | RAM % | `usedMemory / totalMemory * 100` | |
515
+ | Disk total / used / free per path | `fs.statfs(path)` | Node.js 18.15+ built-in, zero external deps |
516
+
517
+ Hostname is automatically set via `os.hostname()` and included with every report.
518
+
519
+ #### Enable in Dashboard
520
+
521
+ 1. Open the **Ceon Monitor** dashboard
522
+ 2. Go to **Projects** and click **Edit** on your project
523
+ 3. Enable the **System Metrics** widget
524
+ 4. Click **Enable Metric Collection**
525
+ 5. Set the collection interval (e.g. every 60 seconds)
526
+ 6. Add disk paths to monitor (e.g. `/` for root, `/data` for a data volume)
527
+ 7. Configure CPU / RAM / disk alert thresholds
528
+ 8. Save
529
+
530
+ The SDK will pick up the new settings on its next startup.
531
+
532
+ #### Notifications
533
+
534
+ When a metric exceeds a configured threshold, Ceon Monitor sends a `SYSTEM_METRIC_CRITICAL` notification to any user who has subscribed to **System Metric Alerts** for that project. Subscribe in **Settings → Subscriptions**.
535
+
536
+ #### Node.js Version Requirement
537
+
538
+ `fs.statfs()` (used for disk monitoring) requires **Node.js 18.15 or later**. No external packages are needed.
539
+
540
+ #### Manual Metric Submission
541
+
542
+ You can also submit a metric reading manually:
543
+
544
+ ```typescript
545
+ await monitor.submitSystemMetric({
546
+ hostname: os.hostname(),
547
+ cpuPercent: 72.5,
548
+ memoryTotal: 8 * 1024 ** 3, // 8 GB in bytes
549
+ memoryUsed: 5 * 1024 ** 3, // 5 GB in bytes
550
+ memoryPercent: 62.5,
551
+ disks: [
552
+ {
553
+ path: '/',
554
+ total: 100 * 1024 ** 3, // 100 GB
555
+ used: 60 * 1024 ** 3, // 60 GB
556
+ free: 40 * 1024 ** 3, // 40 GB
557
+ usedPercent: 60,
558
+ },
559
+ ],
560
+ });
561
+ ```
562
+
493
563
  ### Security Events
494
564
 
495
565
  #### Report Security Event
@@ -1092,6 +1162,10 @@ Runs npm audit and sends results to the server.
1092
1162
 
1093
1163
  Runs npm audit on all directories configured in `auditPaths` and returns a combined summary.
1094
1164
 
1165
+ #### `submitSystemMetric(metric: SystemMetric): Promise<void>`
1166
+
1167
+ Manually submits a system metric reading. Under normal usage this is called automatically by the SDK's internal collection loop — use this only if you need custom collection logic.
1168
+
1095
1169
  #### `flush(): Promise<void>`
1096
1170
 
1097
1171
  Immediately sends all queued errors.
@@ -1160,6 +1234,23 @@ interface AuditPath {
1160
1234
  environment: string; // Environment label (e.g., 'server', 'client')
1161
1235
  }
1162
1236
 
1237
+ interface DiskMetric {
1238
+ path: string; // Mount path (e.g. '/', '/data')
1239
+ total: number; // Total bytes
1240
+ used: number; // Used bytes
1241
+ free: number; // Free bytes
1242
+ usedPercent: number; // 0–100
1243
+ }
1244
+
1245
+ interface SystemMetric {
1246
+ hostname: string;
1247
+ cpuPercent: number;
1248
+ memoryTotal: number;
1249
+ memoryUsed: number;
1250
+ memoryPercent: number;
1251
+ disks: DiskMetric[];
1252
+ }
1253
+
1163
1254
  interface MultiAuditSummary {
1164
1255
  results: Array<{
1165
1256
  environment: string;
package/dist/index.d.mts CHANGED
@@ -166,6 +166,7 @@ interface SdkHealthEndpoint {
166
166
  intervalMs: number;
167
167
  timeoutMs: number;
168
168
  expectedStatus: number;
169
+ allowInsecureTls?: boolean;
169
170
  }
170
171
  interface SdkHealthResult {
171
172
  endpointId: string;
@@ -231,6 +232,7 @@ declare class MonitorClient {
231
232
  private sdkErrorsInCurrentWindow;
232
233
  private sdkErrorWindowResetTimer;
233
234
  private metricsCollectionTimer;
235
+ private metricsSettingsCheckTimer;
234
236
  constructor(config: MonitorClientConfig);
235
237
  /**
236
238
  * Security: Validate and sanitize metadata to prevent oversized payloads
@@ -491,6 +493,7 @@ declare class MonitorClient {
491
493
  * Collects CPU, RAM, and disk usage using built-in Node.js modules.
492
494
  */
493
495
  setupSystemMetricsCollection(): Promise<void>;
496
+ private startMetricsCollection;
494
497
  private stopMetricsCollection;
495
498
  /**
496
499
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
package/dist/index.d.ts CHANGED
@@ -166,6 +166,7 @@ interface SdkHealthEndpoint {
166
166
  intervalMs: number;
167
167
  timeoutMs: number;
168
168
  expectedStatus: number;
169
+ allowInsecureTls?: boolean;
169
170
  }
170
171
  interface SdkHealthResult {
171
172
  endpointId: string;
@@ -231,6 +232,7 @@ declare class MonitorClient {
231
232
  private sdkErrorsInCurrentWindow;
232
233
  private sdkErrorWindowResetTimer;
233
234
  private metricsCollectionTimer;
235
+ private metricsSettingsCheckTimer;
234
236
  constructor(config: MonitorClientConfig);
235
237
  /**
236
238
  * Security: Validate and sanitize metadata to prevent oversized payloads
@@ -491,6 +493,7 @@ declare class MonitorClient {
491
493
  * Collects CPU, RAM, and disk usage using built-in Node.js modules.
492
494
  */
493
495
  setupSystemMetricsCollection(): Promise<void>;
496
+ private startMetricsCollection;
494
497
  private stopMetricsCollection;
495
498
  /**
496
499
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
package/dist/index.js CHANGED
@@ -101,6 +101,7 @@ var MonitorClient = class {
101
101
  this.sdkErrorWindowResetTimer = null;
102
102
  // System metrics collection (on-premise only, opt-in)
103
103
  this.metricsCollectionTimer = null;
104
+ this.metricsSettingsCheckTimer = null;
104
105
  if (!config.apiKey || config.apiKey.trim().length === 0) {
105
106
  throw new Error("[MonitorClient] API key is required");
106
107
  }
@@ -1347,6 +1348,19 @@ var MonitorClient = class {
1347
1348
  "Content-Type": "application/json"
1348
1349
  };
1349
1350
  }
1351
+ if (endpoint.allowInsecureTls) {
1352
+ try {
1353
+ const undici = await import(
1354
+ /* webpackIgnore: true */
1355
+ "undici"
1356
+ );
1357
+ const Agent = undici.Agent;
1358
+ requestOptions.dispatcher = new Agent({
1359
+ connect: { rejectUnauthorized: false }
1360
+ });
1361
+ } catch {
1362
+ }
1363
+ }
1350
1364
  const response = await this.fetchWithTimeout(
1351
1365
  endpoint.url,
1352
1366
  requestOptions,
@@ -1487,16 +1501,33 @@ var MonitorClient = class {
1487
1501
  async setupSystemMetricsCollection() {
1488
1502
  const settings = await this.fetchProjectSettings();
1489
1503
  if (!settings?.metricsEnabled) {
1504
+ this.metricsSettingsCheckTimer = setInterval(() => {
1505
+ this.fetchProjectSettings().then((latestSettings) => {
1506
+ if (latestSettings?.metricsEnabled) {
1507
+ clearInterval(this.metricsSettingsCheckTimer);
1508
+ this.metricsSettingsCheckTimer = null;
1509
+ this.startMetricsCollection(latestSettings);
1510
+ }
1511
+ }).catch(() => {
1512
+ });
1513
+ }, 3e5);
1490
1514
  return;
1491
1515
  }
1492
- const intervalMs = Math.max(3e4, (settings.metricsIntervalSeconds ?? 60) * 1e3);
1493
- const diskPaths = settings.metricsDiskPaths ?? ["/"];
1494
- console.log(`[MonitorClient] System metrics collection enabled (every ${intervalMs / 1e3}s, paths: ${diskPaths.join(", ")})`);
1495
- this.collectAndSubmitMetrics(diskPaths).catch((err) => {
1516
+ this.startMetricsCollection(settings);
1517
+ }
1518
+ startMetricsCollection(settings) {
1519
+ const intervalMs = Math.max(3e4, (settings.metricsIntervalSeconds ?? 3600) * 1e3);
1520
+ console.log(`[MonitorClient] System metrics collection enabled (every ${intervalMs / 1e3}s)`);
1521
+ const initialDiskPaths = settings.metricsDiskPaths ?? ["/"];
1522
+ this.collectAndSubmitMetrics(initialDiskPaths).catch((err) => {
1496
1523
  this.reportError("SYSTEM_METRICS", "Initial system metrics collection failed", err);
1497
1524
  });
1498
1525
  this.metricsCollectionTimer = setInterval(() => {
1499
- this.collectAndSubmitMetrics(diskPaths).catch((err) => {
1526
+ this.fetchProjectSettings().then((latestSettings) => {
1527
+ if (!latestSettings?.metricsEnabled) return;
1528
+ const diskPaths = latestSettings.metricsDiskPaths ?? ["/"];
1529
+ return this.collectAndSubmitMetrics(diskPaths);
1530
+ }).catch((err) => {
1500
1531
  this.reportError("SYSTEM_METRICS", "Scheduled system metrics collection failed", err);
1501
1532
  });
1502
1533
  }, intervalMs);
@@ -1506,6 +1537,10 @@ var MonitorClient = class {
1506
1537
  clearInterval(this.metricsCollectionTimer);
1507
1538
  this.metricsCollectionTimer = null;
1508
1539
  }
1540
+ if (this.metricsSettingsCheckTimer) {
1541
+ clearInterval(this.metricsSettingsCheckTimer);
1542
+ this.metricsSettingsCheckTimer = null;
1543
+ }
1509
1544
  }
1510
1545
  /**
1511
1546
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
package/dist/index.mjs CHANGED
@@ -65,6 +65,7 @@ var MonitorClient = class {
65
65
  this.sdkErrorWindowResetTimer = null;
66
66
  // System metrics collection (on-premise only, opt-in)
67
67
  this.metricsCollectionTimer = null;
68
+ this.metricsSettingsCheckTimer = null;
68
69
  if (!config.apiKey || config.apiKey.trim().length === 0) {
69
70
  throw new Error("[MonitorClient] API key is required");
70
71
  }
@@ -1311,6 +1312,19 @@ var MonitorClient = class {
1311
1312
  "Content-Type": "application/json"
1312
1313
  };
1313
1314
  }
1315
+ if (endpoint.allowInsecureTls) {
1316
+ try {
1317
+ const undici = await import(
1318
+ /* webpackIgnore: true */
1319
+ "undici"
1320
+ );
1321
+ const Agent = undici.Agent;
1322
+ requestOptions.dispatcher = new Agent({
1323
+ connect: { rejectUnauthorized: false }
1324
+ });
1325
+ } catch {
1326
+ }
1327
+ }
1314
1328
  const response = await this.fetchWithTimeout(
1315
1329
  endpoint.url,
1316
1330
  requestOptions,
@@ -1451,16 +1465,33 @@ var MonitorClient = class {
1451
1465
  async setupSystemMetricsCollection() {
1452
1466
  const settings = await this.fetchProjectSettings();
1453
1467
  if (!settings?.metricsEnabled) {
1468
+ this.metricsSettingsCheckTimer = setInterval(() => {
1469
+ this.fetchProjectSettings().then((latestSettings) => {
1470
+ if (latestSettings?.metricsEnabled) {
1471
+ clearInterval(this.metricsSettingsCheckTimer);
1472
+ this.metricsSettingsCheckTimer = null;
1473
+ this.startMetricsCollection(latestSettings);
1474
+ }
1475
+ }).catch(() => {
1476
+ });
1477
+ }, 3e5);
1454
1478
  return;
1455
1479
  }
1456
- const intervalMs = Math.max(3e4, (settings.metricsIntervalSeconds ?? 60) * 1e3);
1457
- const diskPaths = settings.metricsDiskPaths ?? ["/"];
1458
- console.log(`[MonitorClient] System metrics collection enabled (every ${intervalMs / 1e3}s, paths: ${diskPaths.join(", ")})`);
1459
- this.collectAndSubmitMetrics(diskPaths).catch((err) => {
1480
+ this.startMetricsCollection(settings);
1481
+ }
1482
+ startMetricsCollection(settings) {
1483
+ const intervalMs = Math.max(3e4, (settings.metricsIntervalSeconds ?? 3600) * 1e3);
1484
+ console.log(`[MonitorClient] System metrics collection enabled (every ${intervalMs / 1e3}s)`);
1485
+ const initialDiskPaths = settings.metricsDiskPaths ?? ["/"];
1486
+ this.collectAndSubmitMetrics(initialDiskPaths).catch((err) => {
1460
1487
  this.reportError("SYSTEM_METRICS", "Initial system metrics collection failed", err);
1461
1488
  });
1462
1489
  this.metricsCollectionTimer = setInterval(() => {
1463
- this.collectAndSubmitMetrics(diskPaths).catch((err) => {
1490
+ this.fetchProjectSettings().then((latestSettings) => {
1491
+ if (!latestSettings?.metricsEnabled) return;
1492
+ const diskPaths = latestSettings.metricsDiskPaths ?? ["/"];
1493
+ return this.collectAndSubmitMetrics(diskPaths);
1494
+ }).catch((err) => {
1464
1495
  this.reportError("SYSTEM_METRICS", "Scheduled system metrics collection failed", err);
1465
1496
  });
1466
1497
  }, intervalMs);
@@ -1470,6 +1501,10 @@ var MonitorClient = class {
1470
1501
  clearInterval(this.metricsCollectionTimer);
1471
1502
  this.metricsCollectionTimer = null;
1472
1503
  }
1504
+ if (this.metricsSettingsCheckTimer) {
1505
+ clearInterval(this.metricsSettingsCheckTimer);
1506
+ this.metricsSettingsCheckTimer = null;
1507
+ }
1473
1508
  }
1474
1509
  /**
1475
1510
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceon-oy/monitor-sdk",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Client SDK for Ceon Monitor - Error tracking, health monitoring, security events, and vulnerability scanning",
5
5
  "author": "Ceon",
6
6
  "license": "MIT",