UNPKG

log-vista

Version:

LogVista Agent - Lightweight system monitoring and log collection for any project/language

164 lines (133 loc) 5.34 kB
const si = require('systeminformation'); const pidusage = require('pidusage'); const fs = require('fs').promises; const path = require('path'); const logger = require('./logger'); class MetricsCollector { constructor() { this.lastNetworkStats = null; } async collectSystemMetrics() { try { const metrics = {}; // CPU information const cpuLoad = await si.currentLoad(); metrics.cpuUsage = cpuLoad.currentLoad; // Memory information const mem = await si.mem(); metrics.ramUsage = (mem.used / 1024 / 1024); // Convert to MB metrics.ramTotal = (mem.total / 1024 / 1024); // Convert to MB // Disk information const fsSize = await si.fsSize(); if (fsSize && fsSize.length > 0) { // Sum up all disk usage const totalUsed = fsSize.reduce((sum, disk) => sum + disk.used, 0); const totalSize = fsSize.reduce((sum, disk) => sum + disk.size, 0); metrics.diskUsage = totalUsed / 1024 / 1024; // Convert to MB metrics.diskTotal = totalSize / 1024 / 1024; // Convert to MB } // Network information const networkStats = await si.networkStats(); if (networkStats && networkStats.length > 0) { const primaryInterface = networkStats[0]; if (this.lastNetworkStats) { // Calculate delta from last measurement const timeDiff = Date.now() - this.lastNetworkStats.timestamp; const rxDiff = primaryInterface.rx_bytes - this.lastNetworkStats.rx_bytes; const txDiff = primaryInterface.tx_bytes - this.lastNetworkStats.tx_bytes; metrics.networkIn = (rxDiff / 1024 / 1024) / (timeDiff / 1000); // MB/s metrics.networkOut = (txDiff / 1024 / 1024) / (timeDiff / 1000); // MB/s } this.lastNetworkStats = { rx_bytes: primaryInterface.rx_bytes, tx_bytes: primaryInterface.tx_bytes, timestamp: Date.now() }; } // Process count const processes = await si.processes(); metrics.processCount = processes.all; // System load (Linux/macOS) try { const load = await si.currentLoad(); metrics.loadAverage = load.avgLoad; } catch (error) { // Load average might not be available on Windows logger.debug('Load average not available:', error.message); } metrics.timestamp = new Date(); return metrics; } catch (error) { logger.error('Error collecting system metrics:', error); throw error; } } async collectProjectMetrics(projectConfig) { try { const metrics = { projectName: projectConfig.project_name, timestamp: new Date() }; // Check if project directory exists try { await fs.access(projectConfig.pwd_path); // Get directory size const dirSize = await this.getDirectorySize(projectConfig.pwd_path); metrics.projectDiskUsage = dirSize / 1024 / 1024; // Convert to MB // Check if there are any processes running in the project directory // This is a simplified approach - in production, you might want to track specific PIDs const processes = await si.processes(); const projectProcesses = processes.list.filter(proc => proc.command && proc.command.includes(projectConfig.pwd_path) ); if (projectProcesses.length > 0) { let totalCpu = 0; let totalMem = 0; for (const proc of projectProcesses) { try { const procStats = await pidusage(proc.pid); totalCpu += procStats.cpu; totalMem += procStats.memory / 1024 / 1024; // Convert to MB } catch (procError) { // Process might have ended logger.debug(`Process ${proc.pid} not found:`, procError.message); } } metrics.projectCpuUsage = totalCpu; metrics.projectRamUsage = totalMem; metrics.projectProcessCount = projectProcesses.length; } } catch (accessError) { logger.warn(`Project directory not accessible: ${projectConfig.pwd_path}`, accessError); } return metrics; } catch (error) { logger.error('Error collecting project metrics:', error); throw error; } } async getDirectorySize(dirPath) { let totalSize = 0; try { const items = await fs.readdir(dirPath); for (const item of items) { const itemPath = path.join(dirPath, item); try { const stats = await fs.stat(itemPath); if (stats.isDirectory()) { totalSize += await this.getDirectorySize(itemPath); } else { totalSize += stats.size; } } catch (itemError) { // Skip inaccessible files/directories logger.debug(`Cannot access ${itemPath}:`, itemError.message); } } } catch (error) { logger.debug(`Cannot read directory ${dirPath}:`, error.message); } return totalSize; } } module.exports = MetricsCollector;