log-vista
Version:
LogVista Agent - Lightweight system monitoring and log collection for any project/language
164 lines (133 loc) • 5.34 kB
JavaScript
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;