| # Example section | ||
| ## server.js | ||
| Used to be tested with an HTTP benchmark tool like this one: https://github.com/wg/wrk. | ||
| Start the server, run the tests on `localhost:8020` | ||
| ## stresstest.js | ||
| Just start node stresstest.js (but be carefull though...) |
| var http = require('http') | ||
| var pusage = require('../') | ||
| http.createServer(function (req, res) { | ||
| res.writeHead(200) | ||
| res.end('hello world\n') | ||
| }).listen(8020) | ||
| var interval = setInterval(function () { | ||
| pusage.stat(process.pid, function (err, stat) { | ||
| if (err) { | ||
| throw err | ||
| } | ||
| console.log(stat) | ||
| }) | ||
| }, 100) | ||
| process.on('exit', function () { | ||
| clearInterval(interval) | ||
| }) |
| var pusage = require('../') | ||
| // stress test to compare with top or another tool | ||
| console.log('This is my PID: %s', process.pid) | ||
| // classic "drop somewhere"... yeah I'm a lazy guy | ||
| var formatBytes = function (bytes, precision) { | ||
| var kilobyte = 1024 | ||
| var megabyte = kilobyte * 1024 | ||
| var gigabyte = megabyte * 1024 | ||
| var terabyte = gigabyte * 1024 | ||
| if ((bytes >= 0) && (bytes < kilobyte)) { | ||
| return bytes + ' B ' | ||
| } else if ((bytes >= kilobyte) && (bytes < megabyte)) { | ||
| return (bytes / kilobyte).toFixed(precision) + ' KB ' | ||
| } else if ((bytes >= megabyte) && (bytes < gigabyte)) { | ||
| return (bytes / megabyte).toFixed(precision) + ' MB ' | ||
| } else if ((bytes >= gigabyte) && (bytes < terabyte)) { | ||
| return (bytes / gigabyte).toFixed(precision) + ' GB ' | ||
| } else if (bytes >= terabyte) { | ||
| return (bytes / terabyte).toFixed(precision) + ' TB ' | ||
| } else { | ||
| return bytes + ' B ' | ||
| } | ||
| } | ||
| var i = 0 | ||
| var bigMemoryLeak = [] | ||
| var stress = function (cb) { | ||
| var j = 500 | ||
| var arr = [] | ||
| while (j--) { | ||
| arr[j] = [] | ||
| for (var k = 0; k < 1000; k++) { | ||
| arr[j][k] = {lorem: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum non odio venenatis, pretium ligula nec, fringilla ipsum. Sed a erat et sem blandit dignissim. Pellentesque sollicitudin felis eu mattis porta. Nullam nec nibh nisl. Phasellus convallis vulputate massa vitae fringilla. Etiam facilisis lectus in odio lacinia rutrum. Praesent facilisis vitae urna a suscipit. Aenean lacinia blandit lorem, et ullamcorper metus sagittis faucibus. Nam porta eros nisi, at adipiscing quam varius eu. Vivamus sed sem quis lorem varius posuere ut quis elit.'} | ||
| } | ||
| } | ||
| bigMemoryLeak.push(arr) | ||
| pusage.stat(process.pid, function (err, stat) { | ||
| if (err) { | ||
| throw err | ||
| } | ||
| console.log('Pcpu: %s', stat.cpu) | ||
| console.log('Mem: %s', formatBytes(stat.memory)) | ||
| if (i === 100) { | ||
| return cb(null, true) | ||
| } else if (stat.memory > 3e8) { | ||
| console.log("That's enough right?") | ||
| cb(null, true) | ||
| } | ||
| i++ | ||
| return cb(null, false) | ||
| }) | ||
| } | ||
| var interval = function () { | ||
| return setTimeout(function () { | ||
| stress(function (err, stop) { | ||
| if (err) { | ||
| throw err | ||
| } | ||
| if (stop) { | ||
| process.exit() | ||
| } else { | ||
| return interval() | ||
| } | ||
| }) | ||
| }, 400) | ||
| } | ||
| setTimeout(function () { | ||
| interval() | ||
| }, 2000) |
+87
| var os = require('os') | ||
| var fs = require('fs') | ||
| var exec = require('child_process').exec | ||
| var parallel = require('./parallel') | ||
| /** | ||
| * Gathers Clock, PageSize and system uptime through /proc/uptime | ||
| * This method is mocked in procfile tests | ||
| */ | ||
| function updateCpu (cpu, next) { | ||
| if (cpu !== null) { | ||
| getRealUptime(function (err, uptime) { | ||
| if (err) return next(err) | ||
| cpu.uptime = uptime | ||
| next(null, cpu) | ||
| }) | ||
| return | ||
| } | ||
| parallel([ | ||
| getClockAndPageSize, | ||
| getRealUptime | ||
| ], function (err, data) { | ||
| if (err) return next(err) | ||
| cpu = { | ||
| clockTick: data[0].clockTick, | ||
| pageSize: data[0].pageSize, | ||
| uptime: data[1] | ||
| } | ||
| next(null, cpu) | ||
| }) | ||
| } | ||
| module.exports = updateCpu | ||
| /** | ||
| * Fallback on os.uptime(), though /proc/uptime is more precise | ||
| */ | ||
| function getRealUptime (next) { | ||
| fs.readFile('/proc/uptime', 'utf8', function (err, uptime) { | ||
| if (err || uptime === undefined) { | ||
| console.warn("[pidusage] We couldn't find uptime from /proc/uptime, using os.uptime() value") | ||
| return next(null, os.uptime()) | ||
| } | ||
| return next(null, parseFloat(uptime.split(' ')[0])) | ||
| }) | ||
| } | ||
| function getClockAndPageSize (next) { | ||
| parallel([ | ||
| function getClockTick (cb) { | ||
| getconf('CLK_TCK', {default: 100}, cb) | ||
| }, | ||
| function getPageSize (cb) { | ||
| getconf('PAGESIZE', {default: 4096}, cb) | ||
| } | ||
| ], function (err, data) { | ||
| if (err) return next(err) | ||
| next(null, {clockTick: data[0], pageSize: data[1]}) | ||
| }) | ||
| } | ||
| function getconf (keyword, options, next) { | ||
| if (typeof options === 'function') { | ||
| next = options | ||
| options = { default: '' } | ||
| } | ||
| exec('getconf ' + keyword, function (error, stdout, stderr) { | ||
| if (error !== null) { | ||
| console.error('Error while getting ' + keyword, error) | ||
| return next(null, options.default) | ||
| } | ||
| stdout = parseInt(stdout) | ||
| if (!isNaN(stdout)) { | ||
| return next(null, stdout) | ||
| } | ||
| return next(null, options.default) | ||
| }) | ||
| } |
| // execute an array of asynchronous functions in parallel | ||
| // @param {Array} fns - an array of functions | ||
| // @param {Function} done - callback(err, results) | ||
| function parallel (fns, done) { | ||
| var pending = fns.length | ||
| var results = [] | ||
| function each (i, err, result) { | ||
| results[i] = result | ||
| if (--pending === 0 || err) { | ||
| done && done(err, results) | ||
| done = null | ||
| } | ||
| } | ||
| fns.forEach(function (fn, i) { | ||
| fn(function (err, res) { | ||
| each(i, err, res) | ||
| }) | ||
| }) | ||
| } | ||
| module.exports = parallel |
| var os = require('os') | ||
| var UNSUPPORTED = 'unsupported' | ||
| // Also available "procfile" removed in 2.0.0 because of crappy benchmarks compared to ps | ||
| var platformToMethod = { | ||
| darwin: 'ps', | ||
| sunos: 'ps', | ||
| freebsd: 'ps', | ||
| netbsd: 'ps', | ||
| win: 'wmic', | ||
| linux: 'ps', | ||
| aix: 'ps', | ||
| procfile: 'procfile', | ||
| unsupported: UNSUPPORTED | ||
| } | ||
| var platform = os.platform() | ||
| if (platform.match(/^win/)) platform = 'win' // nor is windows a winner... | ||
| if (!platformToMethod[platform]) platform = UNSUPPORTED | ||
| module.exports = platformToMethod[platform] | ||
| module.exports.UNSUPPORTED = UNSUPPORTED |
| var fs = require('fs') | ||
| var path = require('path') | ||
| var updateCpu = require('./cpu') | ||
| var parallel = require('./parallel') | ||
| var cpu = null | ||
| function readProcFile (pid, options, done) { | ||
| var hst = options.history[pid] ? options.history[pid] : {} | ||
| // Arguments to path.join must be strings | ||
| fs.readFile(path.join('/proc', '' + pid, 'stat'), 'utf8', function (err, infos) { | ||
| if (err) { | ||
| return done(err, null) | ||
| } | ||
| var date = Date.now() | ||
| // https://github.com/arunoda/node-usage/commit/a6ca74ecb8dd452c3c00ed2bde93294d7bb75aa8 | ||
| // preventing process space in name by removing values before last ) (pid (name) ...) | ||
| var index = infos.lastIndexOf(')') | ||
| infos = infos.substr(index + 2).split(' ') | ||
| // according to http://man7.org/linux/man-pages/man5/proc.5.html (index 0 based - 2) | ||
| // In kernels before Linux 2.6, start was expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks | ||
| var stat = { | ||
| utime: parseFloat(infos[11]), | ||
| stime: parseFloat(infos[12]), | ||
| cutime: parseFloat(infos[13]), | ||
| cstime: parseFloat(infos[14]), | ||
| start: parseFloat(infos[19]) / cpu.clockTick, | ||
| rss: parseFloat(infos[21]) | ||
| } | ||
| // http://stackoverflow.com/questions/16726779/total-cpu-usage-of-an-application-from-proc-pid-stat/16736599#16736599 | ||
| var childrens = options.childrens ? stat.cutime + stat.cstime : 0 | ||
| var total = (stat.stime - (hst.stime || 0) + stat.utime - (hst.utime || 0) + childrens) / cpu.clockTick | ||
| // time elapsed between calls in seconds | ||
| var seconds = Math.abs(hst.uptime !== undefined ? cpu.uptime - hst.uptime : stat.start - cpu.uptime) | ||
| if (seconds === 0) seconds = 1 // we sure can't divide through 0 | ||
| options.history[pid] = stat | ||
| options.history[pid].uptime = cpu.uptime | ||
| var cpuPercent = (total / seconds) * 100 | ||
| var memory = stat.rss * cpu.pageSize | ||
| return done(null, { | ||
| cpu: cpuPercent, | ||
| memory: memory, | ||
| time: ((stat.utime + stat.stime) / cpu.clockTick) * 1000, // elapsed time in ms | ||
| start: new Date(date - seconds * 1000), // start date | ||
| pid: pid | ||
| }) | ||
| }) | ||
| } | ||
| function procfile (pid, options, done) { | ||
| updateCpu(cpu, function (err, result) { | ||
| if (err) return done(err) | ||
| cpu = result | ||
| var fns = [] | ||
| if (!Array.isArray(pid)) { | ||
| pid = [pid] | ||
| } | ||
| pid.forEach(function (id, i) { | ||
| fns[i] = function (cb) { | ||
| readProcFile(id, options, cb) | ||
| } | ||
| }) | ||
| parallel(fns, done) | ||
| }) | ||
| } | ||
| module.exports = procfile |
+79
| var spawn = require('child_process').spawn | ||
| var os = require('os') | ||
| var PLATFORM = os.platform() | ||
| /** | ||
| * Get pid informations through ps command | ||
| * @param {Number|Number[]} pid | ||
| * @param {Object} options | ||
| * @return {Function} callback(err, stat) | ||
| * on os x skip headers with pcpu=,rss= | ||
| * on linux it could be --no-header | ||
| * on solaris 11 can't figure out a way to do this properly so... | ||
| */ | ||
| function ps (pid, options, done) { | ||
| if (Array.isArray(pid)) { | ||
| pid = pid.join(',') | ||
| } | ||
| var args = ['-o', 'pcpu,rss,pid,time', '-p', pid] | ||
| if (PLATFORM === 'aix') { | ||
| args = ['-o', 'pcpu,rsssize,pid,time', '-p', pid] | ||
| } | ||
| var ps = spawn('ps', args) | ||
| var error | ||
| var stdout | ||
| ps.on('error', function (err) { | ||
| error = err | ||
| }) | ||
| ps.stdout.on('data', function (d) { | ||
| stdout += d.toString() | ||
| }) | ||
| ps.on('close', function () { | ||
| var date = Date.now() | ||
| if (error) return done(error, null) | ||
| stdout = stdout.split(os.EOL) | ||
| var statistics = [] | ||
| for (var i = 1; i < stdout.length; i++) { | ||
| stdout[i] = stdout[i].trim() | ||
| if (!stdout[i]) { | ||
| continue | ||
| } | ||
| var line = stdout[i].replace(/^\s+/, '').replace(/\s\s+/g, ' ').split(' ') | ||
| var time = 0 | ||
| // Example output 7-22:43:36 | ||
| var tmp = line[3].split(':') | ||
| var days = 0 | ||
| if (~tmp[0].indexOf('-')) { | ||
| var daysAndHours = tmp[0].split('-') | ||
| tmp[0] = daysAndHours[1] | ||
| days = daysAndHours[0] | ||
| } | ||
| time = (days * 86400 + tmp[0] * 3600 + tmp[1] * 60 + tmp[2]) * 1000 | ||
| statistics[i - 1] = { | ||
| cpu: parseFloat(line[0].replace(',', '.')), | ||
| memory: parseFloat(line[1]) * 1024, | ||
| pid: parseInt(line[2], 0), | ||
| time: time, // time in ms | ||
| start: new Date(date - time) | ||
| } | ||
| } | ||
| done(null, statistics) | ||
| }) | ||
| } | ||
| module.exports = ps |
+95
| var format = require('util').format | ||
| var os = require('os') | ||
| var spawn = require('child_process').spawn | ||
| function wmic (pid, options, done) { | ||
| var prefix = 'ProcessId=' | ||
| var whereClause = '' | ||
| if (!Array.isArray(pid)) pid = [pid] | ||
| var curr = pid[0] | ||
| if (!options.history[curr]) options.history[curr] = {} | ||
| whereClause = prefix + curr | ||
| for (var i = 1; i < pid.length; i++) { | ||
| curr = pid[i] | ||
| if (!options.history[curr]) options.history[curr] = {} | ||
| whereClause += ' or ' + prefix + curr | ||
| } | ||
| // http://social.msdn.microsoft.com/Forums/en-US/469ec6b7-4727-4773-9dc7-6e3de40e87b8/cpu-usage-in-for-each-active-process-how-is-this-best-determined-and-implemented-in-an?forum=csharplanguage | ||
| var args = ['PROCESS', 'where', '"' + whereClause + '"', 'get', 'ProcessId,workingsetsize,usermodetime,kernelmodetime'] | ||
| var wmic = spawn('wmic', args, {detached: true, windowsHide: true, windowsVerbatimArguments: true}) | ||
| var stdout = '' | ||
| var stderr = '' | ||
| var error = '' | ||
| // Note: On Windows the returned value includes fractions of a second. Use Math.floor() to get whole seconds. | ||
| var uptime = Math.floor(os.uptime()) | ||
| wmic.stdout.on('data', function (d) { | ||
| stdout += d.toString() | ||
| }) | ||
| wmic.stderr.on('data', function (d) { | ||
| stderr += d.toString() | ||
| }) | ||
| wmic.on('error', function (err) { | ||
| error = '[pidusage] Command "wmic ' + args.join(' ') + '" failed with error ' + err.message | ||
| }) | ||
| wmic.on('close', function (code) { | ||
| var date = Date.now() | ||
| stdout = stdout.trim() | ||
| stderr = stderr.trim() | ||
| if (!stdout || code !== 0) { | ||
| error += format('%s %s Wmic errored, please open an issue on https://github.com/soyuka/pidusage with this message.%s', os.EOL, new Date().toString(), os.EOL) | ||
| error += format('Command was "wmic %s" %s System informations: %s - release: %s %s - type %s %s', args.join(' '), os.EOL, os.EOL, os.release(), os.EOL, os.type(), os.EOL) | ||
| stderr = error + (stderr ? format('Wmic reported the following error: %s.', stderr) : 'Wmic reported no errors (stderr empty).') | ||
| stderr = format('%s%s%sWmic exited with code %d.', os.EOL, stderr, os.EOL, code) | ||
| stderr = format('%s%sStdout was %s', stderr, os.EOL, stdout || 'empty') | ||
| return done(new Error(stderr), null) | ||
| } | ||
| stdout = stdout.split(os.EOL) | ||
| var statistics = [] | ||
| for (var i = 1; i < stdout.length; i++) { | ||
| var line = stdout[i].replace(/\s\s+/g, ' ').split(' ') | ||
| // results are in alphabetical order | ||
| var id = parseInt(line[1], 10) | ||
| var hst = options.history[id] | ||
| var workingsetsize = parseFloat(line[3]) | ||
| var stats = { | ||
| kernelmodetime: parseFloat(line[0]), | ||
| usermodetime: parseFloat(line[2]) | ||
| } | ||
| // process usage since last call (obscure sheeeeet don't ask) | ||
| var total = (stats.kernelmodetime - (hst.kernelmodetime || 0) + stats.usermodetime - (hst.usermodetime || 0)) / 10000000 | ||
| // time elapsed between calls | ||
| var seconds = hst.uptime !== undefined ? uptime - hst.uptime : 0 | ||
| var cpu = seconds > 0 ? (total / seconds) * 100 : 0 | ||
| options.history[id] = stats | ||
| options.history[id].uptime = uptime | ||
| statistics[i - 1] = { | ||
| cpu: cpu, | ||
| memory: workingsetsize, | ||
| time: stats.usermodetime + stats.kernelmodetime, // should be ms according to https://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx | ||
| start: new Date(date - (stats.usermodetime + stats.kernelmodetime)), | ||
| pid: id | ||
| } | ||
| } | ||
| done(null, statistics) | ||
| }) | ||
| wmic.stdin.end() | ||
| } | ||
| module.exports = wmic |
| var bench = require('nanobench') | ||
| var fs = require('fs') | ||
| var history = {} | ||
| function clear () { | ||
| for (var i in history) { | ||
| delete history[i] | ||
| } | ||
| } | ||
| function getProcessList (cb) { | ||
| fs.readdir('/proc', function (err, list) { | ||
| if (err) throw err | ||
| cb(list.filter(function (v) { | ||
| return !isNaN(parseInt(v)) | ||
| })) | ||
| }) | ||
| } | ||
| getProcessList(function (list) { | ||
| console.log('Benching %d process', list.length) | ||
| bench('procfile', function (b) { | ||
| var procfile = require('../lib/procfile') | ||
| b.start() | ||
| procfile(list, {history: history}, function (err, data) { | ||
| if (err) throw err | ||
| b.end() | ||
| clear() | ||
| }) | ||
| }) | ||
| bench('ps', function (b) { | ||
| var ps = require('../lib/ps') | ||
| b.start() | ||
| ps(list, {history: history}, function (err, data) { | ||
| if (err) throw err | ||
| b.end() | ||
| clear() | ||
| }) | ||
| }) | ||
| }) |
| var http = require('http') | ||
| http.createServer(function (req, res) { | ||
| res.writeHead(200) | ||
| res.end('hello world\n') | ||
| }).listen(8020) |
| var mockery = require('mockery') | ||
| function before () { | ||
| mockery.enable({ | ||
| warnOnReplace: false, | ||
| warnOnUnregistered: false, | ||
| useCleanCache: true | ||
| }) | ||
| } | ||
| function after () { | ||
| mockery.deregisterAll() | ||
| mockery.disable() | ||
| } | ||
| function test (tape) { | ||
| tape.test('procfile stat', function (t) { | ||
| if (require('os').platform() === 'win32') { | ||
| return t.end() | ||
| } | ||
| t.plan(2) | ||
| before() | ||
| var fs = require('fs') | ||
| fs.readFile = function (path, encoding, callback) { | ||
| if (path === '/proc/uptime') { | ||
| callback(null, '100 0') | ||
| return | ||
| } | ||
| // proc/<pid>/stat | ||
| var infos = '0 (test)' | ||
| for (var i = 0; i < 22; i++) { | ||
| if (i === 12) { | ||
| infos += ' ' + currentStime | ||
| } else { | ||
| infos += ' 0' | ||
| } | ||
| } | ||
| callback(null, infos) | ||
| } | ||
| var clockTick = 100 | ||
| var os = require('os') | ||
| os.platform = function () { return 'procfile' } | ||
| mockery.registerMock('os', os) | ||
| mockery.registerMock('fs', fs) | ||
| mockery.registerMock('./cpu.js', function (cpu, next) { | ||
| next({ | ||
| clockTick: clockTick, | ||
| uptime: clockTick, | ||
| pagesize: 4096 | ||
| }) | ||
| }) | ||
| // set the previous history as if kernel module usage had been called before | ||
| var kernelModulePid = 0 | ||
| var currentStime = 10000 * clockTick | ||
| var previousStime = 2000 * clockTick | ||
| var pidusage = require('..') | ||
| pidusage._history[kernelModulePid] = {} | ||
| pidusage._history[kernelModulePid].uptime = 0 | ||
| pidusage._history[kernelModulePid].utime = 0 | ||
| pidusage._history[kernelModulePid].stime = previousStime | ||
| pidusage.stat(kernelModulePid, function (err, stat) { | ||
| t.error(err) | ||
| t.equal(stat.cpu, (currentStime - previousStime) / clockTick) | ||
| after() | ||
| }) | ||
| }) | ||
| } | ||
| module.exports = test |
+65
| var mockery = require('mockery') | ||
| var EventEmitter = require('events') | ||
| var streamify = require('string-to-stream') | ||
| var through = require('through') | ||
| function before () { | ||
| mockery.enable({ | ||
| warnOnReplace: false, | ||
| warnOnUnregistered: false, | ||
| useCleanCache: true | ||
| }) | ||
| } | ||
| function after () { | ||
| mockery.deregisterAll() | ||
| mockery.disable() | ||
| } | ||
| function test (tape) { | ||
| tape.test('ps stat (darwin)', function (t) { | ||
| t.plan(4) | ||
| before() | ||
| var os = require('os') | ||
| os.platform = function () { return 'darwin' } | ||
| mockery.registerMock('os', os) | ||
| var childprocess = require('child_process') | ||
| childprocess.spawn = function (command, args) { | ||
| t.equal(command, 'ps') | ||
| t.deepEqual(args, ['-o', 'pcpu,rss,pid,time', '-p', process.pid]) | ||
| var ee = new EventEmitter() | ||
| var writable = through(function (data) { | ||
| this.queue(data) | ||
| }) | ||
| var data = [ | ||
| '%CPU RSS PID TIME', | ||
| '0.0 1234 ' + process.pid + ' 7-22:43:36' | ||
| ] | ||
| ee.stdout = writable | ||
| streamify(data.join(os.EOL)).pipe(writable) | ||
| writable.on('end', function () { | ||
| ee.emit('close') | ||
| }) | ||
| return ee | ||
| } | ||
| mockery.registerMock('child_process', childprocess) | ||
| // require after mock | ||
| var pidusage = require('..') | ||
| pidusage.stat(process.pid, {advanced: true}, function (err, stat) { | ||
| t.error(err) | ||
| t.equal(stat.time, 68658036000) | ||
| // @TODO test that the date given is 7 days, 22 hours, 43 minutes and 36 seconds in the past | ||
| after() | ||
| }) | ||
| }) | ||
| } | ||
| module.exports = test |
+69
| var mockery = require('mockery') | ||
| var EventEmitter = require('events') | ||
| var streamify = require('string-to-stream') | ||
| var through = require('through') | ||
| function before () { | ||
| mockery.enable({ | ||
| warnOnReplace: false, | ||
| warnOnUnregistered: false, | ||
| useCleanCache: true | ||
| }) | ||
| } | ||
| function after () { | ||
| mockery.deregisterAll() | ||
| mockery.disable() | ||
| } | ||
| function test (tape) { | ||
| tape.test('wmic stat (win32)', function (t) { | ||
| t.plan(6) | ||
| before() | ||
| var os = require('os') | ||
| os.platform = function () { return 'win32' } | ||
| mockery.registerMock('os', os) | ||
| var childprocess = require('child_process') | ||
| childprocess.spawn = function (command, args) { | ||
| t.equal(command, 'wmic') | ||
| t.deepEqual(args, ['PROCESS', 'where', '"ProcessId=' + process.pid + '"', 'get', 'ProcessId,workingsetsize,usermodetime,kernelmodetime']) | ||
| var ee = new EventEmitter() | ||
| var writable = through(function (data) { | ||
| this.queue(data) | ||
| }) | ||
| var data = [ | ||
| 'KernelModeTime ProcessId UserModeTime WorkingSetSize', | ||
| '153750000 ' + process.pid + ' 8556250000 110821376' | ||
| ] | ||
| ee.stdout = writable | ||
| ee.stderr = through(function () {}) | ||
| ee.stdin = {end: function () {}} | ||
| streamify(data.join(os.EOL)).pipe(writable) | ||
| writable.on('end', function () { | ||
| ee.emit('close', 0) | ||
| }) | ||
| return ee | ||
| } | ||
| mockery.registerMock('child_process', childprocess) | ||
| // require after mock | ||
| var pidusage = require('..') | ||
| pidusage.stat(process.pid, function (err, stat) { | ||
| t.error(err) | ||
| t.equal(stat.memory, 110821376) | ||
| t.equal(stat.time, 8710000000) | ||
| t.equal(stat.pid, process.pid) | ||
| // @TODO test that the date | ||
| after() | ||
| }) | ||
| }) | ||
| } | ||
| module.exports = test |
+11
-9
@@ -0,11 +1,13 @@ | ||
| sudo: false | ||
| language: node_js | ||
| branches: | ||
| only: | ||
| - master | ||
| node_js: | ||
| - '9' | ||
| - '8' | ||
| - '6' | ||
| - '4' | ||
| os: | ||
| - linux | ||
| - osx | ||
| node_js: | ||
| - "8" | ||
| - "6" | ||
| - "4" | ||
| - linux | ||
| - osx | ||
| cache: | ||
| directories: | ||
| - node_modules |
+14
-16
| init: | ||
| - git config --global core.autocrlf input | ||
| - git config --global core.autocrlf input | ||
| build: off | ||
| environment: | ||
| matrix: | ||
| - nodejs_version: "0.10" | ||
| - nodejs_version: "0.12" | ||
| - nodejs_version: "4" | ||
| - nodejs_version: "5" | ||
| - nodejs_version: '9' | ||
| - nodejs_version: '8' | ||
| - nodejs_version: '6' | ||
| - nodejs_version: '4' | ||
| platform: | ||
| - x86 | ||
| - x64 | ||
| cache: | ||
| - node_modules | ||
| install: | ||
| - ps: Install-Product node $env:nodejs_version | ||
| - node --version | ||
| - npm --version | ||
| - npm install | ||
| test_script: | ||
| - node --version | ||
| - npm --version | ||
| - cmd: npm test | ||
| matrix: | ||
| allow_failures: | ||
| - nodejs_version: "0.10" | ||
| build: off | ||
| - npm test |
+14
-0
@@ -0,1 +1,15 @@ | ||
| ### 2.0 | ||
| There is no BC break but because the code got refactored a lot and that the default retrieval method has changed we're bumping a major version. | ||
| - allow multiple pids | ||
| - remove `advanced` option | ||
| - `start` result is now a `Date` instance | ||
| - don't use `/proc` files anymore but use `ps` instead | ||
| - more tests | ||
| ### 1.2.0 | ||
| Introduce `advanced` option to get time, and start | ||
| ### 1.1.0 | ||
@@ -2,0 +16,0 @@ |
+18
-25
| var os = require('os') | ||
| var stats = require('./lib/stats') | ||
| var platform = require('./lib/platform') | ||
| var history = {} | ||
| var wrapper = function (statType) { | ||
| var wrapper = function (method) { | ||
| return function (pid, options, cb) { | ||
@@ -11,33 +13,24 @@ if (typeof options === 'function') { | ||
| return stats[statType](pid, options, cb) | ||
| if (method === platform.UNSUPPORTED) { | ||
| return cb(new Error(os.platform() + ' is not supported yet, please open an issue (https://github.com/soyuka/pidusage)'), null) | ||
| } | ||
| options.history = history | ||
| return stats[method](pid, options, cb) | ||
| } | ||
| } | ||
| var pusage = { | ||
| darwin: wrapper('ps'), | ||
| sunos: wrapper('ps'), | ||
| freebsd: wrapper('ps'), | ||
| netbsd: wrapper('proc'), | ||
| win: wrapper('win'), | ||
| linux: wrapper('proc'), | ||
| aix: wrapper('ps'), | ||
| unsupported: function (pid, options, cb) { | ||
| cb = typeof options === 'function' ? options : cb | ||
| exports.stat = wrapper(platform) | ||
| cb(new Error(os.platform() + ' is not supported yet, please fire an issue (https://github.com/soyuka/pidusage)')) | ||
| exports.unmonitor = function (pid) { | ||
| if (!pid) { | ||
| for (var i in history) { | ||
| delete history[i] | ||
| } | ||
| return | ||
| } | ||
| } | ||
| var platform = os.platform() | ||
| platform = platform.match(/^win/) ? 'win' : platform // nor is windows a winner... | ||
| platform = pusage[platform] ? platform : 'unsupported' | ||
| exports.stat = function () { | ||
| pusage[platform].apply(stats, [].slice.call(arguments)) | ||
| delete history[pid] | ||
| } | ||
| exports.unmonitor = function (pid) { | ||
| delete stats.history[pid] | ||
| } | ||
| exports._history = stats.history | ||
| exports._history = history |
+24
-220
@@ -1,232 +0,36 @@ | ||
| var os = require('os') | ||
| var fs = require('fs') | ||
| var p = require('path') | ||
| var exec = require('child_process').exec | ||
| var spawn = require('child_process').spawn | ||
| var helpers = require('./helpers') | ||
| var format = require('util').format | ||
| var PLATFORM = os.platform() | ||
| // Statistics processor files | ||
| var wmic = require('./wmic') | ||
| var ps = require('./ps') | ||
| var procfile = require('./procfile') | ||
| var stats = { | ||
| history: {}, | ||
| cpu: null, // used to store cpu informations | ||
| proc: function (pid, options, done) { | ||
| var self = this | ||
| /** | ||
| * Just a callback wrapper to keep backward compatibility | ||
| */ | ||
| function callback (err, statistics, options, done) { | ||
| if (err) return done(err, null) | ||
| if (this.cpu !== null) { | ||
| fs.readFile('/proc/uptime', 'utf8', function (err, uptime) { | ||
| if (err) { | ||
| return done(err, null) | ||
| } | ||
| // BC | ||
| if (statistics.length === 1) { | ||
| return done(null, statistics[0]) | ||
| } | ||
| if (uptime === undefined) { | ||
| console.error("[pidusage] We couldn't find uptime from /proc/uptime") | ||
| self.cpu.uptime = os.uptime() | ||
| } else { | ||
| self.cpu.uptime = uptime.split(' ')[0] | ||
| } | ||
| return done(null, statistics) | ||
| } | ||
| return self.proc_calc(pid, options, done) | ||
| }) | ||
| } else { | ||
| helpers.cpu(function (err, cpu) { | ||
| if (err) { | ||
| return done(err, null) | ||
| } | ||
| self.cpu = cpu | ||
| return self.proc_calc(pid, options, done) | ||
| }) | ||
| } | ||
| }, | ||
| proc_calc: function (pid, options, done) { | ||
| pid = parseInt(pid, 10) | ||
| var history = this.history[pid] ? this.history[pid] : {} | ||
| var cpu = this.cpu | ||
| var self = this | ||
| // Arguments to path.join must be strings | ||
| fs.readFile(p.join('/proc', '' + pid, 'stat'), 'utf8', function (err, infos) { | ||
| if (err) { | ||
| return done(err, null) | ||
| } | ||
| // https://github.com/arunoda/node-usage/commit/a6ca74ecb8dd452c3c00ed2bde93294d7bb75aa8 | ||
| // preventing process space in name by removing values before last ) (pid (name) ...) | ||
| var index = infos.lastIndexOf(')') | ||
| infos = infos.substr(index + 2).split(' ') | ||
| // according to http://man7.org/linux/man-pages/man5/proc.5.html (index 0 based - 2) | ||
| // In kernels before Linux 2.6, start was expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks | ||
| var stat = { | ||
| utime: parseFloat(infos[11]), | ||
| stime: parseFloat(infos[12]), | ||
| cutime: parseFloat(infos[13]), | ||
| cstime: parseFloat(infos[14]), | ||
| start: parseFloat(infos[19]) / cpu.clockTick, | ||
| rss: parseFloat(infos[21]) | ||
| } | ||
| // http://stackoverflow.com/questions/16726779/total-cpu-usage-of-an-application-from-proc-pid-stat/16736599#16736599 | ||
| var childrens = options.childrens ? stat.cutime + stat.cstime : 0 | ||
| var total = stat.stime - (history.stime || 0) + stat.utime - (history.utime || 0) + childrens | ||
| total = total / cpu.clockTick | ||
| // time elapsed between calls | ||
| var seconds = history.uptime !== undefined ? cpu.uptime - history.uptime : stat.start - cpu.uptime | ||
| seconds = Math.abs(seconds) | ||
| seconds = seconds === 0 ? 1 : seconds // we sure can't divide through 0 | ||
| self.history[pid] = stat | ||
| self.history[pid].uptime = cpu.uptime | ||
| var cpuPercent = (total / seconds) * 100 | ||
| var memory = stat.rss * cpu.pagesize | ||
| if (!options.advanced) { | ||
| return done(null, { | ||
| cpu: cpuPercent, | ||
| memory: memory | ||
| }) | ||
| } | ||
| return done(null, { | ||
| cpu: cpuPercent, | ||
| memory: memory, | ||
| time: stat.utime + stat.stime, | ||
| start: stat.start | ||
| }) | ||
| module.exports = { | ||
| procfile: function (pid, options, done) { | ||
| procfile(pid, options, function (err, statistics) { | ||
| callback(err, statistics, options, done) | ||
| }) | ||
| }, | ||
| /** | ||
| * Get pid informations through ps command | ||
| * @param {int} pid | ||
| * @return {Function} done (err, stat) | ||
| * on os x skip headers with pcpu=,rss= | ||
| * on linux it could be --no-header | ||
| * on solaris 11 can't figure out a way to do this properly so... | ||
| */ | ||
| ps: function (pid, options, done) { | ||
| pid = parseInt(pid, 10) | ||
| var cmd = 'ps -o pcpu,rss -p ' | ||
| if (options.advanced) { | ||
| cmd = 'ps -o pcpu,rss,time,start -p ' | ||
| if (PLATFORM === 'aix') { | ||
| cmd = 'ps -o pcpu,rssize,time,start -p ' | ||
| } | ||
| } else if (PLATFORM === 'aix') { | ||
| cmd = 'ps -o pcpu,rssize -p ' // this one could work on other platforms see AIX section in man ps | ||
| } | ||
| exec(cmd + pid, function (err, stdout, stderr) { | ||
| if (err) { | ||
| return done(err, null) | ||
| } | ||
| stdout = stdout.split(os.EOL)[1] | ||
| stdout = stdout.replace(/^\s+/, '').replace(/\s\s+/g, ' ').split(' ') | ||
| var cpuPercent = parseFloat(stdout[0].replace(',', '.')) | ||
| var memory = parseFloat(stdout[1]) * 1024 | ||
| if (!options.advanced) { | ||
| return done(null, { | ||
| cpu: cpuPercent, | ||
| memory: memory | ||
| }) | ||
| } | ||
| return done(null, { | ||
| cpu: cpuPercent, | ||
| memory: memory, | ||
| time: parseFloat(stdout[2]), | ||
| start: parseFloat(stdout[3]) | ||
| }) | ||
| ps(pid, options, function (err, statistics) { | ||
| callback(err, statistics, options, done) | ||
| }) | ||
| }, | ||
| /** | ||
| * This is really in a beta stage | ||
| */ | ||
| win: function (pid, options, done) { | ||
| pid = parseInt(pid, 10) | ||
| var history = this.history[pid] ? this.history[pid] : {} | ||
| // http://social.msdn.microsoft.com/Forums/en-US/469ec6b7-4727-4773-9dc7-6e3de40e87b8/cpu-usage-in-for-each-active-process-how-is-this-best-determined-and-implemented-in-an?forum=csharplanguage | ||
| var args = 'PROCESS ' + pid + ' get workingsetsize,usermodetime,kernelmodetime' | ||
| var wmic = spawn('wmic', args.split(' '), {detached: true}) | ||
| var stdout = '' | ||
| var stderr = '' | ||
| var self = this | ||
| // Note: On Windows the returned value includes fractions of a second. Use Math.floor() to get whole seconds. | ||
| var uptime = Math.floor(os.uptime()) | ||
| wmic.stdout.on('data', function (d) { | ||
| stdout += d.toString() | ||
| wmic: function (pid, options, done) { | ||
| wmic(pid, options, function (err, statistics) { | ||
| callback(err, statistics, options, done) | ||
| }) | ||
| wmic.stderr.on('data', function (d) { | ||
| stderr += d.toString() | ||
| }) | ||
| wmic.on('error', function (err) { | ||
| console.error('[pidusage] Command "wmic ' + args + '" failed with error %s', err) | ||
| }) | ||
| wmic.on('close', function (code) { | ||
| stdout = stdout.trim() | ||
| stderr = stderr.trim() | ||
| if (!stdout || code !== 0) { | ||
| var error = format('%s Wmic errored, please open an issue on https://github.com/soyuka/pidusage with this message.%s', new Date().toString(), os.EOL) | ||
| error += format('Command was "wmic %s" %s System informations: %s - release: %s %s - type %s %s', args, os.EOL, os.EOL, os.release(), os.EOL, os.type(), os.EOL) | ||
| stderr = error + (stderr ? format('Wmic reported the following error: %s.', stderr) : 'Wmic reported no errors (stderr empty).') | ||
| stderr = format('%s%s%sWmic exited with code %d.', os.EOL, stderr, os.EOL, code) | ||
| stderr = format('%s%sStdout was %s', stderr, os.EOL, stdout || 'empty') | ||
| return done(new Error(stderr, null)) | ||
| } | ||
| stdout = stdout.split(os.EOL)[1].replace(/\s\s+/g, ' ').split(' ') | ||
| var stats = { | ||
| kernelmodetime: parseFloat(stdout[0]), | ||
| usermodetime: parseFloat(stdout[1]) | ||
| } | ||
| var workingsetsize = parseFloat(stdout[2]) | ||
| // process usage since last call | ||
| var total = stats.kernelmodetime - (history.kernelmodetime || 0) + stats.usermodetime - (history.usermodetime || 0) | ||
| total = total / 10000000 | ||
| // time elapsed between calls | ||
| var seconds = history.uptime !== undefined ? uptime - history.uptime : 0 | ||
| var cpu = 0 | ||
| if (seconds > 0) { | ||
| cpu = (total / seconds) * 100 | ||
| } | ||
| self.history[pid] = stats | ||
| self.history[pid].uptime = uptime | ||
| if (!options.advanced) { | ||
| return done(null, {cpu: cpu, memory: workingsetsize}) | ||
| } | ||
| return done(null, { | ||
| cpu: cpu, | ||
| memory: workingsetsize, | ||
| time: stats.usermodetime + stats.kernelmodetime, | ||
| start: seconds | ||
| }) | ||
| }) | ||
| wmic.stdin.end() | ||
| } | ||
| } | ||
| module.exports = stats |
+8
-5
| { | ||
| "name": "pidusage", | ||
| "version": "1.2.0", | ||
| "version": "2.0.0", | ||
| "description": "Cross-platform process cpu % and memory usage of a PID — Edit", | ||
@@ -8,6 +8,9 @@ "main": "index.js", | ||
| "devDependencies": { | ||
| "chai": "~3.4.1", | ||
| "mocha": "~2.3.4", | ||
| "faucet": "0.0.1", | ||
| "mockery": "1.4.0", | ||
| "standard": "^10.0.3" | ||
| "nanobench": "^2.1.1", | ||
| "standard": "^10.0.3", | ||
| "string-to-stream": "^1.1.0", | ||
| "tape": "^4.9.0", | ||
| "through": "^2.3.8" | ||
| }, | ||
@@ -18,3 +21,3 @@ "engines": { | ||
| "scripts": { | ||
| "test": "standard index.js lib/*.js test/*.js && mocha test/test.js --reporter min && node test/stresstest.js" | ||
| "test": "standard index.js lib/*.js test/*.js && node test/test.js | faucet" | ||
| }, | ||
@@ -21,0 +24,0 @@ "repository": { |
+7
-3
@@ -47,3 +47,3 @@ pidusage | ||
| ```javascript | ||
| pusage(process.pid, {advanced: true}, function (err, stat) { | ||
| pusage.stat(process.pid, {advanced: true}, function (err, stat) { | ||
| console.log(stat.time, stat.start) | ||
@@ -58,4 +58,4 @@ }) | ||
| - `memory` memory bytes | ||
| - `time` user + system time | ||
| - `start` time process was started | ||
| - `time` total cpu time in miliseconds | ||
| - `start` Date when process was started | ||
| ``` | ||
@@ -106,4 +106,8 @@ | ||
| #### pidusage-promise | ||
| Need promise? Use [`pidusage-promise`](https://github.com/soyuka/pidusage-promise)! | ||
| ## Licence | ||
| MIT |
+54
-147
@@ -1,163 +0,70 @@ | ||
| /* global beforeEach, afterEach, it, describe */ | ||
| var mockery = require('mockery') | ||
| var expect = require('chai').expect | ||
| var os = require('os') | ||
| var path = require('path') | ||
| var test = require('tape') | ||
| var fork = require('child_process').fork | ||
| var platform = require('../lib/platform') | ||
| var pidusage = require('../') | ||
| // classic "drop somewhere"... yeah I'm a lazy guy | ||
| var formatBytes = function (bytes, precision) { | ||
| var kilobyte = 1024 | ||
| var megabyte = kilobyte * 1024 | ||
| var gigabyte = megabyte * 1024 | ||
| var terabyte = gigabyte * 1024 | ||
| test('integration', function (t) { | ||
| t.plan(5) | ||
| if ((bytes >= 0) && (bytes < kilobyte)) { | ||
| return bytes + ' B ' | ||
| } else if ((bytes >= kilobyte) && (bytes < megabyte)) { | ||
| return (bytes / kilobyte).toFixed(precision) + ' KB ' | ||
| } else if ((bytes >= megabyte) && (bytes < gigabyte)) { | ||
| return (bytes / megabyte).toFixed(precision) + ' MB ' | ||
| } else if ((bytes >= gigabyte) && (bytes < terabyte)) { | ||
| return (bytes / gigabyte).toFixed(precision) + ' GB ' | ||
| } else if (bytes >= terabyte) { | ||
| return (bytes / terabyte).toFixed(precision) + ' TB ' | ||
| } else { | ||
| return bytes + ' B ' | ||
| } | ||
| } | ||
| t.equal(typeof pidusage.stat, 'function') | ||
| t.equal(typeof pidusage.unmonitor, 'function') | ||
| describe('pid usage', function () { | ||
| this.timeout(10000) | ||
| beforeEach(function () { | ||
| mockery.enable({ | ||
| warnOnReplace: false, | ||
| warnOnUnregistered: false, | ||
| useCleanCache: true | ||
| }) | ||
| pidusage.stat(process.pid, function (err, stats) { | ||
| t.comment('Pid: ' + process.pid + '. Platform: ' + os.platform()) | ||
| console.log(stats) | ||
| t.error(err) | ||
| t.deepEqual(Object.keys(stats).sort(), ['cpu', 'memory', 'pid', 'start', 'time']) | ||
| t.ok(typeof stats.start, 'Date') | ||
| }) | ||
| }) | ||
| afterEach(function () { | ||
| mockery.deregisterAll() | ||
| mockery.disable() | ||
| }) | ||
| test('unmonitor with pid (only wmic and procfile)', function (t) { | ||
| if (platform === 'ps' || platform === platform.UNSUPPORTED) { | ||
| t.end() | ||
| return | ||
| } | ||
| it('should get pid usage', function (cb) { | ||
| var pusage = require('../').stat | ||
| pusage(process.pid, function (err, stat) { | ||
| expect(err).to.equal(null) | ||
| expect(stat).to.be.an('object') | ||
| expect(stat).to.have.property('cpu') | ||
| expect(stat).to.have.property('memory') | ||
| t.plan(3) | ||
| console.log('Pcpu: %s', stat.cpu) | ||
| console.log('Mem: %s', formatBytes(stat.memory)) | ||
| cb() | ||
| }) | ||
| pidusage.stat(process.pid, {advanced: true}, function (err, stats) { | ||
| t.error(err) | ||
| t.ok(pidusage._history[process.pid]) | ||
| pidusage.unmonitor(process.pid) | ||
| t.notOk(pidusage._history[process.pid]) | ||
| }) | ||
| }) | ||
| it('should get advanced pid usage', function (cb) { | ||
| var pusage = require('../').stat | ||
| pusage(process.pid, {advanced: true}, function (err, stat) { | ||
| expect(err).to.equal(null) | ||
| expect(stat).to.be.an('object') | ||
| expect(stat).to.have.property('cpu') | ||
| expect(stat).to.have.property('memory') | ||
| expect(stat).to.have.property('time') | ||
| expect(stat).to.have.property('start') | ||
| test('unmonitor without pid (only wmic and procfile)', function (t) { | ||
| if (platform === 'ps' || platform === platform.UNSUPPORTED) { | ||
| t.end() | ||
| return | ||
| } | ||
| console.log('Pcpu: %s', stat.cpu) | ||
| console.log('Mem: %s', formatBytes(stat.memory)) | ||
| t.plan(3) | ||
| cb() | ||
| }) | ||
| pidusage.stat(process.pid, {advanced: true}, function (err, stats) { | ||
| t.error(err) | ||
| t.ok(pidusage._history[process.pid]) | ||
| pidusage.unmonitor() | ||
| t.notOk(pidusage._history[process.pid]) | ||
| }) | ||
| }) | ||
| it('should get pid usage multiple time', function (cb) { | ||
| var pusage = require('../').stat | ||
| var num = 0 | ||
| var interval | ||
| test('integration mutliple pids', function (t) { | ||
| t.plan(3) | ||
| var p = fork(path.join(__dirname, './fixtures/http.js')) | ||
| var pids = [process.pid, p.pid] | ||
| function launch () { | ||
| pusage(process.pid, function (err, stat) { | ||
| expect(err).to.equal(null) | ||
| expect(stat).to.be.an('object') | ||
| expect(stat).to.have.property('cpu') | ||
| expect(stat).to.have.property('memory') | ||
| console.log('Pcpu: %s', stat.cpu) | ||
| console.log('Mem: %s', formatBytes(stat.memory)) | ||
| if (++num === 5) { | ||
| clearInterval(interval) | ||
| cb() | ||
| } else { | ||
| setTimeout(launch, 100) | ||
| } | ||
| }) | ||
| } | ||
| interval = setTimeout(launch, 1000) | ||
| pidusage.stat(pids, function (err, stats) { | ||
| t.error(err) | ||
| t.equal(stats.length, 2) | ||
| t.deepEqual(Object.keys(stats[1]).sort(), ['cpu', 'memory', 'pid', 'start', 'time']) | ||
| p.kill() | ||
| }) | ||
| }) | ||
| it('should calculate correct cpu when user space time is zero (kernel module)', function (cb) { | ||
| // force platform to linux to test this case | ||
| var os = require('os') | ||
| os.platform = function () { | ||
| return 'linux' | ||
| } | ||
| // override readFile to simulate the system time only (kernel module) case | ||
| var fs = require('fs') | ||
| var clockTick = 100 | ||
| fs.readFile = function (path, encoding, callback) { | ||
| if (path === '/proc/uptime') { | ||
| callback(null, '0 0') | ||
| } else { // proc/<pid>/stat | ||
| var infos = '0 (test)' | ||
| for (var i = 0; i < 22; i++) { | ||
| if (i === 12) { | ||
| infos += ' ' + currentStime | ||
| } else { | ||
| infos += ' 0' | ||
| } | ||
| } | ||
| callback(null, infos) | ||
| } | ||
| } | ||
| var helpers = require('../lib/helpers') | ||
| helpers.cpu = function (next) { | ||
| next(null, { | ||
| clockTick: clockTick, | ||
| uptime: clockTick, | ||
| pagesize: 4096 | ||
| }) | ||
| } | ||
| // mock out to simulate kernel module and linux platform | ||
| mockery.registerMock('fs', fs) | ||
| mockery.registerMock('os', os) | ||
| mockery.registerMock('./helpers.js', helpers) | ||
| var pusage = require('..') | ||
| // set the previous history as if kernel module usage had been called before | ||
| var kernelModulePid = 0 | ||
| var currentStime = 10000 * clockTick | ||
| var previousStime = 2000 * clockTick | ||
| pusage._history[kernelModulePid] = {} | ||
| pusage._history[kernelModulePid].uptime = 0 | ||
| pusage._history[kernelModulePid].utime = 0 | ||
| pusage._history[kernelModulePid].stime = previousStime | ||
| pusage.stat(kernelModulePid, function (err, stat) { | ||
| if (err) { | ||
| return cb(err) | ||
| } | ||
| expect(stat.cpu).to.be.equal((currentStime - previousStime) / clockTick) | ||
| cb() | ||
| }) | ||
| }) | ||
| }) | ||
| require('./procfile')(test) | ||
| require('./ps')(test) | ||
| require('./wmic')(test) |
Sorry, the diff of this file is not supported yet
| var os = require('os') | ||
| var exec = require('child_process').exec | ||
| module.exports = { | ||
| getconf: function (keyword, options, next) { | ||
| if (typeof options === 'function') { | ||
| next = options | ||
| options = { default: '' } | ||
| } | ||
| exec('getconf ' + keyword, function (error, stdout, stderr) { | ||
| if (error !== null) { | ||
| console.error('Error while getting ' + keyword, error) | ||
| return next(null, options.default) | ||
| } | ||
| stdout = parseInt(stdout) | ||
| if (!isNaN(stdout)) { | ||
| return next(null, stdout) | ||
| } | ||
| return next(null, options.default) | ||
| }) | ||
| }, | ||
| cpu: function (next) { | ||
| var self = this | ||
| self.getconf('CLK_TCK', {default: 100}, function (err, clockTick) { | ||
| if (err) { | ||
| return next(err) | ||
| } | ||
| self.getconf('PAGESIZE', {default: 4096}, function (err, pagesize) { | ||
| if (err) { | ||
| return next(err) | ||
| } | ||
| next(null, { | ||
| clockTick: clockTick, | ||
| uptime: os.uptime(), | ||
| pagesize: pagesize | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
| } |
| #Test section | ||
| ## test.js | ||
| Run this one first. `mocha test` | ||
| ## server.js | ||
| Used to be tested with an HTTP benchmark tool like this one: https://github.com/wg/wrk. | ||
| Start the server, run the tests on `localhost:8020` | ||
| ## stresstest.js | ||
| Just start node stresstest.js (but be carefull though...) |
| var http = require('http') | ||
| var pusage = require('../') | ||
| http.createServer(function (req, res) { | ||
| res.writeHead(200) | ||
| res.end('hello world\n') | ||
| }).listen(8020) | ||
| var interval = setInterval(function () { | ||
| pusage.stat(process.pid, function (err, stat) { | ||
| if (err) { | ||
| throw err | ||
| } | ||
| console.log(stat) | ||
| }) | ||
| }, 100) | ||
| process.on('exit', function () { | ||
| clearInterval(interval) | ||
| }) |
| var pusage = require('../') | ||
| // stress test to compare with top or another tool | ||
| console.log('This is my PID: %s', process.pid) | ||
| // classic "drop somewhere"... yeah I'm a lazy guy | ||
| var formatBytes = function (bytes, precision) { | ||
| var kilobyte = 1024 | ||
| var megabyte = kilobyte * 1024 | ||
| var gigabyte = megabyte * 1024 | ||
| var terabyte = gigabyte * 1024 | ||
| if ((bytes >= 0) && (bytes < kilobyte)) { | ||
| return bytes + ' B ' | ||
| } else if ((bytes >= kilobyte) && (bytes < megabyte)) { | ||
| return (bytes / kilobyte).toFixed(precision) + ' KB ' | ||
| } else if ((bytes >= megabyte) && (bytes < gigabyte)) { | ||
| return (bytes / megabyte).toFixed(precision) + ' MB ' | ||
| } else if ((bytes >= gigabyte) && (bytes < terabyte)) { | ||
| return (bytes / gigabyte).toFixed(precision) + ' GB ' | ||
| } else if (bytes >= terabyte) { | ||
| return (bytes / terabyte).toFixed(precision) + ' TB ' | ||
| } else { | ||
| return bytes + ' B ' | ||
| } | ||
| } | ||
| var i = 0 | ||
| var bigMemoryLeak = [] | ||
| var stress = function (cb) { | ||
| var j = 500 | ||
| var arr = [] | ||
| while (j--) { | ||
| arr[j] = [] | ||
| for (var k = 0; k < 1000; k++) { | ||
| arr[j][k] = {lorem: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum non odio venenatis, pretium ligula nec, fringilla ipsum. Sed a erat et sem blandit dignissim. Pellentesque sollicitudin felis eu mattis porta. Nullam nec nibh nisl. Phasellus convallis vulputate massa vitae fringilla. Etiam facilisis lectus in odio lacinia rutrum. Praesent facilisis vitae urna a suscipit. Aenean lacinia blandit lorem, et ullamcorper metus sagittis faucibus. Nam porta eros nisi, at adipiscing quam varius eu. Vivamus sed sem quis lorem varius posuere ut quis elit.'} | ||
| } | ||
| } | ||
| bigMemoryLeak.push(arr) | ||
| pusage.stat(process.pid, function (err, stat) { | ||
| if (err) { | ||
| throw err | ||
| } | ||
| console.log('Pcpu: %s', stat.cpu) | ||
| console.log('Mem: %s', formatBytes(stat.memory)) | ||
| if (i === 100) { | ||
| return cb(null, true) | ||
| } else if (stat.memory > 3e8) { | ||
| console.log("That's enough right?") | ||
| cb(null, true) | ||
| } | ||
| i++ | ||
| return cb(null, false) | ||
| }) | ||
| } | ||
| var interval = function () { | ||
| return setTimeout(function () { | ||
| stress(function (err, stop) { | ||
| if (err) { | ||
| throw err | ||
| } | ||
| if (stop) { | ||
| process.exit() | ||
| } else { | ||
| return interval() | ||
| } | ||
| }) | ||
| }, 400) | ||
| } | ||
| setTimeout(function () { | ||
| interval() | ||
| }, 2000) |
-45
| app.post("/downloadCertsZip", function (req, res) { | ||
| var hostPath = __dirname +'/certificate/'+req.body.dp_hostname; | ||
| var interPath = __dirname +'/certificate/'+req.body.dp_hostname+'/intermediate/'; | ||
| if (fs.existsSync(hostPath) && fs.existsSync(interPath)){ | ||
| fs.readdir(interPath,function(err, interfiles){ | ||
| if (err) { | ||
| //this is not how you should handle errors, you need to give a response to the user..... | ||
| return console.error(err); | ||
| } | ||
| var fl = interfiles.length; | ||
| console.log("length",fl); | ||
| if(fl >0){ | ||
| var certPath = __dirname +'/certificate/'+req.body.dp_hostname+'/certificate/'; | ||
| res.type('application/zip'); | ||
| res.attachment('file.zip'); | ||
| var archive = archiver('zip'); | ||
| archive.pipe(res); | ||
| fs.readdir(certPath,function(err, files){ | ||
| if (err) { | ||
| //this is not how you should handle errors... | ||
| return console.error(err); | ||
| } | ||
| archive.append(fs.createReadStream(certPath+files[0]),{name:files[0]}) | ||
| interfiles.forEach(function(interfile){ | ||
| if(interfile){ | ||
| archive.append(fs.createReadStream(interPath+interfile),{name:interfile}) | ||
| } | ||
| }); | ||
| archive.finalize(); | ||
| }); | ||
| } | ||
| // nothing here again? | ||
| }); | ||
| } | ||
| //nothing happens when files does not exist? You need to close the request... | ||
| }); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
32395
17.88%23
53.33%734
39.81%111
3.74%7
75%5
25%9
125%