From fedebe797adcd43d18b25e973ab0aa5e73c8b059 Mon Sep 17 00:00:00 2001 From: Sebastian Hildebrandt Date: Mon, 14 Nov 2016 11:49:46 +0100 Subject: [PATCH] optimization fsStats, disksIO, networkStats --- CHANGELOG.md | 1 + lib/filesystem.js | 351 +++++++++++++++++++++++++++------------------- lib/index.js | 1 + lib/network.js | 158 ++++++++++++--------- lib/processes.js | 2 +- 5 files changed, 297 insertions(+), 216 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a00129b..874f99e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,7 @@ Other changes | Version | Date | Comment | | -------------- | -------------- | -------- | +| 3.10.1 | 2016-11-14 | optimization fsStats, disksIO, networkStats | | 3.10.0 | 2016-11-12 | added blockDevices, fixed fsSize, added file system type | | 3.9.0 | 2016-11-11 | added MAC address to networkInterfaces, fixed currentLoad | | 3.8.1 | 2016-11-04 | updated docs | diff --git a/lib/filesystem.js b/lib/filesystem.js index b3798d6..49551b5 100644 --- a/lib/filesystem.js +++ b/lib/filesystem.js @@ -132,6 +132,49 @@ exports.blockDevices = blockDevices; // -------------------------- // FS - speed +function calcFsSpeed(rx, wx) { + let result = { + rx: 0, + wx: 0, + tx: 0, + rx_sec: -1, + wx_sec: -1, + tx_sec: -1, + ms: 0 + }; + + if (_fs_speed && _fs_speed.ms) { + result.rx = rx; + result.wx = wx; + result.tx = result.rx + result.wx; + result.ms = Date.now() - _fs_speed.ms; + result.rx_sec = (result.rx - _fs_speed.bytes_read) / (result.ms / 1000); + result.wx_sec = (result.wx - _fs_speed.bytes_write) / (result.ms / 1000); + result.tx_sec = result.rx_sec + result.wx_sec; + _fs_speed.rx_sec = result.rx_sec; + _fs_speed.wx_sec = result.wx_sec; + _fs_speed.tx_sec = result.tx_sec; + _fs_speed.bytes_read = result.rx; + _fs_speed.bytes_write = result.wx; + _fs_speed.bytes_overall = result.rx + result.wx; + _fs_speed.ms = Date.now(); + _fs_speed.last_ms = result.ms; + } else { + result.rx = rx; + result.wx = wx; + result.tx = result.rx + result.wx; + _fs_speed.rx_sec = -1; + _fs_speed.wx_sec = -1; + _fs_speed.tx_sec = -1; + _fs_speed.bytes_read = result.rx; + _fs_speed.bytes_write = result.wx; + _fs_speed.bytes_overall = result.rx + result.wx; + _fs_speed.ms = Date.now(); + _fs_speed.last_ms = 0; + } + return result; +} + function fsStats(callback) { return new Promise((resolve, reject) => { @@ -142,7 +185,7 @@ function fsStats(callback) { reject(error); } - var result = { + let result = { rx: 0, wx: 0, tx: 0, @@ -152,89 +195,75 @@ function fsStats(callback) { ms: 0 }; - if (_linux) { -// exec("df -k | grep /dev/", function(error, stdout) { - exec("lsblk | grep /", function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - let fs_filter = []; - lines.forEach(function (line) { - if (line != '') { - line = line.replace(/[├─│└]+/g, "").trim().split(' '); - if (fs_filter.indexOf(line[0]) == -1) fs_filter.push(line[0]) - } - }); - - let output = fs_filter.join('|'); - exec("cat /proc/diskstats | egrep '" + output + "'", function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line != '') { - line = line.replace(/ +/g, " ").split(' '); - - result.rx += parseInt(line[5]) * 512; - result.wx += parseInt(line[9]) * 512; - } - }); - result.tx = result.rx + result.wx; - if (_fs_speed && _fs_speed.ms) { - result.ms = Date.now() - _fs_speed.ms; - result.rx_sec = (result.rx - _fs_speed.bytes_read) / (result.ms / 1000); - result.wx_sec = (result.wx - _fs_speed.bytes_write) / (result.ms / 1000); - result.tx_sec = result.rx_sec + result.wx_sec; - } else { - result.rx_sec = -1; - result.wx_sec = -1; - result.tx_sec = -1; + let rx = 0; + let wx = 0; + if ((_fs_speed && !_fs_speed.ms) || (_fs_speed && _fs_speed.ms && Date.now() - _fs_speed.ms >= 500)) { + if (_linux) { +// exec("df -k | grep /dev/", function(error, stdout) { + exec("lsblk | grep /", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + let fs_filter = []; + lines.forEach(function (line) { + if (line != '') { + line = line.replace(/[├─│└]+/g, "").trim().split(' '); + if (fs_filter.indexOf(line[0]) == -1) fs_filter.push(line[0]) } - _fs_speed.bytes_read = result.rx; - _fs_speed.bytes_write = result.wx; - _fs_speed.bytes_overall = result.rx + result.wx; - _fs_speed.ms = Date.now(); - } + }); + + let output = fs_filter.join('|'); + exec("cat /proc/diskstats | egrep '" + output + "'", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.trim(); + if (line != '') { + line = line.replace(/ +/g, " ").split(' '); + + rx += parseInt(line[5]) * 512; + wx += parseInt(line[9]) * 512; + } + }); + result = calcFsSpeed(rx, wx); + } + if (callback) { callback(result) } + resolve(result); + }) + } else { if (callback) { callback(result) } resolve(result); - }) - } else { + } + }) + } + if (_darwin) { + exec("ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n '/IOBlockStorageDriver/,/Statistics/p' | grep 'Statistics' | tr -cd '01234567890,\n' | awk -F',' '{print $3, $10}'", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.trim(); + if (line != '') { + line = line.split(' '); + + rx += parseInt(line[0]); + wx += parseInt(line[1]); + } + }); + result = calcFsSpeed(rx, wx); + } if (callback) { callback(result) } resolve(result); - } - }) - } - if (_darwin) { - exec("ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n '/IOBlockStorageDriver/,/Statistics/p' | grep 'Statistics' | tr -cd '01234567890,\n' | awk -F',' '{print $3, $10}'", function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line != '') { - line = line.split(' '); - - result.rx += parseInt(line[0]); - result.wx += parseInt(line[1]); - } - }); - result.tx = result.rx + result.wx; - if (_fs_speed && _fs_speed.ms) { - result.ms = Date.now() - _fs_speed.ms; - result.rx_sec = (result.rx - _fs_speed.bytes_read) / (result.ms / 1000); - result.wx_sec = (result.wx - _fs_speed.bytes_write) / (result.ms / 1000); - result.tx_sec = result.rx_sec + result.wx_sec; - } else { - result.rx_sec = -1; - result.wx_sec = -1; - result.tx_sec = -1; - } - _fs_speed.bytes_read = result.rx; - _fs_speed.bytes_write = result.wx; - _fs_speed.bytes_overall = result.rx + result.wx; - _fs_speed.ms = Date.now(); - } - if (callback) { callback(result) } - resolve(result); - }) + }) + } + } else { + result.ms = _fs_speed.last_ms; + result.rx = _fs_speed.bytes_read; + result.wx = _fs_speed.bytes_write; + result.tx = _fs_speed.bytes_read + _fs_speed.bytes_write; + result.rx_sec = _fs_speed.rx_sec; + result.wx_sec = _fs_speed.wx_sec; + result.tx_sec = _fs_speed.tx_sec; + if (callback) { callback(result) } + resolve(result); } }); }); @@ -242,6 +271,46 @@ function fsStats(callback) { exports.fsStats = fsStats; +function calcDiskIO(rIO, wIO) { + let result = { + rIO: 0, + wIO: 0, + tIO: 0, + rIO_sec: -1, + wIO_sec: -1, + tIO_sec: -1, + ms: 0 + }; + if (_disk_io && _disk_io.ms) { + result.rIO = rIO; + result.wIO = wIO; + result.tIO = rIO + wIO; + result.ms = Date.now() - _disk_io.ms; + result.rIO_sec = (result.rIO - _disk_io.rIO) / (result.ms / 1000); + result.wIO_sec = (result.wIO - _disk_io.wIO) / (result.ms / 1000); + result.tIO_sec = result.rIO_sec + result.wIO_sec; + _disk_io.rIO = rIO; + _disk_io.wIO = wIO; + _disk_io.rIO_sec = result.rIO_sec; + _disk_io.wIO_sec = result.wIO_sec; + _disk_io.tIO_sec = result.tIO_sec; + _disk_io.last_ms = result.ms; + _disk_io.ms = Date.now(); + } else { + result.rIO = rIO; + result.wIO = wIO; + result.tIO = rIO + wIO; + _disk_io.rIO = rIO; + _disk_io.wIO = wIO; + _disk_io.rIO_sec = -1; + _disk_io.wIO_sec = -1; + _disk_io.tIO_sec = -1; + _disk_io.last_ms = 0; + _disk_io.ms = Date.now(); + } + return result; +} + function disksIO(callback) { return new Promise((resolve, reject) => { @@ -252,7 +321,7 @@ function disksIO(callback) { reject(error); } - var result = { + let result = { rIO: 0, wIO: 0, tIO: 0, @@ -261,81 +330,67 @@ function disksIO(callback) { tIO_sec: -1, ms: 0 }; - if (_linux) { - // prints Block layer statistics for all mounted volumes - // var cmd = "for mount in `lsblk | grep / | sed -r 's/│ └─//' | cut -d ' ' -f 1`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; - // var cmd = "for mount in `lsblk | grep / | sed 's/[│└─├]//g' | awk '{$1=$1};1' | cut -d ' ' -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; - let cmd = "for mount in `lsblk | grep ' disk ' | sed 's/[│└─├]//g' | awk '{$1=$1};1' | cut -d ' ' -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; + let rIO = 0; + let wIO = 0; - exec(cmd, function (error, stdout) { - if (!error) { - let lines = stdout.split('\n'); - lines.forEach(function (line) { - // ignore empty lines - if (!line) return; + if ((_disk_io && !_disk_io.ms) || (_disk_io && _disk_io.ms && Date.now() - _disk_io.ms >= 500)) { + if (_linux) { + // prints Block layer statistics for all mounted volumes + // var cmd = "for mount in `lsblk | grep / | sed -r 's/│ └─//' | cut -d ' ' -f 1`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; + // var cmd = "for mount in `lsblk | grep / | sed 's/[│└─├]//g' | awk '{$1=$1};1' | cut -d ' ' -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; + let cmd = "for mount in `lsblk | grep ' disk ' | sed 's/[│└─├]//g' | awk '{$1=$1};1' | cut -d ' ' -f 1 | sort -u`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; - // sum r/wIO of all disks to compute all disks IO - let stats = line.split(';'); - result.rIO += parseInt(stats[0]); - result.wIO += parseInt(stats[4]); - }); - result.tIO = result.rIO + result.wIO; - if (_disk_io && _disk_io.ms) { - result.ms = Date.now() - _disk_io.ms; - result.rIO_sec = (result.rIO - _disk_io.rIO) / (result.ms / 1000); - result.wIO_sec = (result.wIO - _disk_io.wIO) / (result.ms / 1000); - result.tIO_sec = result.rIO_sec + result.wIO_sec; + exec(cmd, function (error, stdout) { + if (!error) { + let lines = stdout.split('\n'); + lines.forEach(function (line) { + // ignore empty lines + if (!line) return; + + // sum r/wIO of all disks to compute all disks IO + let stats = line.split(';'); + rIO += parseInt(stats[0]); + wIO += parseInt(stats[4]); + }); + result = calcDiskIO(rIO, wIO); + + if (callback) { callback(result) } + resolve(result); } else { - result.rIO_sec = -1; - result.wIO_sec = -1; - result.tIO_sec = -1; + if (callback) { callback(result) } + resolve(result); } - _disk_io.rIO = result.rIO; - _disk_io.wIO = result.wIO; - _disk_io.tIO = result.tIO; - _disk_io.ms = Date.now(); + }); + } + if (_darwin) { + exec("ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n '/IOBlockStorageDriver/,/Statistics/p' | grep 'Statistics' | tr -cd '01234567890,\n' | awk -F',' '{print $1, $11}'", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + lines.forEach(function (line) { + line = line.trim(); + if (line != '') { + line = line.split(' '); + rIO += parseInt(line[1]); + wIO += parseInt(line[0]); + } + }); + result = calcDiskIO(rIO, wIO); + } if (callback) { callback(result) } resolve(result); - } else { - if (callback) { callback(result) } - resolve(result); - } - }); - } - if (_darwin) { - exec("ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n '/IOBlockStorageDriver/,/Statistics/p' | grep 'Statistics' | tr -cd '01234567890,\n' | awk -F',' '{print $1, $11}'", function (error, stdout) { - if (!error) { - let lines = stdout.toString().split('\n'); - lines.forEach(function (line) { - line = line.trim(); - if (line != '') { - line = line.split(' '); - - result.rIO += parseInt(line[1]); - result.wIO += parseInt(line[0]); - } - }); - - result.tIO = result.rIO + result.wIO; - if (_disk_io && _disk_io.ms) { - result.ms = Date.now() - _disk_io.ms; - result.rIO_sec = (result.rIO - _disk_io.rIO) / (result.ms / 1000); - result.wIO_sec = (result.wIO - _disk_io.wIO) / (result.ms / 1000); - result.tIO_sec = result.rIO_sec + result.wIO_sec; - } else { - result.rIO_sec = -1; - result.wIO_sec = -1; - result.tIO_sec = -1; - } - _disk_io.rIO = result.rIO; - _disk_io.wIO = result.wIO; - _disk_io.tIO = result.tIO; - _disk_io.ms = Date.now(); - } - if (callback) { callback(result) } - resolve(result); - }) + }) + } + } else { + result.rIO = _disk_io.rIO; + result.wIO = _disk_io.wIO; + result.tIO = _disk_io.rIO + _disk_io.wIO; + result.ms = _disk_io.last_ms; + result.rIO_sec = _disk_io.rIO_sec; + result.wIO_sec = _disk_io.wIO_sec; + result.tIO_sec = _disk_io.tIO_sec; + if (callback) { callback(result) } + resolve(result); } }); }); diff --git a/lib/index.js b/lib/index.js index c964e34..1b27d6c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -81,6 +81,7 @@ // -------------------------------- // // version date comment +// 3.10.1 2016-11-14 optimization fsStats, disksIO, networkStats // 3.10.0 2016-11-12 added blockDevices, fixed fsSize, added file system type // 3.9.0 2016-11-11 added MAC address to networkInterfaces, fixed currentLoad // 3.8.1 2016-11-04 updated docs diff --git a/lib/network.js b/lib/network.js index 29e4e0c..a08fd8d 100644 --- a/lib/network.js +++ b/lib/network.js @@ -108,7 +108,7 @@ function networkInterfaces(callback) { mac = details.mac }); let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : null; - result.push({ iface: dev, ip4: ip4, ip6: ip6, mac : mac, internal: internal }) + result.push({ iface: dev, ip4: ip4, ip6: ip6, mac: mac, internal: internal }) } } if (callback) { callback(result) } @@ -122,26 +122,43 @@ exports.networkInterfaces = networkInterfaces; // -------------------------- // NET - Speed -function calcNetworkSpeed(iface, rx, tx) { - let rx_sec = -1; - let tx_sec = -1; - let ms = 0; +function calcNetworkSpeed(iface, rx, tx, operstate) { + let result = { + iface: iface, + operstate: operstate, + rx: 0, + tx: 0, + rx_sec: -1, + tx_sec: -1, + ms: 0 + }; + if (_network[iface] && _network[iface].ms) { - ms = Date.now() - _network[iface].ms; - rx_sec = (rx - _network[iface].rx) / (ms / 1000); - tx_sec = (tx - _network[iface].tx) / (ms / 1000); + result.rx = rx; + result.tx = tx; + result.ms = Date.now() - _network[iface].ms; + result.rx_sec = (rx - _network[iface].rx) / (result.ms / 1000); + result.tx_sec = (tx - _network[iface].tx) / (result.ms / 1000); + _network[iface].rx = rx; + _network[iface].tx = tx; + _network[iface].rx_sec = result.rx_sec; + _network[iface].tx_sec = result.tx_sec; + _network[iface].ms = Date.now(); + _network[iface].last_ms = result.ms; } else { - _network[iface] = {}; + result.rx = rx; + result.tx = tx; + if (!_network[iface]) _network[iface] = {}; + _network[iface].rx = rx; + _network[iface].tx = tx; + _network[iface].rx_sec = -1; + _network[iface].tx_sec = -1; + _network[iface].ms = Date.now(); + _network[iface].last_ms = 0; } - _network[iface].rx = rx; - _network[iface].tx = tx; - _network[iface].ms = Date.now(); - return ({ - rx_sec: rx_sec, - tx_sec: tx_sec, - ms: ms - }) + return result; } + function networkStats(iface, callback) { // fallback - if only callback is given @@ -171,63 +188,70 @@ function networkStats(iface, callback) { ms: 0 }; - let cmd, lines, stats, speed; + let operstate = 'unknown'; + let rx = 0; + let tx = 0; - if (_linux) { - if (fs.existsSync('/sys/class/net/' + iface)) { - cmd = - "cat /sys/class/net/" + iface + "/operstate; " + - "cat /sys/class/net/" + iface + "/statistics/rx_bytes; " + - "cat /sys/class/net/" + iface + "/statistics/tx_bytes; "; - exec(cmd, function (error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - result.operstate = lines[0].trim(); - result.rx = parseInt(lines[1]); - result.tx = parseInt(lines[2]); + let cmd, lines, stats; + if (!_network[iface] || (_network[iface] && !_network[iface].ms) || (_network[iface] && _network[iface].ms && Date.now() - _network[iface].ms >= 500)) { + if (_linux) { + if (fs.existsSync('/sys/class/net/' + iface)) { + cmd = + "cat /sys/class/net/" + iface + "/operstate; " + + "cat /sys/class/net/" + iface + "/statistics/rx_bytes; " + + "cat /sys/class/net/" + iface + "/statistics/tx_bytes; "; + exec(cmd, function (error, stdout) { + if (!error) { + lines = stdout.toString().split('\n'); + operstate = lines[0].trim(); + rx = parseInt(lines[1]); + tx = parseInt(lines[2]); - speed = calcNetworkSpeed(iface, result.rx, result.tx); + result = calcNetworkSpeed(iface, rx, tx, operstate); - result.rx_sec = speed.rx_sec; - result.tx_sec = speed.tx_sec; - result.ms = speed.ms; - } - if (callback) { callback(result) } - resolve(result); - }); - } else { - if (callback) { callback(result) } - resolve(result); - } - } - if (_darwin) { - cmd = "ifconfig " + iface + " | grep 'status'"; - exec(cmd, function (error, stdout) { - result.operstate = (stdout.toString().split(':')[1] || '').trim(); - result.operstate = (result.operstate || '').toLowerCase(); - result.operstate = (result.operstate == 'active' ? 'up' : (result.operstate == 'inactive' ? 'down' : 'unknown')); - cmd = "netstat -bI " + iface; - exec(cmd, function (error, stdout) { - if (!error) { - lines = stdout.toString().split('\n'); - // if there is less than 2 lines, no information for this interface was found - if (lines.length > 1 && lines[1].trim() != '') { - // skip header line - // use the second line because it is tied to the NIC instead of the ipv4 or ipv6 address - stats = lines[1].replace(/ +/g, " ").split(' '); - result.rx = parseInt(stats[6]); - result.tx = parseInt(stats[9]); - - speed = calcNetworkSpeed(iface, result.rx, result.tx); - - result.rx_sec = speed.rx_sec; - result.tx_sec = speed.tx_sec; } - } + if (callback) { callback(result) } + resolve(result); + }); + } else { if (callback) { callback(result) } resolve(result); + } + } + if (_darwin) { + cmd = "ifconfig " + iface + " | grep 'status'"; + exec(cmd, function (error, stdout) { + result.operstate = (stdout.toString().split(':')[1] || '').trim(); + result.operstate = (result.operstate || '').toLowerCase(); + result.operstate = (result.operstate == 'active' ? 'up' : (result.operstate == 'inactive' ? 'down' : 'unknown')); + cmd = "netstat -bI " + iface; + exec(cmd, function (error, stdout) { + if (!error) { + lines = stdout.toString().split('\n'); + // if there is less than 2 lines, no information for this interface was found + if (lines.length > 1 && lines[1].trim() != '') { + // skip header line + // use the second line because it is tied to the NIC instead of the ipv4 or ipv6 address + stats = lines[1].replace(/ +/g, " ").split(' '); + rx = parseInt(stats[6]); + tx = parseInt(stats[9]); + + result = calcNetworkSpeed(iface, rx, tx, operstate); + } + } + if (callback) { callback(result) } + resolve(result); + }); }); - }); + } + } else { + result.rx = _network[iface].rx; + result.tx = _network[iface].tx; + result.rx_sec = _network[iface].rx_sec; + result.tx_sec = _network[iface].tx_sec; + result.ms = _network[iface].last_ms; + if (callback) { callback(result) } + resolve(result); } }); }); diff --git a/lib/processes.js b/lib/processes.js index 761bbe2..0a58433 100644 --- a/lib/processes.js +++ b/lib/processes.js @@ -84,7 +84,7 @@ function getLoad() { } if (_linux) { let now = Date.now() - _current_cpu.ms; - if (now >= 1000) { + if (now >= 500) { _current_cpu.ms = Date.now(); exec("cat /proc/stat | grep 'cpu '", function (error, stdout) { if (!error) {