diff --git a/lib/API.js b/lib/API.js index 5a408013..fd33b7bd 100644 --- a/lib/API.js +++ b/lib/API.js @@ -1725,13 +1725,11 @@ class API { if ((conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI')) return false; - return that.Client.executeRemote('getSystemData', {}, (err, sys_infos) => { - that.Client.executeRemote('getMonitorData', {}, (err, proc_list) => { - doList(err, proc_list, sys_infos) - }) + return that.Client.executeRemote('getMonitorData', {}, (err, proc_list) => { + doList(err, proc_list) }) - function doList(err, list, sys_infos) { + function doList(err, list) { if (err) { if (that.gl_retry == 0) { that.gl_retry += 1; @@ -1758,7 +1756,7 @@ class API { chalk.bold(that.gl_interact_infos.machine_name), chalk.bold(dashboard_url)) } - UX.list(list, sys_infos, commander); + UX.list(list, commander); //Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); } diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 23ece50a..3f5396cd 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -32,21 +32,13 @@ module.exports = function(CLI) { }; /** - * Get version of the daemonized PM2 - * @method getVersion - * @callback cb + * Install pm2-sysmonit */ CLI.prototype.launchSysMonitoring = function(cb) { var that = this; - this.set('pm2:sysmonit', 'true', () => { - that.Client.executeRemote('launchSysMonitoring', {}, function(err) { - if (err) - Common.err(err) - else - Common.log('System Monitoring launched') - return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT); - }) + that.install('pm2-sysmonit', (err, apps) => { + return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT); }) }; diff --git a/lib/API/UX/pm2-ls.js b/lib/API/UX/pm2-ls.js index 8584646c..da43fe4a 100644 --- a/lib/API/UX/pm2-ls.js +++ b/lib/API/UX/pm2-ls.js @@ -24,10 +24,10 @@ function checkIfProcessAreDumped(list) { .map(proc => proc.name) var diff = apps_dumped.filter(a => !apps_running.includes(a)) if (diff.length > 0) { - Common.printOut(`Current process list running is not in sync with saved list. App ${chalk.bold(diff.join(' '))} differs. Type 'pm2 save' to synchronize.`) + Common.warn(`Current process list is not synchronized with saved list. App ${chalk.bold(diff.join(' '))} differs. Type 'pm2 save' to synchronize.`) } else if (apps_dumped.length != apps_running.length) { - Common.printOut(`Current process list running is not in sync with saved list. Type 'pm2 save' to synchronize'`) + Common.warn(`Current process list is not synchronized with saved list. Type 'pm2 save' to synchronize.`) } } catch(e) { } @@ -402,39 +402,51 @@ function listHighResourcesProcesses(sys_infos) { * Sys info line */ function miniMonitBar(sys_infos) { + let sys_metrics = sys_infos.pm2_env.axm_monitor + + let cpu = sys_metrics['cpu'] + + if (typeof(cpu) == 'undefined') return + var sys_summary_line = `${chalk.bold.cyan('host metrics')} ` - sys_summary_line += `| ${chalk.bold('cpu')}: ${UxHelpers.colorizedMetric(sys_infos.cpu.usage, 40, 70, '%')}` - if (sys_infos.cpu.temperature && sys_infos.cpu.temperature != '-1') { - sys_summary_line += ` ${UxHelpers.colorizedMetric(sys_infos.cpu.temperature, 50, 70, 'º')}` + sys_summary_line += `| ${chalk.bold('cpu')}: ${UxHelpers.colorizedMetric(cpu.value, 40, 70, '%')}` + + let temp = sys_metrics['cpu:temp'].value + if (temp && temp != '-1') { + sys_summary_line += ` ${UxHelpers.colorizedMetric(temp, 50, 70, 'º')}` } - if (sys_infos.mem) { - var perc_mem_usage = (((sys_infos.mem.available) / sys_infos.mem.total) * 100).toFixed(1) + + let mem_total = sys_metrics['mem:total'].value + let mem_available = sys_metrics['mem:available'].value + + if (mem_total) { + var perc_mem_usage = (((mem_available) / mem_total) * 100).toFixed(1) sys_summary_line += ` | ${chalk.bold('mem free')}: ${UxHelpers.colorizedMetric(perc_mem_usage, 30, 10, '%')} ` } - if (sys_infos.network) { - var latency = (sys_infos.network.latency).toFixed(1) - if (latency == -1) { - sys_summary_line += `| ${chalk.bold('net')}: ${chalk.red('offline')} ` - } - else { - sys_summary_line += `| ${chalk.bold('net')}: ` - //sys_summary_line += `${colorizedMetric(latency, 100, 150, 'ms')} ` - sys_summary_line += `⇓ ${UxHelpers.colorizedMetric(sys_infos.network.rx_5, 10, 20, 'mb/s')} ` - sys_summary_line += `⇑ ${UxHelpers.colorizedMetric(sys_infos.network.tx_5, 10, 20, 'mb/s')} ` - } - } + + let interfaces = Object.keys(sys_metrics).filter(m => m.includes('net') && m != 'net:default').map(i => i.split(':')[1]).filter((iface, i, self) => self.indexOf(iface) === i) + + interfaces.forEach(iface => { + sys_summary_line += `| ${chalk.bold(iface)}: ` + sys_summary_line += `⇓ ${UxHelpers.colorizedMetric(sys_metrics[`net:${iface}:rx_5`].value, 10, 20, 'mb/s')} ` + sys_summary_line += `⇑ ${UxHelpers.colorizedMetric(sys_metrics[`net:${iface}:tx_5`].value, 10, 20, 'mb/s')} ` + }) + + if (CONDENSED_MODE == false) { - if (sys_infos.storage) { - sys_summary_line += `| ${chalk.bold('disk')}: ⇓ ${UxHelpers.colorizedMetric(sys_infos.storage.io.read, 10, 20, 'mb/s')}` - sys_summary_line += ` ⇑ ${UxHelpers.colorizedMetric(sys_infos.storage.io.write, 10, 20, 'mb/s')} ` - } + let read = sys_metrics['io:r'].value + let write = sys_metrics['io:w'].value + + sys_summary_line += `| ${chalk.bold('disk')}: ⇓ ${UxHelpers.colorizedMetric(read, 10, 20, 'mb/s')}` + sys_summary_line += ` ⇑ ${UxHelpers.colorizedMetric(write, 10, 20, 'mb/s')} ` + + let disks = Object.keys(sys_metrics).filter(m => m.includes('fs:')).map(i => i.split(':')[1]).filter((iface, i, self) => self.indexOf(iface) === i) var disk_nb = 0 - sys_infos.storage.filesystems.forEach(fs => { - disk_nb++ - var perc_used = ((fs.used / fs.size) * 100).toFixed() - if (perc_used > 60) - sys_summary_line += `${chalk.grey(fs.fs)} ${UxHelpers.colorizedMetric(perc_used, 80, 90, '%')} ` + disks.forEach(fs => { + let use = sys_metrics[`fs:${fs}:use`].value + if (use > 60) + sys_summary_line += `${chalk.grey(fs)} ${UxHelpers.colorizedMetric(use, 80, 90, '%')} ` }) } @@ -448,7 +460,7 @@ function miniMonitBar(sys_infos) { * @param {Object} list * @param {Object} system informations (via pm2 sysmonit/pm2 sysinfos) */ -module.exports = function(list, sys_infos, commander) { +module.exports = function(list, commander) { var pm2_conf = Configuration.getSync('pm2') if (!list) @@ -456,17 +468,9 @@ module.exports = function(list, sys_infos, commander) { listModulesAndAppsManaged(list, commander) - if (sys_infos) { - if (sys_infos.containers && sys_infos.containers.length > 0 && - (pm2_conf && pm2_conf.show_docker == "true")) - containersListing(sys_infos) - - if (sys_infos.processes && (sys_infos.processes.cpu_sorted || sys_infos.processes.mem_sorted)) - listHighResourcesProcesses(sys_infos) - - if (sys_infos.cpu && sys_infos.cpu.usage) - miniMonitBar(sys_infos) - } + let sysmonit = list.filter(proc => proc.name == 'pm2-sysmonit') + if (sysmonit && sysmonit[0]) + miniMonitBar(sysmonit[0]) checkIfProcessAreDumped(list) } diff --git a/lib/Daemon.js b/lib/Daemon.js index ed21fa29..6a521e72 100644 --- a/lib/Daemon.js +++ b/lib/Daemon.js @@ -217,9 +217,7 @@ Daemon.prototype.innerStart = function(cb) { profileCPU : profile.bind(this, 'cpu'), profileMEM : profile.bind(this, 'mem'), prepare : God.prepare, - launchSysMonitoring : God.launchSysMonitoring, getMonitorData : God.getMonitorData, - getSystemData : God.getSystemData, startProcessId : God.startProcessId, stopProcessId : God.stopProcessId, diff --git a/lib/God.js b/lib/God.js index 1923e31f..beac9510 100644 --- a/lib/God.js +++ b/lib/God.js @@ -79,10 +79,6 @@ God.init = function() { this.configuration = Configuration.getSync('pm2') - if (this.configuration && this.configuration.sysmonit == 'true') { - God.launchSysMonitoring({}, () => { console.log('System monitoring launched') }) - } - setTimeout(function() { God.Worker.start() }, 500) @@ -586,27 +582,4 @@ God.injectVariables = function injectVariables (env, cb) { return cb(null, env); }; -God.launchSysMonitoring = function(env, cb) { - if (God.system_infos_proc !== null) - return cb(new Error('Sys Monitoring already launched')) - - try { - var sysinfo = require('./Sysinfo/SystemInfo.js') - God.system_infos_proc = new sysinfo() - - setInterval(() => { - God.system_infos_proc.query((err, data) => { - if (err) return - God.system_infos = data - }) - }, 1000) - - God.system_infos_proc.fork() - } catch(e) { - console.log(e) - God.system_infos_proc = null - } - return cb() -} - God.init() diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index c698d199..1ae75770 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -118,23 +118,6 @@ module.exports = function(God) { }); }; - /** - * Description - * @method getSystemData - * @param {} env - * @param {} cb - * @return - */ - God.getSystemData = function getSystemData(env, cb) { - if (God.system_infos_proc !== null) - God.system_infos_proc.query((err, data) => { - cb(null, data) - }) - else { - cb(new Error('Sysinfos not launched, type: pm2 sysmonit')) - } - }; - /** * Description * @method dumpProcessList diff --git a/lib/Sysinfo/MeanCalc.js b/lib/Sysinfo/MeanCalc.js deleted file mode 100644 index 453a7213..00000000 --- a/lib/Sysinfo/MeanCalc.js +++ /dev/null @@ -1,26 +0,0 @@ - -class MeanCalc { - constructor(count) { - this.metrics = [] - this.count = count - } - - inspect() { - return this.val() - } - - add(value) { - if (this.metrics.length >= this.count) { - this.metrics.shift() - } - this.metrics.push(value) - } - - val() { - if (this.metrics.length == 0) return 0 - let sum = this.metrics.reduce((prev, curr) => curr += prev) - return Math.floor((sum / this.metrics.length) * 1000) / 1000 - } -} - -module.exports = MeanCalc diff --git a/lib/Sysinfo/ServiceDetection/ServiceDetection.js b/lib/Sysinfo/ServiceDetection/ServiceDetection.js deleted file mode 100644 index 1199b6a9..00000000 --- a/lib/Sysinfo/ServiceDetection/ServiceDetection.js +++ /dev/null @@ -1,118 +0,0 @@ - -const PM2 = require('./../../API.js') -const psList = require('../psList.js') - -const SERVICES_ASSOCIATION = { - 'mongodb,mongo': { - module: 'pm2-mongodb' - }, - 'redis,redis-server': { - module: 'pm2-redis' - }, - 'elasticsearch': { - module: 'pm2-elasticsearch' - }, - 'docker': { - module: 'pm2-monit-docker' - }, - 'consul': { - module:'pm2-monit-consul' - }, - 'pm2': { - module: 'pm2-probe' - }, - 'fpm': { - module: 'pm2-php-fpm' - } -} - -// 'python,python3': { -// module: 'pm2-python' -// }, -// 'nginx': { -// module: 'pm2-monit-nginx' -// }, -// 'haproxy': { -// module: 'pm2-monit-haproxy' -// }, -// 'traeffik': { -// module: 'pm2-monit-traeffik' -// } - -class ServicesDetection { - constructor() { - this.pm2 = new PM2() - } - - startDetection(cb = () => {}) { - // Check running probes - this.monitoredServices((err, pm2_services) => { - // Check running services - this.discover((err, required_modules) => { - var required_monitoring_probes = Object.keys(required_modules) - // Make the diff between - // console.log(`Need to start following modules:`) - // console.log(_.difference(required_monitoring_probes, pm2_services)) - this.pm2.install('pm2-server-monit', (err, apps) => { - cb() - }) - }) - }) - } - - monitoredServices(cb) { - var f_proc_list = [] - - this.pm2.list((err, proc_list) => { - f_proc_list = proc_list.map(p => { - return p.name - }) - this.pm2.close() - cb(err, f_proc_list) - }) - } - - discover(cb) { - psList() - .then(processes => { - var supported_systems = Object.keys(SERVICES_ASSOCIATION) - var required_modules = {} - - processes.forEach((proc) => { - supported_systems.forEach(sup_sys => { - var proc_names = sup_sys.split(',') - proc_names.forEach(proc_name => { - if (proc.name.includes(proc_name) === true || - proc.cmd.includes(proc_name) === true) { - var key = SERVICES_ASSOCIATION[sup_sys].module - required_modules[key] = SERVICES_ASSOCIATION[sup_sys] - required_modules[key].monit = proc - } - }) - }) - }) - return cb(null, required_modules) - }) - .catch(e => { - console.error(`Error while listing processes`, e) - }) - } -} - -if (require.main === module) { - var serviceDetection = new ServicesDetection() - - var process = (done) => { - serviceDetection.startDetection((err, procs) => { - done() - }) - } - - var iterate = () => { - process(() => { - setTimeout(iterate, 3000) - }) - } - - iterate() -} diff --git a/lib/Sysinfo/SystemInfo.js b/lib/Sysinfo/SystemInfo.js deleted file mode 100644 index 66ef9d61..00000000 --- a/lib/Sysinfo/SystemInfo.js +++ /dev/null @@ -1,633 +0,0 @@ - -const sysinfo = require('systeminformation') -const psList = require('./psList.js') -const async = require('async') -const MeanCalc = require('./MeanCalc.js') -const fork = require('child_process').fork -const DEFAULT_CONVERSION = 1024 * 1024 -const os = require('os') -const fs = require('fs') -const debug = require('debug')('pm2:sysinfos') - -class SystemInfo { - constructor() { - this.infos = { - baseboard: { - model: null, - version: null - }, - cpu: { - manufacturer: null, - brand: null, - speedmax: null, - cores: null, - physicalCores: null, - processors: null, - temperature: null, - usage: null - }, - graphics: { - model: null, - driverVersion: null, - memTotal: null, - memUsed: null, - temperature: null - }, - mem: { - total: null, - free: null, - active: null - }, - os: { - platform: null, - distro: null, - release: null, - codename: null, - kernel: null, - arch: null, - }, - fd: { - opened: null, - max: null - }, - storage: { - io: { - read: new MeanCalc(15), - write: new MeanCalc(15) - }, - physical_disks: [{ - device: null, - type: null, - name: null, - interfaceType: null, - vendor: null - }], - filesystems: [{ - }] - }, - connections: ['source_ip:source_port-dest_ip:dest_port-proc_name'], - network: { - latency: new MeanCalc(5), - tx_5: new MeanCalc(5), - rx_5: new MeanCalc(5), - rx_errors_60: new MeanCalc(60), - tx_errors_60: new MeanCalc(60), - tx_dropped_60: new MeanCalc(60), - rx_dropped_60: new MeanCalc(60) - }, - // Procs - containers: [], - processes: { - cpu_sorted: null, - mem_sorted: null - }, - services: { - running: null, - stopped: null - } - } - this.restart = true - this.ping_timeout = null - } - - // Cast MeanCalc and other object to real value - // This method retrieve the machine snapshot well formated - report() { - var report = JSON.parse(JSON.stringify(this.infos)) - report.network.latency = this.infos.network.latency.val() - report.network.tx_5 = this.infos.network.tx_5.val() - report.network.rx_5 = this.infos.network.rx_5.val() - report.network.rx_errors_60 = this.infos.network.rx_errors_60.val() - report.network.tx_errors_60 = this.infos.network.tx_errors_60.val() - report.network.rx_dropped_60 = this.infos.network.rx_dropped_60.val() - report.network.tx_dropped_60 = this.infos.network.tx_dropped_60.val() - report.storage.io.read = this.infos.storage.io.read.val() - report.storage.io.write = this.infos.storage.io.write.val() - return report - } - - fork() { - this.process = fork(__filename, { - detached: false, - windowsHide: true, - stdio: ['inherit', 'inherit', 'inherit', 'ipc'] - }) - - this.process.on('exit', (code) => { - console.log(`systeminfos collection process offline with code ${code}`) - // if (this.restart == true) - // this.fork() - }) - - this.process.on('error', (e) => { - console.log(`Sysinfo errored`, e) - }) - - this.process.on('message', (msg) => { - try { - msg = JSON.parse(msg) - } - catch (e) { - } - if (msg.cmd == 'ping') { - if (this.process.connected == true) { - try { - this.process.send('pong') - } catch(e) { - console.error('Cannot send message to Sysinfos') - } - } - } - }) - } - - query(cb) { - if (this.process.connected == true) { - try { - this.process.send('query') - } catch(e) { - return cb(new Error('not ready yet'), null) - } - } - else - return cb(new Error('not ready yet'), null) - - var res = (msg) => { - try { - msg = JSON.parse(msg) - } - catch (e) { - } - - if (msg.cmd == 'query:res') { - listener.removeListener('message', res) - return cb(null, msg.data) - } - } - - var listener = this.process.on('message', res) - } - - kill() { - this.restart = false - this.process.kill() - } - - startCollection() { - this.staticInformations() - - var dockerCollection, processCollection, memCollection, - servicesCollection, graphicsCollection - - (dockerCollection = () => { - this.dockerSummary(() => { - setTimeout(dockerCollection.bind(this), 5000) - }) - })(); - - (processCollection = () => { - this.processesSummary(() => { - setTimeout(processCollection.bind(this), 5000) - }) - })(); - - (graphicsCollection = () => { - this.graphicsInformations(() => { - setTimeout(graphicsCollection.bind(this), 20000) - }) - })(); - - // (servicesCollection = () => { - // this.servicesSummary(() => { - // setTimeout(servicesCollection.bind(this), 60000) - // }) - // })(); - - (memCollection = () => { - this.memStats(() => { - setTimeout(memCollection.bind(this), 1000) - }) - })(); - - //this.networkConnectionsWorker() - this.disksStatsWorker() - this.networkStatsWorker() - - this.cpuStatsWorker() - this.fdStatsWorker() - - setInterval(() => { - if (process.connected == false) { - console.error('Sysinfos not connected, exiting') - process.exit() - } - try { - process.send(JSON.stringify({cmd: 'ping'})) - } catch(e) { - console.error('PM2 is dead while doing process.send') - process.exit() - } - this.ping_timeout = setTimeout(() => { - console.error('PM2 is dead while waiting for a pong') - process.exit() - }, 2000) - }, 3000) - - // Systeminfo receive command - process.on('message', (cmd) => { - if (cmd == 'query') { - try { - var res = JSON.stringify({ - cmd: 'query:res', - data: this.report() - }) - process.send(res) - } catch (e) { - console.error('Could not retrieve system informations', e) - } - } - else if (cmd == 'pong') { - clearTimeout(this.ping_timeout) - } - }) - - } - - staticInformations() { - var getCPU = () => { - return sysinfo.cpu() - .then(data => { - this.infos.cpu = { - brand: data.manufacturer, - model: data.brand, - speed: data.speedmax, - cores: data.cores, - physicalCores: data.physicalCores - } - }) - } - - var getBaseboard = () => { - return sysinfo.system() - .then(data => { - this.infos.baseboard = { - manufacturer: data.manufacturer, - model: data.model, - version: data.version - } - }) - } - - var getOsInfo = () => { - return sysinfo.osInfo() - .then(data => { - this.infos.os = { - platform: data.platform, - distro: data.distro, - release: data.release, - codename: data.codename, - kernel: data.kernel, - arch: data.arch - } - }) - } - - var diskLayout = () => { - this.infos.storage.physical_disks = [] - - return sysinfo.diskLayout() - .then(disks => { - disks.forEach((disk) => { - this.infos.storage.physical_disks.push({ - device: disk.device, - type: disk.type, - name: disk.name, - interfaceType: disk.interfaceType, - vendor: disk.vendor - }) - }) - }) - } - - getBaseboard() - .then(getCPU) - .then(getOsInfo) - .then(diskLayout) - .catch(e => { - debug(`Error when trying to retrieve static informations`, e) - }) - } - - dockerSummary(cb = () => {}) { - sysinfo.dockerContainers('all') - .then(containers => { - var non_exited_containers = containers.filter(container => container.state != 'exited') - var new_containers = [] - - async.forEach(non_exited_containers, (container, next) => { - sysinfo.dockerContainerStats(container.id) - .then(stats => { - var meta = container - - stats[0].cpu_percent = (stats[0].cpu_percent).toFixed(1) - stats[0].mem_percent = (stats[0].mem_percent).toFixed(1) - stats[0].netIO.tx = (stats[0].netIO.tx / DEFAULT_CONVERSION).toFixed(1) - stats[0].netIO.rx = (stats[0].netIO.rx / DEFAULT_CONVERSION).toFixed(1) - - stats[0].blockIO.w = (stats[0].blockIO.w / DEFAULT_CONVERSION).toFixed(1) - stats[0].blockIO.r = (stats[0].blockIO.r / DEFAULT_CONVERSION).toFixed(1) - - meta.stats = Array.isArray(stats) == true ? stats[0] : null - new_containers.push(meta) - next() - }) - .catch(e => { - debug(e) - next() - }) - }, (err) => { - if (err) - debug(err) - this.infos.containers = new_containers.sort((a, b) => { - var textA = a.name.toUpperCase(); - var textB = b.name.toUpperCase(); - return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; - }) - return cb() - }) - }) - .catch(e => { - debug(e) - return cb() - }) - } - - servicesSummary() { - sysinfo.services('*') - .then(services => { - this.infos.services.running = services.filter(service => service.running === true) - this.infos.services.stopped = services.filter(service => service.running === false) - }) - .catch(e => { - debug(e) - }) - } - - processesSummary(cb) { - psList() - .then(processes => { - this.infos.processes.cpu_sorted = processes - .filter(a => !(a.cmd.includes('SystemInfo') && a.cmd.includes('PM2'))) - .sort((a, b) => b.cpu - a.cpu).slice(0, 5) - this.infos.processes.mem_sorted = processes - .filter(a => !(a.cmd.includes('SystemInfo') && a.cmd.includes('PM2'))) - .sort((a, b) => b.memory - a.memory).slice(0, 5) - return cb() - }) - .catch(e => { - console.error(`Error when retrieving process list`, e) - return cb() - }) - } - - graphicsInformations(cb) { - sysinfo.graphics() - .then(data => { - let cg1 = data.controllers[0] - if (!cg1) return cb() - - this.infos.graphics = { - model: cg1.model, - driverVersion: cg1.driverVersion, - memTotal: cg1.memoryTotal, - memUsed: cg1.memoryUsed, - temperature: cg1.temperatureGpu - } - return cb() - }) - .catch(e => { - console.error(`Error while retrieving graphics informations`) - console.error(e) - return cb() - }) - } - - cpuStatsWorker() { - var cpuTempCollection - - (cpuTempCollection = () => { - sysinfo.cpuTemperature() - .then(data => { - this.infos.cpu.temperature = data.main - setTimeout(cpuTempCollection.bind(this), 2000) - }) - .catch(e => { - setTimeout(cpuTempCollection.bind(this), 2000) - }) - })() - - function fetch () { - const startMeasure = computeUsage() - - setTimeout(_ => { - var endMeasure = computeUsage() - - var idleDifference = endMeasure.idle - startMeasure.idle - var totalDifference = endMeasure.total - startMeasure.total - - var percentageCPU = (10000 - Math.round(10000 * idleDifference / totalDifference)) / 100 - this.infos.cpu.usage = (percentageCPU).toFixed(1) - }, 100) - } - - function computeUsage () { - let totalIdle = 0 - let totalTick = 0 - const cpus = os.cpus() - - for (var i = 0, len = cpus.length; i < len; i++) { - var cpu = cpus[i] - for (let type in cpu.times) { - totalTick += cpu.times[type] - } - totalIdle += cpu.times.idle - } - - return { - idle: parseInt(totalIdle / cpus.length), - total: parseInt(totalTick / cpus.length) - } - } - - setInterval(fetch.bind(this), 1000) - fetch.bind(this)() - } - - memStats(cb) { - sysinfo.mem() - .then(data => { - this.infos.mem.total = (data.total / DEFAULT_CONVERSION).toFixed() - this.infos.mem.free = (data.free / DEFAULT_CONVERSION).toFixed() - this.infos.mem.active = (data.active / DEFAULT_CONVERSION).toFixed() - this.infos.mem.available = (data.available / DEFAULT_CONVERSION).toFixed() - return cb() - }) - .catch(e => { - console.error(`Error while retrieving memory info`) - console.error(e) - return cb() - }) - } - - networkConnectionsWorker() { - var retrieveConn - - (retrieveConn = () => { - sysinfo.networkConnections() - .then(conns => { - this.infos.connections = conns - .filter(conn => conn.localport != '443' && conn.peerport != '443') - .map(conn => `${conn.localaddress}:${conn.localport}-${conn.peeraddress}:${conn.peerport}-${conn.proc ? conn.proc : 'unknown'}`) - setTimeout(retrieveConn.bind(this), 10 * 1000) - }) - .catch(e => { - console.error(`Error while retrieving filesystems info`) - console.error(e) - setTimeout(retrieveConn.bind(this), 10 * 1000) - }) - })(); - } - - disksStatsWorker() { - var rx = 0 - var wx = 0 - var started = false - var fsSizeCollection, ioCollection - - (fsSizeCollection = () => { - sysinfo.fsSize() - .then(fss => { - var fse = fss.filter(fs => (fs.size / (1024 * 1024)) > 200) - this.infos.storage.filesystems = fse - setTimeout(fsSizeCollection.bind(this), 30 * 1000) - }) - .catch(e => { - console.error(`Error while retrieving filesystem infos (FSSIZE)`, e) - setTimeout(fsSizeCollection.bind(this), 10 * 1000) - }) - })(); - - (ioCollection = () => { - sysinfo.fsStats() - .then(fs_stats => { - var new_rx = fs_stats.rx - var new_wx = fs_stats.wx - - var read = ((new_rx - rx) / DEFAULT_CONVERSION).toFixed(3) - var write = ((new_wx - wx) / DEFAULT_CONVERSION).toFixed(3) - - if (started == true) { - this.infos.storage.io.read.add(parseFloat(read)) - this.infos.storage.io.write.add(parseFloat(write)) - } - - rx = new_rx - wx = new_wx - started = true - setTimeout(ioCollection.bind(this), 1000) - }) - .catch(e => { - console.error(`Error while getting network statistics`, e) - setTimeout(ioCollection.bind(this), 1000) - }) - })(); - } - - fdStatsWorker() { - var getFDOpened = () => { - fs.readFile('/proc/sys/fs/file-nr', (err, out) => { - if (err) return - const output = out.toString().trim() - const parsed = output.split('\t') - if (parsed.length !== 3) return - this.infos.fd.opened = parseInt(parsed[0]) - this.infos.fd.max = parseInt(parsed[2]) - }) - } - - setInterval(() => { - getFDOpened() - }, 20 * 1000) - - getFDOpened() - } - - networkStatsWorker() { - var latencyCollection, networkStatsCollection - - // (latencyCollection = () => { - // sysinfo.inetLatency() - // .then(latency => { - // this.infos.network.latency.add(latency) - // setTimeout(latencyCollection.bind(this), 2000) - // }) - // .catch(e => { - // debug(e) - // setTimeout(latencyCollection.bind(this), 2000) - // }) - // })() - - sysinfo.networkInterfaceDefault((net_interface) => { - var started = false - var rx = 0 - var tx = 0 - var rx_e = 0 - var tx_e = 0 - var rx_d = 0 - var tx_d = 0; - - (networkStatsCollection = () => { - sysinfo.networkStats(net_interface) - .then((net) => { - var new_rx = (net[0].rx_bytes - rx) / DEFAULT_CONVERSION - var new_tx = (net[0].tx_bytes - tx) / DEFAULT_CONVERSION - rx = net[0].rx_bytes - tx = net[0].tx_bytes - - var new_rx_e = (net[0].rx_errors - rx_e) / DEFAULT_CONVERSION - var new_tx_e = (net[0].tx_errors - tx_e) / DEFAULT_CONVERSION - rx_e = net[0].rx_errors - tx_e = net[0].tx_errors - - var new_rx_d = (net[0].rx_dropped - rx_d) / DEFAULT_CONVERSION - var new_tx_d = (net[0].tx_dropped - tx_d) / DEFAULT_CONVERSION - rx_d = net[0].rx_dropped - tx_d = net[0].tx_dropped - - if (started == true) { - this.infos.network.rx_5.add(new_rx) - this.infos.network.tx_5.add(new_tx) - this.infos.network.rx_errors_60.add(new_rx_e) - this.infos.network.tx_errors_60.add(new_tx_e) - this.infos.network.rx_dropped_60.add(new_rx_d) - this.infos.network.tx_dropped_60.add(new_tx_d) - } - started = true - setTimeout(networkStatsCollection.bind(this), 1000) - }) - .catch(e => { - console.error(`Error on retrieving network stats`, e) - setTimeout(networkStatsCollection.bind(this), 900) - }) - })() - }) - - } -} - -module.exports = SystemInfo - -if (require.main === module) { - var sys = new SystemInfo() - sys.startCollection() -} diff --git a/lib/Sysinfo/fastlist.exe b/lib/Sysinfo/fastlist.exe deleted file mode 100644 index ca719736..00000000 Binary files a/lib/Sysinfo/fastlist.exe and /dev/null differ diff --git a/lib/Sysinfo/psList.js b/lib/Sysinfo/psList.js deleted file mode 100644 index 2008ab2e..00000000 --- a/lib/Sysinfo/psList.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; -const util = require('util'); -const path = require('path'); -const childProcess = require('child_process'); - -const TEN_MEGABYTES = 1000 * 1000 * 10; -const execFile = util.promisify(childProcess.execFile); - -const windows = async () => { - // Source: https://github.com/MarkTiedemann/fastlist - const bin = path.join(__dirname, 'fastlist.exe'); - - const {stdout} = await execFile(bin, {maxBuffer: TEN_MEGABYTES}); - - return stdout - .trim() - .split('\r\n') - .map(line => line.split('\t')) - .map(([name, pid, ppid]) => ({ - name, - pid: Number.parseInt(pid, 10), - ppid: Number.parseInt(ppid, 10) - })); -}; - -const main = async (options = {}) => { - const flags = (options.all === false ? '' : 'a') + 'wwxo'; - const ret = {}; - - await Promise.all(['comm', 'args', 'ppid', 'uid', '%cpu', '%mem'].map(async cmd => { - const {stdout} = await execFile('ps', [flags, `pid,${cmd}`], {maxBuffer: TEN_MEGABYTES}); - - for (let line of stdout.trim().split('\n').slice(1)) { - line = line.trim(); - const [pid] = line.split(' ', 1); - const val = line.slice(pid.length + 1).trim(); - - if (ret[pid] === undefined) { - ret[pid] = {}; - } - - ret[pid][cmd] = val; - } - })); - - // Filter out inconsistencies as there might be race - // issues due to differences in `ps` between the spawns - return Object.entries(ret) - .filter(([, value]) => value.comm && value.args && value.ppid && value.uid && value['%cpu'] && value['%mem']) - .map(([key, value]) => ({ - pid: Number.parseInt(key, 10), - name: path.basename(value.comm), - cmd: value.args, - ppid: Number.parseInt(value.ppid, 10), - uid: Number.parseInt(value.uid, 10), - cpu: Number.parseFloat(value['%cpu']), - memory: Number.parseFloat(value['%mem']) - })); -}; - -module.exports = process.platform === 'win32' ? windows : main; -// TODO: remove this in the next major version -module.exports.default = module.exports; diff --git a/package.json b/package.json index b24b7eaf..04fb6d25 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "pm2", "preferGlobal": true, - "version": "4.5.1", + "version": "5.0.0", "engines": { - "node": ">=8.10.0" + "node": ">=10.0.0" }, "directories": { "bin": "./bin", @@ -201,9 +201,6 @@ "mocha": "^7.1.0", "should": "^13" }, - "optionalDependencies": { - "systeminformation": "^4.32" - }, "bugs": { "url": "https://github.com/Unitech/pm2/issues" },