1426 lines
51 KiB
JavaScript
1426 lines
51 KiB
JavaScript
'use strict';
|
|
// @ts-check
|
|
// ==================================================================================
|
|
// processes.js
|
|
// ----------------------------------------------------------------------------------
|
|
// Description: System Information - library
|
|
// for Node.js
|
|
// Copyright: (c) 2014 - 2026
|
|
// Author: Sebastian Hildebrandt
|
|
// ----------------------------------------------------------------------------------
|
|
// License: MIT
|
|
// ==================================================================================
|
|
// 10. Processes
|
|
// ----------------------------------------------------------------------------------
|
|
|
|
const os = require('os');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const exec = require('child_process').exec;
|
|
const execSync = require('child_process').execSync;
|
|
|
|
const util = require('./util');
|
|
|
|
let _platform = process.platform;
|
|
|
|
const _linux = _platform === 'linux' || _platform === 'android';
|
|
const _darwin = _platform === 'darwin';
|
|
const _windows = _platform === 'win32';
|
|
const _freebsd = _platform === 'freebsd';
|
|
const _openbsd = _platform === 'openbsd';
|
|
const _netbsd = _platform === 'netbsd';
|
|
const _sunos = _platform === 'sunos';
|
|
|
|
const _processes_cpu = {
|
|
all: 0,
|
|
all_utime: 0,
|
|
all_stime: 0,
|
|
list: {},
|
|
ms: 0,
|
|
result: {}
|
|
};
|
|
const _services_cpu = {
|
|
all: 0,
|
|
all_utime: 0,
|
|
all_stime: 0,
|
|
list: {},
|
|
ms: 0,
|
|
result: {}
|
|
};
|
|
const _process_cpu = {
|
|
all: 0,
|
|
all_utime: 0,
|
|
all_stime: 0,
|
|
list: {},
|
|
ms: 0,
|
|
result: {}
|
|
};
|
|
|
|
const _winStatusValues = {
|
|
0: 'unknown',
|
|
1: 'other',
|
|
2: 'ready',
|
|
3: 'running',
|
|
4: 'blocked',
|
|
5: 'suspended blocked',
|
|
6: 'suspended ready',
|
|
7: 'terminated',
|
|
8: 'stopped',
|
|
9: 'growing'
|
|
};
|
|
|
|
function parseTimeUnix(time) {
|
|
let result = time;
|
|
let parts = time.replace(/ +/g, ' ').split(' ');
|
|
if (parts.length === 5) {
|
|
result = parts[4] + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(parts[1].toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + parts[2]).slice(-2) + ' ' + parts[3];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function parseElapsedTime(etime) {
|
|
let current = new Date();
|
|
current = new Date(current.getTime() - current.getTimezoneOffset() * 60000);
|
|
|
|
const elapsed = etime.split('-');
|
|
|
|
const timeIndex = elapsed.length - 1;
|
|
const days = timeIndex > 0 ? parseInt(elapsed[timeIndex - 1]) : 0;
|
|
|
|
const timeStr = elapsed[timeIndex].split(':');
|
|
const hours = timeStr.length === 3 ? parseInt(timeStr[0] || 0) : 0;
|
|
const mins = parseInt(timeStr[timeStr.length === 3 ? 1 : 0] || 0);
|
|
const secs = parseInt(timeStr[timeStr.length === 3 ? 2 : 1] || 0);
|
|
const ms = (((days * 24 + hours) * 60 + mins) * 60 + secs) * 1000;
|
|
|
|
let res = new Date(current.getTime());
|
|
let result = res.toISOString().substring(0, 10) + ' ' + res.toISOString().substring(11, 19);
|
|
try {
|
|
res = new Date(current.getTime() - ms);
|
|
result = res.toISOString().substring(0, 10) + ' ' + res.toISOString().substring(11, 19);
|
|
} catch (e) {
|
|
util.noop();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// --------------------------
|
|
// PS - services
|
|
// pass a comma separated string with services to check (mysql, apache, postgresql, ...)
|
|
// this function gives an array back, if the services are running.
|
|
|
|
function services(srv, callback) {
|
|
// fallback - if only callback is given
|
|
if (util.isFunction(srv) && !callback) {
|
|
callback = srv;
|
|
srv = '';
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
process.nextTick(() => {
|
|
if (typeof srv !== 'string') {
|
|
if (callback) {
|
|
callback([]);
|
|
}
|
|
return resolve([]);
|
|
}
|
|
|
|
if (srv) {
|
|
let srvString = '';
|
|
try {
|
|
srvString.__proto__.toLowerCase = util.stringToLower;
|
|
srvString.__proto__.replace = util.stringReplace;
|
|
srvString.__proto__.toString = util.stringToString;
|
|
srvString.__proto__.substr = util.stringSubstr;
|
|
srvString.__proto__.substring = util.stringSubstring;
|
|
srvString.__proto__.trim = util.stringTrim;
|
|
srvString.__proto__.startsWith = util.stringStartWith;
|
|
} catch (e) {
|
|
Object.setPrototypeOf(srvString, util.stringObj);
|
|
}
|
|
|
|
const s = util.sanitizeShellString(srv);
|
|
const l = util.mathMin(s.length, 2000);
|
|
for (let i = 0; i <= l; i++) {
|
|
if (s[i] !== undefined) {
|
|
srvString = srvString + s[i];
|
|
}
|
|
}
|
|
|
|
srvString = srvString.trim().toLowerCase().replace(/, /g, '|').replace(/,+/g, '|');
|
|
if (srvString === '') {
|
|
srvString = '*';
|
|
}
|
|
if (util.isPrototypePolluted() && srvString !== '*') {
|
|
srvString = '------';
|
|
}
|
|
let srvs = srvString.split('|');
|
|
let result = [];
|
|
let dataSrv = [];
|
|
|
|
if (_linux || _freebsd || _openbsd || _netbsd || _darwin) {
|
|
if ((_linux || _freebsd || _openbsd || _netbsd) && srvString === '*') {
|
|
try {
|
|
const tmpsrv = execSync('systemctl --all --type=service --no-legend 2> /dev/null', util.execOptsLinux).toString().split('\n');
|
|
srvs = [];
|
|
for (const s of tmpsrv) {
|
|
const name = s.split('.service')[0];
|
|
if (name && s.indexOf(' not-found ') === -1) {
|
|
srvs.push(name.trim());
|
|
}
|
|
}
|
|
srvString = srvs.join('|');
|
|
} catch (d) {
|
|
try {
|
|
srvString = '';
|
|
const tmpsrv = execSync('service --status-all 2> /dev/null', util.execOptsLinux).toString().split('\n');
|
|
for (const s of tmpsrv) {
|
|
const parts = s.split(']');
|
|
if (parts.length === 2) {
|
|
srvString += (srvString !== '' ? '|' : '') + parts[1].trim();
|
|
}
|
|
}
|
|
srvs = srvString.split('|');
|
|
} catch (e) {
|
|
try {
|
|
const srvStr = execSync('ls /etc/init.d/ -m 2> /dev/null', util.execOptsLinux).toString().split('\n').join('');
|
|
srvString = '';
|
|
if (srvStr) {
|
|
const tmpsrv = srvStr.split(',');
|
|
for (const s of tmpsrv) {
|
|
const name = s.trim();
|
|
if (name) {
|
|
srvString += (srvString !== '' ? '|' : '') + name;
|
|
}
|
|
}
|
|
srvs = srvString.split('|');
|
|
}
|
|
} catch (f) {
|
|
srvString = '';
|
|
srvs = [];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (_darwin && srvString === '*') {
|
|
// service enumeration not yet suported on mac OS
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
let args = _darwin ? ['-caxo', 'pcpu,pmem,pid,command'] : ['-axo', 'pcpu,pmem,pid,command'];
|
|
if (srvString !== '' && srvs.length > 0) {
|
|
util.execSafe('ps', args).then((stdout) => {
|
|
if (stdout) {
|
|
let lines = stdout.replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
|
|
srvs.forEach(function (srv) {
|
|
let ps;
|
|
if (_darwin) {
|
|
ps = lines.filter(function (e) {
|
|
return e.toLowerCase().indexOf(srv) !== -1;
|
|
});
|
|
} else {
|
|
ps = lines.filter(function (e) {
|
|
return (
|
|
e.toLowerCase().indexOf(' ' + srv.toLowerCase() + ':') !== -1 ||
|
|
e.toLowerCase().indexOf('(' + srv.toLowerCase() + ' ') !== -1 ||
|
|
e.toLowerCase().indexOf('(' + srv.toLowerCase() + ')') !== -1 ||
|
|
e.toLowerCase().indexOf(' ' + srv.toLowerCase().replace(/[0-9.]/g, '') + ':') !== -1 ||
|
|
e.toLowerCase().indexOf('/' + srv.toLowerCase()) !== -1
|
|
);
|
|
});
|
|
}
|
|
const pids = [];
|
|
for (const p of ps) {
|
|
const pid = p.trim().split(' ')[2];
|
|
if (pid) {
|
|
pids.push(parseInt(pid, 10));
|
|
}
|
|
}
|
|
result.push({
|
|
name: srv,
|
|
running: ps.length > 0,
|
|
startmode: '',
|
|
pids: pids,
|
|
cpu: parseFloat(
|
|
ps
|
|
.reduce(function (pv, cv) {
|
|
return pv + parseFloat(cv.trim().split(' ')[0]);
|
|
}, 0)
|
|
.toFixed(2)
|
|
),
|
|
mem: parseFloat(
|
|
ps
|
|
.reduce(function (pv, cv) {
|
|
return pv + parseFloat(cv.trim().split(' ')[1]);
|
|
}, 0)
|
|
.toFixed(2)
|
|
)
|
|
});
|
|
});
|
|
if (_linux) {
|
|
// calc process_cpu - ps is not accurate in linux!
|
|
let cmd = 'cat /proc/stat | grep "cpu "';
|
|
for (let i in result) {
|
|
for (let j in result[i].pids) {
|
|
cmd += ';cat /proc/' + result[i].pids[j] + '/stat';
|
|
}
|
|
}
|
|
exec(cmd, { maxBuffer: 1024 * 102400 }, function (error, stdout) {
|
|
let curr_processes = stdout.toString().split('\n');
|
|
|
|
// first line (all - /proc/stat)
|
|
let all = parseProcStat(curr_processes.shift());
|
|
|
|
// process
|
|
let list_new = {};
|
|
let resultProcess = {};
|
|
curr_processes.forEach((element) => {
|
|
resultProcess = calcProcStatLinux(element, all, _services_cpu);
|
|
|
|
if (resultProcess.pid) {
|
|
let listPos = -1;
|
|
for (let i in result) {
|
|
for (let j in result[i].pids) {
|
|
if (parseInt(result[i].pids[j]) === parseInt(resultProcess.pid)) {
|
|
listPos = i;
|
|
}
|
|
}
|
|
}
|
|
if (listPos >= 0) {
|
|
result[listPos].cpu += resultProcess.cpuu + resultProcess.cpus;
|
|
}
|
|
|
|
// save new values
|
|
list_new[resultProcess.pid] = {
|
|
cpuu: resultProcess.cpuu,
|
|
cpus: resultProcess.cpus,
|
|
utime: resultProcess.utime,
|
|
stime: resultProcess.stime,
|
|
cutime: resultProcess.cutime,
|
|
cstime: resultProcess.cstime
|
|
};
|
|
}
|
|
});
|
|
|
|
// store old values
|
|
_services_cpu.all = all;
|
|
_services_cpu.list = Object.assign({}, list_new);
|
|
_services_cpu.ms = Date.now() - _services_cpu.ms;
|
|
_services_cpu.result = Object.assign({}, result);
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
});
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
} else {
|
|
args = ['-o', 'comm'];
|
|
util.execSafe('ps', args).then((stdout) => {
|
|
if (stdout) {
|
|
let lines = stdout.replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
|
|
srvs.forEach(function (srv) {
|
|
let ps = lines.filter(function (e) {
|
|
return e.indexOf(srv) !== -1;
|
|
});
|
|
result.push({
|
|
name: srv,
|
|
running: ps.length > 0,
|
|
startmode: '',
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
});
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
} else {
|
|
srvs.forEach(function (srv) {
|
|
result.push({
|
|
name: srv,
|
|
running: false,
|
|
startmode: '',
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
});
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
}
|
|
if (_windows) {
|
|
try {
|
|
let wincommand = 'Get-CimInstance Win32_Service';
|
|
if (srvs[0] !== '*') {
|
|
wincommand += ' -Filter "';
|
|
srvs.forEach((srv) => {
|
|
wincommand += `Name='${srv}' or `;
|
|
});
|
|
wincommand = `${wincommand.slice(0, -4)}"`;
|
|
}
|
|
wincommand += ' | select Name,Caption,Started,StartMode,ProcessId | fl';
|
|
util.powerShell(wincommand).then((stdout, error) => {
|
|
if (!error) {
|
|
let serviceSections = stdout.split(/\n\s*\n/);
|
|
serviceSections.forEach((element) => {
|
|
if (element.trim() !== '') {
|
|
let lines = element.trim().split('\r\n');
|
|
let srvName = util.getValue(lines, 'Name', ':', true).toLowerCase();
|
|
let srvCaption = util.getValue(lines, 'Caption', ':', true).toLowerCase();
|
|
let started = util.getValue(lines, 'Started', ':', true);
|
|
let startMode = util.getValue(lines, 'StartMode', ':', true);
|
|
let pid = util.getValue(lines, 'ProcessId', ':', true);
|
|
if (srvString === '*' || srvs.indexOf(srvName) >= 0 || srvs.indexOf(srvCaption) >= 0) {
|
|
result.push({
|
|
name: srvName,
|
|
running: started.toLowerCase() === 'true',
|
|
startmode: startMode,
|
|
pids: [pid],
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
dataSrv.push(srvName);
|
|
dataSrv.push(srvCaption);
|
|
}
|
|
}
|
|
});
|
|
|
|
if (srvString !== '*') {
|
|
const srvsMissing = srvs.filter((e) => dataSrv.indexOf(e) === -1);
|
|
srvsMissing.forEach((srvName) => {
|
|
result.push({
|
|
name: srvName,
|
|
running: false,
|
|
startmode: '',
|
|
pids: [],
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
});
|
|
}
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
} else {
|
|
srvs.forEach((srvName) => {
|
|
result.push({
|
|
name: srvName,
|
|
running: false,
|
|
startmode: '',
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
});
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
});
|
|
} catch {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
}
|
|
} else {
|
|
if (callback) {
|
|
callback([]);
|
|
}
|
|
resolve([]);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
exports.services = services;
|
|
|
|
function parseProcStat(line) {
|
|
const parts = line.replace(/ +/g, ' ').split(' ');
|
|
const user = parts.length >= 2 ? parseInt(parts[1]) : 0;
|
|
const nice = parts.length >= 3 ? parseInt(parts[2]) : 0;
|
|
const system = parts.length >= 4 ? parseInt(parts[3]) : 0;
|
|
const idle = parts.length >= 5 ? parseInt(parts[4]) : 0;
|
|
const iowait = parts.length >= 6 ? parseInt(parts[5]) : 0;
|
|
const irq = parts.length >= 7 ? parseInt(parts[6]) : 0;
|
|
const softirq = parts.length >= 8 ? parseInt(parts[7]) : 0;
|
|
const steal = parts.length >= 9 ? parseInt(parts[8]) : 0;
|
|
const guest = parts.length >= 10 ? parseInt(parts[9]) : 0;
|
|
const guest_nice = parts.length >= 11 ? parseInt(parts[10]) : 0;
|
|
return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
|
|
}
|
|
|
|
function calcProcStatLinux(line, all, _cpu_old) {
|
|
let statparts = line.replace(/ +/g, ' ').split(')');
|
|
if (statparts.length >= 2) {
|
|
let parts = statparts[1].split(' ');
|
|
if (parts.length >= 16) {
|
|
let pid = parseInt(statparts[0].split(' ')[0]);
|
|
let utime = parseInt(parts[12]);
|
|
let stime = parseInt(parts[13]);
|
|
let cutime = parseInt(parts[14]);
|
|
let cstime = parseInt(parts[15]);
|
|
|
|
// calc
|
|
let cpuu = 0;
|
|
let cpus = 0;
|
|
if (_cpu_old.all > 0 && _cpu_old.list[pid]) {
|
|
cpuu = ((utime + cutime - _cpu_old.list[pid].utime - _cpu_old.list[pid].cutime) / (all - _cpu_old.all)) * 100; // user
|
|
cpus = ((stime + cstime - _cpu_old.list[pid].stime - _cpu_old.list[pid].cstime) / (all - _cpu_old.all)) * 100; // system
|
|
} else {
|
|
cpuu = ((utime + cutime) / all) * 100; // user
|
|
cpus = ((stime + cstime) / all) * 100; // system
|
|
}
|
|
return {
|
|
pid: pid,
|
|
utime: utime,
|
|
stime: stime,
|
|
cutime: cutime,
|
|
cstime: cstime,
|
|
cpuu: cpuu,
|
|
cpus: cpus
|
|
};
|
|
} else {
|
|
return {
|
|
pid: 0,
|
|
utime: 0,
|
|
stime: 0,
|
|
cutime: 0,
|
|
cstime: 0,
|
|
cpuu: 0,
|
|
cpus: 0
|
|
};
|
|
}
|
|
} else {
|
|
return {
|
|
pid: 0,
|
|
utime: 0,
|
|
stime: 0,
|
|
cutime: 0,
|
|
cstime: 0,
|
|
cpuu: 0,
|
|
cpus: 0
|
|
};
|
|
}
|
|
}
|
|
|
|
function calcProcStatWin(procStat, all, _cpu_old) {
|
|
// calc
|
|
let cpuu = 0;
|
|
let cpus = 0;
|
|
if (_cpu_old.all > 0 && _cpu_old.list[procStat.pid]) {
|
|
cpuu = ((procStat.utime - _cpu_old.list[procStat.pid].utime) / (all - _cpu_old.all)) * 100; // user
|
|
cpus = ((procStat.stime - _cpu_old.list[procStat.pid].stime) / (all - _cpu_old.all)) * 100; // system
|
|
} else {
|
|
cpuu = (procStat.utime / all) * 100; // user
|
|
cpus = (procStat.stime / all) * 100; // system
|
|
}
|
|
return {
|
|
pid: procStat.pid,
|
|
utime: procStat.utime,
|
|
stime: procStat.stime,
|
|
cpuu: cpuu > 0 ? cpuu : 0,
|
|
cpus: cpus > 0 ? cpus : 0
|
|
};
|
|
}
|
|
|
|
// --------------------------
|
|
// running processes
|
|
|
|
function processes(callback) {
|
|
let parsedhead = [];
|
|
|
|
function getName(command) {
|
|
command = command || '';
|
|
let result = command.split(' ')[0];
|
|
if (result.substr(-1) === ':') {
|
|
result = result.substr(0, result.length - 1);
|
|
}
|
|
if (result.substr(0, 1) !== '[') {
|
|
let parts = result.split('/');
|
|
if (isNaN(parseInt(parts[parts.length - 1]))) {
|
|
result = parts[parts.length - 1];
|
|
} else {
|
|
result = parts[0];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function parseLine(line) {
|
|
let offset = 0;
|
|
let offset2 = 0;
|
|
|
|
function checkColumn(i) {
|
|
offset = offset2;
|
|
if (parsedhead[i]) {
|
|
offset2 = line.substring(parsedhead[i].to + offset, 10000).indexOf(' ');
|
|
} else {
|
|
offset2 = 10000;
|
|
}
|
|
}
|
|
|
|
checkColumn(0);
|
|
const pid = parseInt(line.substring(parsedhead[0].from + offset, parsedhead[0].to + offset2));
|
|
checkColumn(1);
|
|
const ppid = parseInt(line.substring(parsedhead[1].from + offset, parsedhead[1].to + offset2));
|
|
checkColumn(2);
|
|
const cpu = parseFloat(line.substring(parsedhead[2].from + offset, parsedhead[2].to + offset2).replace(/,/g, '.'));
|
|
checkColumn(3);
|
|
const mem = parseFloat(line.substring(parsedhead[3].from + offset, parsedhead[3].to + offset2).replace(/,/g, '.'));
|
|
checkColumn(4);
|
|
const priority = parseInt(line.substring(parsedhead[4].from + offset, parsedhead[4].to + offset2));
|
|
checkColumn(5);
|
|
const vsz = parseInt(line.substring(parsedhead[5].from + offset, parsedhead[5].to + offset2));
|
|
checkColumn(6);
|
|
const rss = parseInt(line.substring(parsedhead[6].from + offset, parsedhead[6].to + offset2));
|
|
checkColumn(7);
|
|
const nice = parseInt(line.substring(parsedhead[7].from + offset, parsedhead[7].to + offset2)) || 0;
|
|
checkColumn(8);
|
|
const started = !_sunos
|
|
? parseElapsedTime(line.substring(parsedhead[8].from + offset, parsedhead[8].to + offset2).trim())
|
|
: parseTimeUnix(line.substring(parsedhead[8].from + offset, parsedhead[8].to + offset2).trim());
|
|
checkColumn(9);
|
|
let state = line.substring(parsedhead[9].from + offset, parsedhead[9].to + offset2).trim();
|
|
state =
|
|
state[0] === 'R'
|
|
? 'running'
|
|
: state[0] === 'S'
|
|
? 'sleeping'
|
|
: state[0] === 'T'
|
|
? 'stopped'
|
|
: state[0] === 'W'
|
|
? 'paging'
|
|
: state[0] === 'X'
|
|
? 'dead'
|
|
: state[0] === 'Z'
|
|
? 'zombie'
|
|
: state[0] === 'D' || state[0] === 'U'
|
|
? 'blocked'
|
|
: 'unknown';
|
|
checkColumn(10);
|
|
let tty = line.substring(parsedhead[10].from + offset, parsedhead[10].to + offset2).trim();
|
|
if (tty === '?' || tty === '??') {
|
|
tty = '';
|
|
}
|
|
checkColumn(11);
|
|
const user = line.substring(parsedhead[11].from + offset, parsedhead[11].to + offset2).trim();
|
|
checkColumn(12);
|
|
let cmdPath = '';
|
|
let command = '';
|
|
let params = '';
|
|
let fullcommand = line.substring(parsedhead[12].from + offset, parsedhead[12].to + offset2).trim();
|
|
if (fullcommand.substr(fullcommand.length - 1) === ']') {
|
|
fullcommand = fullcommand.slice(0, -1);
|
|
}
|
|
if (fullcommand.substr(0, 1) === '[') {
|
|
command = fullcommand.substring(1);
|
|
} else {
|
|
const p1 = fullcommand.indexOf('(');
|
|
const p2 = fullcommand.indexOf(')');
|
|
const p3 = fullcommand.indexOf('/');
|
|
const p4 = fullcommand.indexOf(':');
|
|
if (p1 < p2 && p1 < p3 && p3 < p2) {
|
|
command = fullcommand.split(' ')[0];
|
|
command = command.replace(/:/g, '');
|
|
} else {
|
|
if (p4 > 0 && (p3 === -1 || p3 > 3)) {
|
|
command = fullcommand.split(' ')[0];
|
|
command = command.replace(/:/g, '');
|
|
} else {
|
|
// try to figure out where parameter starts
|
|
let firstParamPos = fullcommand.indexOf(' -');
|
|
let firstParamPathPos = fullcommand.indexOf(' /');
|
|
firstParamPos = firstParamPos >= 0 ? firstParamPos : 10000;
|
|
firstParamPathPos = firstParamPathPos >= 0 ? firstParamPathPos : 10000;
|
|
const firstPos = Math.min(firstParamPos, firstParamPathPos);
|
|
let tmpCommand = fullcommand.substr(0, firstPos);
|
|
const tmpParams = fullcommand.substr(firstPos);
|
|
const lastSlashPos = tmpCommand.lastIndexOf('/');
|
|
if (lastSlashPos >= 0) {
|
|
cmdPath = tmpCommand.substr(0, lastSlashPos);
|
|
tmpCommand = tmpCommand.substr(lastSlashPos + 1);
|
|
}
|
|
|
|
if (firstPos === 10000 && tmpCommand.indexOf(' ') > -1) {
|
|
const parts = tmpCommand.split(' ');
|
|
if (fs.existsSync(path.join(cmdPath, parts[0]))) {
|
|
command = parts.shift();
|
|
params = (parts.join(' ') + ' ' + tmpParams).trim();
|
|
} else {
|
|
command = tmpCommand.trim();
|
|
params = tmpParams.trim();
|
|
}
|
|
} else {
|
|
command = tmpCommand.trim();
|
|
params = tmpParams.trim();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
pid: pid,
|
|
parentPid: ppid,
|
|
name: _linux ? getName(command) : command,
|
|
cpu: cpu,
|
|
cpuu: 0,
|
|
cpus: 0,
|
|
mem: mem,
|
|
priority: priority,
|
|
memVsz: vsz,
|
|
memRss: rss,
|
|
nice: nice,
|
|
started: started,
|
|
state: state,
|
|
tty: tty,
|
|
user: user,
|
|
command: command,
|
|
params: params,
|
|
path: cmdPath
|
|
};
|
|
}
|
|
|
|
function parseProcesses(lines) {
|
|
let result = [];
|
|
if (lines.length > 1) {
|
|
let head = lines[0];
|
|
parsedhead = util.parseHead(head, 8);
|
|
lines.shift();
|
|
lines.forEach((line) => {
|
|
if (line.trim() !== '') {
|
|
result.push(parseLine(line));
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
function parseProcesses2(lines) {
|
|
function formatDateTime(time) {
|
|
const month = ('0' + (time.getMonth() + 1).toString()).slice(-2);
|
|
const year = time.getFullYear().toString();
|
|
const day = ('0' + time.getDate().toString()).slice(-2);
|
|
const hours = ('0' + time.getHours().toString()).slice(-2);
|
|
const mins = ('0' + time.getMinutes().toString()).slice(-2);
|
|
const secs = ('0' + time.getSeconds().toString()).slice(-2);
|
|
|
|
return year + '-' + month + '-' + day + ' ' + hours + ':' + mins + ':' + secs;
|
|
}
|
|
|
|
function parseElapsed(etime) {
|
|
let started = '';
|
|
if (etime.indexOf('d') >= 0) {
|
|
const elapsed_parts = etime.split('d');
|
|
started = formatDateTime(new Date(Date.now() - (elapsed_parts[0] * 24 + elapsed_parts[1] * 1) * 60 * 60 * 1000));
|
|
} else if (etime.indexOf('h') >= 0) {
|
|
const elapsed_parts = etime.split('h');
|
|
started = formatDateTime(new Date(Date.now() - (elapsed_parts[0] * 60 + elapsed_parts[1] * 1) * 60 * 1000));
|
|
} else if (etime.indexOf(':') >= 0) {
|
|
const elapsed_parts = etime.split(':');
|
|
started = formatDateTime(new Date(Date.now() - (elapsed_parts.length > 1 ? (elapsed_parts[0] * 60 + elapsed_parts[1]) * 1000 : elapsed_parts[0] * 1000)));
|
|
}
|
|
return started;
|
|
}
|
|
|
|
let result = [];
|
|
lines.forEach((line) => {
|
|
if (line.trim() !== '') {
|
|
line = line.trim().replace(/ +/g, ' ').replace(/,+/g, '.');
|
|
const parts = line.split(' ');
|
|
const command = parts.slice(9).join(' ');
|
|
const pmem = parseFloat(((1.0 * parseInt(parts[3]) * 1024) / os.totalmem()).toFixed(1));
|
|
const started = parseElapsed(parts[5]);
|
|
|
|
result.push({
|
|
pid: parseInt(parts[0]),
|
|
parentPid: parseInt(parts[1]),
|
|
name: getName(command),
|
|
cpu: 0,
|
|
cpuu: 0,
|
|
cpus: 0,
|
|
mem: pmem,
|
|
priority: 0,
|
|
memVsz: parseInt(parts[2]),
|
|
memRss: parseInt(parts[3]),
|
|
nice: parseInt(parts[4]),
|
|
started: started,
|
|
state:
|
|
parts[6] === 'R'
|
|
? 'running'
|
|
: parts[6] === 'S'
|
|
? 'sleeping'
|
|
: parts[6] === 'T'
|
|
? 'stopped'
|
|
: parts[6] === 'W'
|
|
? 'paging'
|
|
: parts[6] === 'X'
|
|
? 'dead'
|
|
: parts[6] === 'Z'
|
|
? 'zombie'
|
|
: parts[6] === 'D' || parts[6] === 'U'
|
|
? 'blocked'
|
|
: 'unknown',
|
|
tty: parts[7],
|
|
user: parts[8],
|
|
command: command
|
|
});
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
process.nextTick(() => {
|
|
let result = {
|
|
all: 0,
|
|
running: 0,
|
|
blocked: 0,
|
|
sleeping: 0,
|
|
unknown: 0,
|
|
list: []
|
|
};
|
|
|
|
let cmd = '';
|
|
|
|
if ((_processes_cpu.ms && Date.now() - _processes_cpu.ms >= 500) || _processes_cpu.ms === 0) {
|
|
if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
|
|
if (_linux) {
|
|
cmd = 'export LC_ALL=C; ps -axo pid:11,ppid:11,pcpu:6,pmem:6,pri:5,vsz:11,rss:11,ni:5,etime:30,state:5,tty:15,user:20,command; unset LC_ALL';
|
|
}
|
|
if (_freebsd || _openbsd || _netbsd) {
|
|
cmd = 'export LC_ALL=C; ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,ni,etime,state,tty,user,command; unset LC_ALL';
|
|
}
|
|
if (_darwin) {
|
|
cmd = 'ps -axo pid,ppid,pcpu,pmem,pri,vsz=temp_title_1,rss=temp_title_2,nice,etime=temp_title_3,state,tty,user,command -r';
|
|
}
|
|
if (_sunos) {
|
|
cmd = 'ps -Ao pid,ppid,pcpu,pmem,pri,vsz,rss,nice,stime,s,tty,user,comm';
|
|
}
|
|
try {
|
|
exec(cmd, { maxBuffer: 1024 * 102400 }, (error, stdout) => {
|
|
if (!error && stdout.toString().trim()) {
|
|
result.list = parseProcesses(stdout.toString().split('\n')).slice();
|
|
result.all = result.list.length;
|
|
result.running = result.list.filter((e) => {
|
|
return e.state === 'running';
|
|
}).length;
|
|
result.blocked = result.list.filter((e) => {
|
|
return e.state === 'blocked';
|
|
}).length;
|
|
result.sleeping = result.list.filter((e) => {
|
|
return e.state === 'sleeping';
|
|
}).length;
|
|
|
|
if (_linux) {
|
|
// calc process_cpu - ps is not accurate in linux!
|
|
cmd = 'cat /proc/stat | grep "cpu "';
|
|
result.list.forEach((element) => {
|
|
cmd += ';cat /proc/' + element.pid + '/stat';
|
|
});
|
|
exec(cmd, { maxBuffer: 1024 * 102400 }, (error, stdout) => {
|
|
let curr_processes = stdout.toString().split('\n');
|
|
|
|
// first line (all - /proc/stat)
|
|
let all = parseProcStat(curr_processes.shift());
|
|
|
|
// process
|
|
let list_new = {};
|
|
let resultProcess = {};
|
|
curr_processes.forEach((element) => {
|
|
resultProcess = calcProcStatLinux(element, all, _processes_cpu);
|
|
|
|
if (resultProcess.pid) {
|
|
// store pcpu in outer array
|
|
let listPos = result.list
|
|
.map((e) => {
|
|
return e.pid;
|
|
})
|
|
.indexOf(resultProcess.pid);
|
|
if (listPos >= 0) {
|
|
result.list[listPos].cpu = resultProcess.cpuu + resultProcess.cpus;
|
|
result.list[listPos].cpuu = resultProcess.cpuu;
|
|
result.list[listPos].cpus = resultProcess.cpus;
|
|
}
|
|
|
|
// save new values
|
|
list_new[resultProcess.pid] = {
|
|
cpuu: resultProcess.cpuu,
|
|
cpus: resultProcess.cpus,
|
|
utime: resultProcess.utime,
|
|
stime: resultProcess.stime,
|
|
cutime: resultProcess.cutime,
|
|
cstime: resultProcess.cstime
|
|
};
|
|
}
|
|
});
|
|
|
|
// store old values
|
|
_processes_cpu.all = all;
|
|
_processes_cpu.list = Object.assign({}, list_new);
|
|
_processes_cpu.ms = Date.now() - _processes_cpu.ms;
|
|
_processes_cpu.result = Object.assign({}, result);
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
});
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
} else {
|
|
cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,stat,tty,user,comm';
|
|
if (_sunos) {
|
|
cmd = 'ps -o pid,ppid,vsz,rss,nice,etime,s,tty,user,comm';
|
|
}
|
|
exec(cmd, { maxBuffer: 1024 * 102400 }, (error, stdout) => {
|
|
if (!error) {
|
|
let lines = stdout.toString().split('\n');
|
|
lines.shift();
|
|
|
|
result.list = parseProcesses2(lines).slice();
|
|
result.all = result.list.length;
|
|
result.running = result.list.filter((e) => {
|
|
return e.state === 'running';
|
|
}).length;
|
|
result.blocked = result.list.filter((e) => {
|
|
return e.state === 'blocked';
|
|
}).length;
|
|
result.sleeping = result.list.filter((e) => {
|
|
return e.state === 'sleeping';
|
|
}).length;
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} catch {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
} else if (_windows) {
|
|
try {
|
|
util
|
|
.powerShell(
|
|
`Get-CimInstance Win32_Process | select-Object ProcessId,ParentProcessId,ExecutionState,Caption,CommandLine,ExecutablePath,UserModeTime,KernelModeTime,WorkingSetSize,Priority,PageFileUsage,
|
|
@{n="CreationDate";e={$_.CreationDate.ToString("yyyy-MM-dd HH:mm:ss")}} | ConvertTo-Json -compress`
|
|
)
|
|
.then((stdout, error) => {
|
|
if (!error) {
|
|
const procs = [];
|
|
const procStats = [];
|
|
const list_new = {};
|
|
let allcpuu = 0;
|
|
let allcpus = 0;
|
|
let processArray = [];
|
|
try {
|
|
stdout = stdout.trim().replace(/^\uFEFF/, '');
|
|
processArray = JSON.parse(stdout);
|
|
} catch {}
|
|
processArray.forEach((element) => {
|
|
const pid = element.ProcessId;
|
|
const parentPid = element.ParentProcessId;
|
|
const statusValue = element.ExecutionState || null;
|
|
const name = element.Caption;
|
|
const commandLine = element.CommandLine;
|
|
// get additional command line data
|
|
const commandPath = element.ExecutablePath;
|
|
const utime = element.UserModeTime;
|
|
const stime = element.KernelModeTime;
|
|
const memw = element.WorkingSetSize;
|
|
allcpuu = allcpuu + utime;
|
|
allcpus = allcpus + stime;
|
|
result.all++;
|
|
if (!statusValue) {
|
|
result.unknown++;
|
|
}
|
|
if (statusValue === '3') {
|
|
result.running++;
|
|
}
|
|
if (statusValue === '4' || statusValue === '5') {
|
|
result.blocked++;
|
|
}
|
|
|
|
procStats.push({
|
|
pid: pid,
|
|
utime: utime,
|
|
stime: stime,
|
|
cpu: 0,
|
|
cpuu: 0,
|
|
cpus: 0
|
|
});
|
|
procs.push({
|
|
pid: pid,
|
|
parentPid: parentPid,
|
|
name: name,
|
|
cpu: 0,
|
|
cpuu: 0,
|
|
cpus: 0,
|
|
mem: (memw / os.totalmem()) * 100,
|
|
priority: element.Priority | null,
|
|
memVsz: element.PageFileUsage || null,
|
|
memRss: Math.floor((element.WorkingSetSize || 0) / 1024),
|
|
nice: 0,
|
|
started: element.CreationDate,
|
|
state: statusValue ? _winStatusValues[statusValue] : _winStatusValues[0],
|
|
tty: '',
|
|
user: '',
|
|
command: commandLine || name,
|
|
path: commandPath,
|
|
params: ''
|
|
});
|
|
});
|
|
|
|
result.sleeping = result.all - result.running - result.blocked - result.unknown;
|
|
result.list = procs;
|
|
procStats.forEach((element) => {
|
|
let resultProcess = calcProcStatWin(element, allcpuu + allcpus, _processes_cpu);
|
|
|
|
// store pcpu in outer array
|
|
let listPos = result.list.map((e) => e.pid).indexOf(resultProcess.pid);
|
|
if (listPos >= 0) {
|
|
result.list[listPos].cpu = resultProcess.cpuu + resultProcess.cpus;
|
|
result.list[listPos].cpuu = resultProcess.cpuu;
|
|
result.list[listPos].cpus = resultProcess.cpus;
|
|
}
|
|
|
|
// save new values
|
|
list_new[resultProcess.pid] = {
|
|
cpuu: resultProcess.cpuu,
|
|
cpus: resultProcess.cpus,
|
|
utime: resultProcess.utime,
|
|
stime: resultProcess.stime
|
|
};
|
|
});
|
|
|
|
// store old values
|
|
_processes_cpu.all = allcpuu + allcpus;
|
|
_processes_cpu.all_utime = allcpuu;
|
|
_processes_cpu.all_stime = allcpus;
|
|
_processes_cpu.list = Object.assign({}, list_new);
|
|
_processes_cpu.ms = Date.now() - _processes_cpu.ms;
|
|
_processes_cpu.result = Object.assign({}, result);
|
|
}
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
});
|
|
} catch {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
} else {
|
|
if (callback) {
|
|
callback(_processes_cpu.result);
|
|
}
|
|
resolve(_processes_cpu.result);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
exports.processes = processes;
|
|
|
|
// --------------------------
|
|
// PS - process load
|
|
// get detailed information about a certain process
|
|
// (PID, CPU-Usage %, Mem-Usage %)
|
|
|
|
function processLoad(proc, callback) {
|
|
// fallback - if only callback is given
|
|
if (util.isFunction(proc) && !callback) {
|
|
callback = proc;
|
|
proc = '';
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
process.nextTick(() => {
|
|
proc = proc || '';
|
|
|
|
if (typeof proc !== 'string') {
|
|
if (callback) {
|
|
callback([]);
|
|
}
|
|
return resolve([]);
|
|
}
|
|
|
|
let processesString = '';
|
|
try {
|
|
processesString.__proto__.toLowerCase = util.stringToLower;
|
|
processesString.__proto__.replace = util.stringReplace;
|
|
processesString.__proto__.toString = util.stringToString;
|
|
processesString.__proto__.substr = util.stringSubstr;
|
|
processesString.__proto__.substring = util.stringSubstring;
|
|
processesString.__proto__.trim = util.stringTrim;
|
|
processesString.__proto__.startsWith = util.stringStartWith;
|
|
} catch {
|
|
Object.setPrototypeOf(processesString, util.stringObj);
|
|
}
|
|
|
|
const s = util.sanitizeShellString(proc);
|
|
const l = util.mathMin(s.length, 2000);
|
|
|
|
for (let i = 0; i <= l; i++) {
|
|
if (s[i] !== undefined) {
|
|
processesString = processesString + s[i];
|
|
}
|
|
}
|
|
|
|
processesString = processesString.trim().toLowerCase().replace(/, /g, '|').replace(/,+/g, '|');
|
|
if (processesString === '') {
|
|
processesString = '*';
|
|
}
|
|
if (util.isPrototypePolluted() && processesString !== '*') {
|
|
processesString = '------';
|
|
}
|
|
let processes = processesString.split('|');
|
|
let result = [];
|
|
|
|
const procSanitized = util.isPrototypePolluted() ? '' : util.sanitizeShellString(proc) || '*';
|
|
|
|
// from here new
|
|
// let result = {
|
|
// 'proc': procSanitized,
|
|
// 'pid': null,
|
|
// 'cpu': 0,
|
|
// 'mem': 0
|
|
// };
|
|
if (procSanitized && processes.length && processes[0] !== '------') {
|
|
if (_windows) {
|
|
try {
|
|
util.powerShell('Get-CimInstance Win32_Process | select ProcessId,Caption,UserModeTime,KernelModeTime,WorkingSetSize | ConvertTo-Json -compress').then((stdout, error) => {
|
|
if (!error) {
|
|
const procStats = [];
|
|
const list_new = {};
|
|
let allcpuu = 0;
|
|
let allcpus = 0;
|
|
let processArray = [];
|
|
try {
|
|
stdout = stdout.trim().replace(/^\uFEFF/, '');
|
|
processArray = JSON.parse(stdout);
|
|
} catch {}
|
|
|
|
// go through all processes
|
|
processArray.forEach((element) => {
|
|
const pid = element.ProcessId;
|
|
const name = element.Caption;
|
|
const utime = element.UserModeTime;
|
|
const stime = element.KernelModeTime;
|
|
const mem = element.WorkingSetSize;
|
|
allcpuu = allcpuu + utime;
|
|
allcpus = allcpus + stime;
|
|
|
|
procStats.push({
|
|
pid: pid,
|
|
name,
|
|
utime: utime,
|
|
stime: stime,
|
|
cpu: 0,
|
|
cpuu: 0,
|
|
cpus: 0,
|
|
mem
|
|
});
|
|
let pname = '';
|
|
let inList = false;
|
|
processes.forEach((proc) => {
|
|
if (name.toLowerCase().indexOf(proc.toLowerCase()) >= 0 && !inList) {
|
|
inList = true;
|
|
pname = proc;
|
|
}
|
|
});
|
|
|
|
if (processesString === '*' || inList) {
|
|
let processFound = false;
|
|
result.forEach((item) => {
|
|
if (item.proc.toLowerCase() === pname.toLowerCase()) {
|
|
item.pids.push(pid);
|
|
item.mem += (mem / os.totalmem()) * 100;
|
|
processFound = true;
|
|
}
|
|
});
|
|
if (!processFound) {
|
|
result.push({
|
|
proc: pname,
|
|
pid: pid,
|
|
pids: [pid],
|
|
cpu: 0,
|
|
mem: (mem / os.totalmem()) * 100
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
if (processesString !== '*') {
|
|
// add missing processes
|
|
let processesMissing = processes.filter((name) => procStats.filter((item) => item.name.toLowerCase().indexOf(name) >= 0).length === 0);
|
|
processesMissing.forEach((procName) => {
|
|
result.push({
|
|
proc: procName,
|
|
pid: null,
|
|
pids: [],
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
});
|
|
}
|
|
|
|
// calculate proc stats for each proc
|
|
procStats.forEach((element) => {
|
|
let resultProcess = calcProcStatWin(element, allcpuu + allcpus, _process_cpu);
|
|
|
|
let listPos = -1;
|
|
for (let j = 0; j < result.length; j++) {
|
|
if (result[j].pid === resultProcess.pid || result[j].pids.indexOf(resultProcess.pid) >= 0) {
|
|
listPos = j;
|
|
}
|
|
}
|
|
if (listPos >= 0) {
|
|
result[listPos].cpu += resultProcess.cpuu + resultProcess.cpus;
|
|
}
|
|
|
|
// save new values
|
|
list_new[resultProcess.pid] = {
|
|
cpuu: resultProcess.cpuu,
|
|
cpus: resultProcess.cpus,
|
|
utime: resultProcess.utime,
|
|
stime: resultProcess.stime
|
|
};
|
|
});
|
|
|
|
// store old values
|
|
_process_cpu.all = allcpuu + allcpus;
|
|
_process_cpu.all_utime = allcpuu;
|
|
_process_cpu.all_stime = allcpus;
|
|
_process_cpu.list = Object.assign({}, list_new);
|
|
_process_cpu.ms = Date.now() - _process_cpu.ms;
|
|
_process_cpu.result = JSON.parse(JSON.stringify(result));
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
});
|
|
} catch {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
}
|
|
|
|
if (_darwin || _linux || _freebsd || _openbsd || _netbsd) {
|
|
const params = ['-axo', 'pid,ppid,pcpu,pmem,comm'];
|
|
util.execSafe('ps', params).then((stdout) => {
|
|
if (stdout) {
|
|
const procStats = [];
|
|
const lines = stdout
|
|
.toString()
|
|
.split('\n')
|
|
.filter((line) => {
|
|
if (processesString === '*') {
|
|
return true;
|
|
}
|
|
if (line.toLowerCase().indexOf('grep') !== -1) {
|
|
return false;
|
|
} // remove this??
|
|
let found = false;
|
|
processes.forEach((item) => {
|
|
found = found || line.toLowerCase().indexOf(item.toLowerCase()) >= 0;
|
|
});
|
|
return found;
|
|
});
|
|
lines.shift();
|
|
lines.forEach((line) => {
|
|
const data = line.trim().replace(/ +/g, ' ').split(' ');
|
|
if (data.length > 4) {
|
|
const linuxName = data[4].indexOf('/') >= 0 ? data[4].substring(0, data[4].indexOf('/')) : data[4];
|
|
const name = _linux ? linuxName : data[4].substring(data[4].lastIndexOf('/') + 1);
|
|
procStats.push({
|
|
name,
|
|
pid: parseInt(data[0]) || 0,
|
|
ppid: parseInt(data[1]) || 0,
|
|
cpu: parseFloat(data[2].replace(',', '.')),
|
|
mem: parseFloat(data[3].replace(',', '.'))
|
|
});
|
|
}
|
|
});
|
|
|
|
procStats.forEach((item) => {
|
|
let listPos = -1;
|
|
let inList = false;
|
|
let name = item.name;
|
|
for (let j = 0; j < result.length; j++) {
|
|
if (item.name.toLowerCase().indexOf(result[j].proc.toLowerCase()) >= 0) {
|
|
listPos = j;
|
|
}
|
|
}
|
|
processes.forEach((proc) => {
|
|
if (item.name.toLowerCase().indexOf(proc.toLowerCase()) >= 0 && !inList) {
|
|
inList = true;
|
|
name = proc;
|
|
}
|
|
});
|
|
if (processesString === '*' || inList) {
|
|
if (listPos < 0) {
|
|
if (name) {
|
|
result.push({
|
|
proc: name,
|
|
pid: item.pid,
|
|
pids: [item.pid],
|
|
cpu: item.cpu,
|
|
mem: item.mem
|
|
});
|
|
}
|
|
} else {
|
|
if (item.ppid < 10) {
|
|
result[listPos].pid = item.pid;
|
|
}
|
|
result[listPos].pids.push(item.pid);
|
|
result[listPos].cpu += item.cpu;
|
|
result[listPos].mem += item.mem;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (processesString !== '*') {
|
|
// add missing processes
|
|
let processesMissing = processes.filter((name) => {
|
|
return (
|
|
procStats.filter((item) => {
|
|
return item.name.toLowerCase().indexOf(name) >= 0;
|
|
}).length === 0
|
|
);
|
|
});
|
|
processesMissing.forEach((procName) => {
|
|
result.push({
|
|
proc: procName,
|
|
pid: null,
|
|
pids: [],
|
|
cpu: 0,
|
|
mem: 0
|
|
});
|
|
});
|
|
}
|
|
if (_linux) {
|
|
// calc process_cpu - ps is not accurate in linux!
|
|
result.forEach((item) => {
|
|
item.cpu = 0;
|
|
});
|
|
let cmd = 'cat /proc/stat | grep "cpu "';
|
|
for (let i in result) {
|
|
for (let j in result[i].pids) {
|
|
cmd += ';cat /proc/' + result[i].pids[j] + '/stat';
|
|
}
|
|
}
|
|
exec(cmd, { maxBuffer: 1024 * 102400 }, (error, stdout) => {
|
|
let curr_processes = stdout.toString().split('\n');
|
|
|
|
// first line (all - /proc/stat)
|
|
let all = parseProcStat(curr_processes.shift());
|
|
|
|
// process
|
|
let list_new = {};
|
|
let resultProcess = {};
|
|
curr_processes.forEach((element) => {
|
|
resultProcess = calcProcStatLinux(element, all, _process_cpu);
|
|
|
|
if (resultProcess.pid) {
|
|
// find result item
|
|
let resultItemId = -1;
|
|
for (let i in result) {
|
|
if (result[i].pids.indexOf(resultProcess.pid) >= 0) {
|
|
resultItemId = i;
|
|
}
|
|
}
|
|
// store pcpu in outer result
|
|
if (resultItemId >= 0) {
|
|
result[resultItemId].cpu += resultProcess.cpuu + resultProcess.cpus;
|
|
}
|
|
|
|
// save new values
|
|
list_new[resultProcess.pid] = {
|
|
cpuu: resultProcess.cpuu,
|
|
cpus: resultProcess.cpus,
|
|
utime: resultProcess.utime,
|
|
stime: resultProcess.stime,
|
|
cutime: resultProcess.cutime,
|
|
cstime: resultProcess.cstime
|
|
};
|
|
}
|
|
});
|
|
|
|
result.forEach((item) => {
|
|
item.cpu = Math.round(item.cpu * 100) / 100;
|
|
});
|
|
|
|
_process_cpu.all = all;
|
|
_process_cpu.list = Object.assign({}, list_new);
|
|
_process_cpu.ms = Date.now() - _process_cpu.ms;
|
|
_process_cpu.result = Object.assign({}, result);
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
});
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
} else {
|
|
if (callback) {
|
|
callback(result);
|
|
}
|
|
resolve(result);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
exports.processLoad = processLoad;
|