@gazzehamine/armada-watch-agent 1.4.1 → 1.4.3

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/dist/collector.js CHANGED
@@ -7,6 +7,8 @@ exports.getSystemInfo = getSystemInfo;
7
7
  exports.collectMetrics = collectMetrics;
8
8
  exports.collectProcesses = collectProcesses;
9
9
  exports.collectDockerContainers = collectDockerContainers;
10
+ exports.collectNginxMetrics = collectNginxMetrics;
11
+ exports.collectPM2Processes = collectPM2Processes;
10
12
  exports.collectSSLCertificates = collectSSLCertificates;
11
13
  const systeminformation_1 = __importDefault(require("systeminformation"));
12
14
  const os_1 = __importDefault(require("os"));
@@ -262,6 +264,89 @@ async function getCertificateInfo(certPath, domain) {
262
264
  return null;
263
265
  }
264
266
  }
267
+ /**
268
+ * Collect Nginx metrics from stub_status
269
+ */
270
+ async function collectNginxMetrics() {
271
+ try {
272
+ // Try common nginx stub_status URLs
273
+ const urls = [
274
+ 'http://localhost/nginx_status',
275
+ 'http://localhost:80/nginx_status',
276
+ 'http://127.0.0.1/nginx_status',
277
+ 'http://localhost/status',
278
+ ];
279
+ for (const url of urls) {
280
+ try {
281
+ const { stdout } = await execAsync(`curl -s ${url} --max-time 2`, { timeout: 3000 });
282
+ if (stdout && stdout.includes('Active connections')) {
283
+ // Parse nginx stub_status output
284
+ // Example:
285
+ // Active connections: 2
286
+ // server accepts handled requests
287
+ // 123 123 456
288
+ // Reading: 0 Writing: 1 Waiting: 1
289
+ const activeMatch = stdout.match(/Active connections:\s+(\d+)/);
290
+ const serverMatch = stdout.match(/\s+(\d+)\s+(\d+)\s+(\d+)/);
291
+ const rwwMatch = stdout.match(/Reading:\s+(\d+)\s+Writing:\s+(\d+)\s+Waiting:\s+(\d+)/);
292
+ if (activeMatch && serverMatch && rwwMatch) {
293
+ const accepts = parseInt(serverMatch[1]);
294
+ const handled = parseInt(serverMatch[2]);
295
+ const requests = parseInt(serverMatch[3]);
296
+ // Calculate per-second rates (will be calculated from deltas in the backend)
297
+ return {
298
+ activeConnections: parseInt(activeMatch[1]),
299
+ accepts,
300
+ handled,
301
+ requests,
302
+ reading: parseInt(rwwMatch[1]),
303
+ writing: parseInt(rwwMatch[2]),
304
+ waiting: parseInt(rwwMatch[3]),
305
+ requestsPerSecond: 0, // Will be calculated from deltas
306
+ connectionsPerSecond: 0, // Will be calculated from deltas
307
+ };
308
+ }
309
+ }
310
+ }
311
+ catch (error) {
312
+ // Try next URL
313
+ continue;
314
+ }
315
+ }
316
+ // Nginx not available or stub_status not configured
317
+ return null;
318
+ }
319
+ catch (error) {
320
+ return null;
321
+ }
322
+ }
323
+ /**
324
+ * Collect PM2 process information
325
+ */
326
+ async function collectPM2Processes() {
327
+ try {
328
+ // Execute pm2 jlist command to get JSON output
329
+ const { stdout } = await execAsync('pm2 jlist');
330
+ const pm2Processes = JSON.parse(stdout);
331
+ return pm2Processes.map((proc) => ({
332
+ pmId: proc.pm_id || 0,
333
+ name: proc.name || 'unknown',
334
+ version: proc.pm2_env?.version || 'unknown',
335
+ mode: proc.pm2_env?.exec_mode || 'unknown',
336
+ pid: proc.pid || 0,
337
+ uptime: proc.pm2_env?.pm_uptime || 0,
338
+ restarts: proc.pm2_env?.restart_time || 0,
339
+ status: proc.pm2_env?.status || 'unknown',
340
+ cpu: proc.monit?.cpu || 0,
341
+ memory: proc.monit?.memory || 0,
342
+ user: proc.pm2_env?.username || 'unknown',
343
+ }));
344
+ }
345
+ catch (error) {
346
+ // PM2 not installed or no processes running
347
+ return [];
348
+ }
349
+ }
265
350
  /**
266
351
  * Collect SSL certificate information from Certbot certificates
267
352
  */
package/dist/index.js CHANGED
@@ -75,6 +75,8 @@ async function sendMetrics() {
75
75
  const metrics = await (0, collector_1.collectMetrics)();
76
76
  const processes = await (0, collector_1.collectProcesses)();
77
77
  const dockerContainers = await (0, collector_1.collectDockerContainers)();
78
+ const pm2Processes = await (0, collector_1.collectPM2Processes)();
79
+ const nginxMetrics = await (0, collector_1.collectNginxMetrics)();
78
80
  // Check if it's time to refresh SSL certificates (every 5 minutes)
79
81
  const now = Date.now();
80
82
  const shouldCheckSSL = (now - lastSSLCheckTime) >= SSL_CHECK_INTERVAL;
@@ -93,13 +95,17 @@ async function sendMetrics() {
93
95
  },
94
96
  processes,
95
97
  dockerContainers,
98
+ pm2Processes: pm2Processes.length > 0 ? pm2Processes : undefined,
99
+ nginxMetrics: nginxMetrics || undefined,
96
100
  // Always send SSL certificates if we have them (from startup or last check)
97
101
  sslCertificates: lastSSLCertificates.length > 0 ? lastSSLCertificates : undefined,
98
102
  };
99
103
  await axios_1.default.post(`${SERVER_URL}/api/metrics`, payload, {
100
104
  timeout: 5000,
101
105
  });
102
- console.log(`✓ Metrics sent successfully - CPU: ${metrics.cpuUsage.toFixed(1)}% | Memory: ${metrics.memoryUsage.toFixed(1)}%`);
106
+ const pm2Info = pm2Processes.length > 0 ? ` | PM2: ${pm2Processes.length}` : '';
107
+ const nginxInfo = nginxMetrics ? ` | Nginx: ${nginxMetrics.activeConnections} conn` : '';
108
+ console.log(`✓ Metrics sent successfully - CPU: ${metrics.cpuUsage.toFixed(1)}% | Memory: ${metrics.memoryUsage.toFixed(1)}%${pm2Info}${nginxInfo}`);
103
109
  }
104
110
  catch (error) {
105
111
  if (axios_1.default.isAxiosError(error)) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gazzehamine/armada-watch-agent",
3
- "version": "1.4.1",
4
- "description": "Monitoring agent for Armada Watch - EC2 instance monitoring with SSL certificate tracking",
3
+ "version": "1.4.3",
4
+ "description": "Monitoring agent for Armada Watch - EC2 instance monitoring with SSL, PM2, and Nginx monitoring",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "armada-watch-agent": "dist/index.js"