UNPKG

node-watch-tower

Version:

Node.js monitoring utility to track uptime, CPU, and memory usage and report to a central admin server.

104 lines (88 loc) 3.29 kB
const os = require('os'); const axios = require('axios'); const process = require('process'); const { monitorEventLoopDelay } = require('perf_hooks'); class NodeWatchTower { constructor(config) { this.adminUrl = "https://prutech.co.in/nodeMonitor/api"; this.interval = 1000 * 60; this.token = config.token || null; this.registered = false; this.id = config.id || null; // Setup event loop delay monitor this.eventLoopMonitor = monitorEventLoopDelay({ resolution: 10 }); this.eventLoopMonitor.enable(); this.start(); } async start() { await this.register(); this.sendStatsLoop(); } async register() { try { const res = await axios.post(`${this.adminUrl}/app/register`, { id: this.id, hostname: os.hostname(), pid: process.pid, token: this.token, }); if (res.data?.status == 1) { this.registered = true; console.log('\x1b[32m[NodeWatchTower]\x1b[0m ✅ Registered with Admin Monitor'); this.interval = res.data?.data?.heartBeatInterval * 1000 || this.interval; } else { console.log('\x1b[31m[NodeWatchTower]\x1b[0m ❌ Registration Failed:', res.data.message); } } catch (err) { console.log('\x1b[31m[NodeWatchTower]\x1b[0m ❌ Registration Failed:', err?.response?.data?.message || err.message); } } async sendStatsLoop() { setInterval(async () => { if (!this.registered) return; try { const stats = this.getStats(); await axios.post(`${this.adminUrl}/app/heartbeat`, { id: this.id, stats, token: this.token, }); } catch (err) { console.log('\x1b[31m[NodeWatchTower]\x1b[0m ❌ Heartbeat failed:', err.message); } }, this.interval); } getStats() { const memory = process.memoryUsage(); const heapUsedMB = memory.heapUsed / 1024 / 1024; const heapTotalMB = memory.heapTotal / 1024 / 1024; const eventLoop = this.eventLoopMonitor; const p95 = eventLoop.percentile(95) / 1_000_000; // ns to ms const meanLatency = eventLoop.mean / 1_000_000; return { timestamp: new Date(), cpu: this.getAppCpuUsagePercent(), memory: { rss: (memory.rss / 1024 / 1024).toFixed(2), heapUsed: heapUsedMB.toFixed(2), heapTotal: heapTotalMB.toFixed(2), heapUsagePercent: ((heapUsedMB / heapTotalMB) * 100).toFixed(2), }, uptime: process.uptime().toFixed(2), eventLoopLatencyMs: meanLatency.toFixed(2), eventLoopLatencyP95Ms: p95.toFixed(2), activeHandles: process._getActiveHandles().length, activeRequests: process._getActiveRequests().length, }; } getAppCpuUsagePercent() { const cpuUsage = process.cpuUsage(); // in microseconds const elapsedTime = process.uptime(); // in seconds const totalMicroSec = cpuUsage.user + cpuUsage.system; const cpuUsedSeconds = totalMicroSec / 1_000_000; const cpuCores = os.cpus().length; const totalAvailableCpuTime = elapsedTime * cpuCores; return ((cpuUsedSeconds / totalAvailableCpuTime) * 100).toFixed(2); } } module.exports = NodeWatchTower;