Added Docker support

This commit is contained in:
Sebastian Hildebrandt 2016-08-17 14:51:21 +02:00
parent fbeade938b
commit 21677bcca5
3 changed files with 349 additions and 5 deletions

View File

@ -36,6 +36,15 @@ si.cpu()
```
## News and Changes
### Latest Activity
- Version 3.1.0: added [Docker][docker-url] support. Now you can scan your docker containers and get their stats
- Version 3.0.0: added DisksIO - overall diskIO and IOPS values for all mounted volumes
Here all changes more detailed:
### Major (breaking) Changes - Version 3
- works only with [node.js][nodejs-url] **v4.0.0** and above (using now internal ES6 promise function, arrow functions, ...)
@ -52,7 +61,10 @@ si.cpu()
New Functions
- `disksIO`: returns overall diskIO and IOPS values for all mounted volumes
- `dockerContainers`: returns a list of all docker containers (new in version 3.1)
- `dockerContainerStats`: returns statistics for a specific docker container (new in version 3.1)
- `dockerAll`: returns a list of all docker containers including their stats (new in version 3.1)
- `disksIO`: returns overall diskIO and IOPS values for all mounted volumes (new in version 3.0)
Bug Fixes
@ -137,7 +149,8 @@ This library is splitted in several sections:
8. Processes
9. Users
10. Internet
11. GetAll
11. Docker
12. GetAll
### Function Reference and OS Support
@ -258,6 +271,28 @@ This library is splitted in several sections:
| - status | X | X | status code |
| - ms | X | X | response time in ms |
| si.inetLatency(host, cb) | X | X | response-time (ms) to external resource<br>host parameter is optional (default 8.8.8.8)|
| si.dockerContainers(all, cb) | X | X | returns array of active/all docker containers |
| - [0].id | X | X | ID of container |
| - [0].name | X | X | name of container |
| - [0].image | X | X | name of image |
| - [0].imageID | X | X | ID of image |
| - [0].command | X | X | command |
| - [0].created | X | X | creation time |
| - [0].state | X | X | created, running, exited |
| - [0].ports | X | X | array of ports |
| - [0].mounts | X | X | array of mounts |
| si.dockerContainerStats(id, cb) | X | X | statistics for a specific container |
| - id | X | X | Container ID |
| - mem_usage | X | X | memory usage in bytes |
| - mem_limit | X | X | memory limit (max mem) in bytes |
| - mem_percent | X | X | memory usage in percent |
| - cpu_percent | X | X | cpu usage in percent |
| - pids | X | X | number of processes |
| - netIO.rx | X | X | received bytes via network |
| - netIO.wx | X | X | sent bytes via network |
| - blockIO.r | X | X | bytes read from BlockIO |
| - blockIO.w | X | X | bytes written to BlockIO |
| si.dockerAll(cb) | X | X | list of all containers including their stats<br>in one single array |
| si.getStaticData(cb) | X | X | all static data at once |
| si.getDynamicData(srv,iface,cb) | X | X | all dynamic data at once |
| si.getAllData(srv,iface,cb) | X | X | all data at once |
@ -319,6 +354,7 @@ I am happy to discuss any comments and suggestions. Please feel free to contact
| Version | Date | Comment |
| -------------- | -------------- | -------- |
| 3.1.0 | 2016-08-18 | added Docker stats |
| 3.0.1 | 2016-08-17 | Bug-Fix disksIO, users, updated docs |
| 3.0.0 | 2016-08-03 | new major version 3.0 |
| 2.0.5 | 2016-03-02 | changed .gitignore |
@ -406,6 +442,7 @@ All other trademarks are the property of their respective owners.
[npmjs-license]: https://img.shields.io/npm/l/systeminformation.svg?style=flat-square
[nodejs-url]: https://nodejs.org/en/
[docker-url]: https://www.docker.com/
[daviddm-img]: https://img.shields.io/david/sebhildebrandt/systeminformation.svg?style=flat-square
[daviddm-url]: https://david-dm.org/sebhildebrandt/systeminformation

View File

@ -27,7 +27,8 @@
// 8. Processes
// 9. Users/Sessions
// 10. Internet
// 11. GetAll - get all data
// 11. Docker
// 12. GetAll - get all data
//
// ==================================================================================
//
@ -78,6 +79,7 @@
// --------------------------------
//
// version date comment
// 3.1.0 2016-08-18 added docker stats
// 3.0.1 2016-08-17 Bug-Fix disksIO, users, updated docs
// 3.0.0 2016-08-03 new major version 3.0
// 2.0.5 2016-02-22 some more tiny correction ...
@ -119,6 +121,7 @@ var _cpu_speed = '0.00';
var _fs_speed = {};
var _disk_io = {};
var _default_iface;
var _docker_container_stats = {};
const NOT_SUPPORTED = 'not supported';
@ -338,6 +341,14 @@ function osInfo(callback) {
exec("cat /etc/*-release", function (error, stdout) {
if (!error) {
/**
* @namespace
* @property {string} DISTRIB_ID
* @property {string} NAME
* @property {string} DISTRIB_RELEASE
* @property {string} VERSION_ID
* @property {string} DISTRIB_CODENAME
*/
var release = {};
var lines = stdout.toString().split('\n');
lines.forEach(function (line) {
@ -1929,7 +1940,295 @@ function inetLatency(host, callback) {
exports.inetLatency = inetLatency;
// ----------------------------------------------------------------------------------
// 11. get all
// 11. Docker
// ----------------------------------------------------------------------------------
// --------------------------
// get containers (parameter all: get also inactive/exited containers)
function dockerContainers(all, callback) {
function inContainers(containers, id) {
let filtered = containers.filter(obj => {
/**
* @namespace
* @property {string} Id
*/
return (obj.Id && (obj.Id == id))
});
return (filtered.length > 0);
}
// fallback - if only callback is given
if (isFunction(all) && !callback) {
callback = all;
all = false;
}
all = all || false;
var result = [];
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) { callback(NOT_SUPPORTED) }
reject(error);
}
let cmd = "curl --unix-socket /var/run/docker.sock http:/containers/json" + (all ? "?all=1": "");
exec(cmd, function (error, stdout) {
if (!error) {
try {
let jsonString = stdout.toString();
var docker_containers = JSON.parse(jsonString);
// console.log(docker_containers)
if (docker_containers && Object.prototype.toString.call(docker_containers) === '[object Array]' && docker_containers.length > 0) {
docker_containers.forEach(function (element) {
/**
* @namespace
* @property {string} Id
* @property {string} Name
* @property {string} Image
* @property {string} ImageID
* @property {string} Command
* @property {number} Created
* @property {string} State
* @property {Array} Names
* @property {Array} Ports
* @property {Array} Mounts
*/
if (element.Names && Object.prototype.toString.call(element.Names) === '[object Array]' && element.Names.length > 0) {
element.Name = element.Names[0].replace(/^\/|\/$/g, '');
}
result.push({
id: element.Id,
name: element.Name,
image: element.Image,
imageID: element.ImageID,
command: element.Command,
created: element.Created,
state: element.State,
ports: element.Ports,
mounts: element.Mounts,
// hostconfig: element.HostConfig,
// network: element.NetworkSettings
})
});
}
} catch (err) {
}
}
// GC in _docker_container_stats
for (var key in _docker_container_stats) {
if (_docker_container_stats.hasOwnProperty(key)) {
if (!inContainers(docker_containers, key)) delete _docker_container_stats[key];
}
}
if (callback) { callback(result) }
resolve(result);
});
});
});
}
exports.dockerContainers = dockerContainers;
// --------------------------
// helper functions for calculation of docker stats
function docker_calcCPUPercent(cpu_stats, id) {
/**
* @namespace
* @property {object} cpu_usage
* @property {number} cpu_usage.total_usage
* @property {number} system_cpu_usage
* @property {object} cpu_usage
* @property {Array} cpu_usage.percpu_usage
*/
var cpuPercent = 0.0;
// calculate the change for the cpu usage of the container in between readings
var cpuDelta = cpu_stats.cpu_usage.total_usage - (_docker_container_stats[id] && _docker_container_stats[id].prev_CPU ? _docker_container_stats[id].prev_CPU : 0);
// calculate the change for the entire system between readings
var systemDelta = cpu_stats.system_cpu_usage - (_docker_container_stats[id] && _docker_container_stats[id].prev_system ? _docker_container_stats[id].prev_system : 0);
if (systemDelta > 0.0 && cpuDelta > 0.0) {
cpuPercent = (cpuDelta / systemDelta) * cpu_stats.cpu_usage.percpu_usage.length * 100.0;
}
if (!_docker_container_stats[id]) _docker_container_stats[id] = {};
_docker_container_stats[id].prev_CPU = cpu_stats.cpu_usage.total_usage;
_docker_container_stats[id].prev_system = cpu_stats.system_cpu_usage;
return cpuPercent
}
function docker_calcNetworkIO(networks) {
var rx;
var tx;
for (var key in networks) {
// skip loop if the property is from prototype
if (!networks.hasOwnProperty(key)) continue;
/**
* @namespace
* @property {number} rx_bytes
* @property {number} tx_bytes
*/
var obj = networks[key];
rx =+ obj.rx_bytes;
tx =+ obj.tx_bytes;
}
return {
rx: rx,
tx: tx
}
}
function docker_calcBlockIO(blkio_stats) {
let result = {
r: 0,
w: 0
};
/**
* @namespace
* @property {Array} io_service_bytes_recursive
*/
if (blkio_stats && blkio_stats.io_service_bytes_recursive && Object.prototype.toString.call( blkio_stats.io_service_bytes_recursive ) === '[object Array]' && blkio_stats.io_service_bytes_recursive.length > 0) {
blkio_stats.io_service_bytes_recursive.forEach( function(element) {
/**
* @namespace
* @property {string} op
* @property {number} value
*/
if (element.op && element.op.toLowerCase() == 'read' && element.value) {
result.r += element.value;
}
if (element.op && element.op.toLowerCase() == 'write' && element.value) {
result.w += element.value;
}
})
}
return result;
}
// --------------------------
// container Stats (for one container)
function dockerContainerStats(containerID, callback) {
containerID = containerID || '';
var result = {
id: containerID,
mem_usage: 0,
mem_limit: 0,
mem_percent: 0,
cpu_percent: 0,
pids: 0,
netIO: {
rx: 0,
wx: 0
},
blockIO: {
r: 0,
w: 0
}
};
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) { callback(NOT_SUPPORTED) }
reject(error);
}
if (containerID) {
let cmd = "curl --unix-socket /var/run/docker.sock http:/containers/" + containerID + "/stats?stream=0";
exec(cmd, function (error, stdout) {
if (!error) {
let jsonString = stdout.toString();
try {
let stats = JSON.parse(jsonString);
/**
* @namespace
* @property {Object} memory_stats
* @property {number} memory_stats.usage
* @property {number} memory_stats.limit
* @property {Object} cpu_stats
* @property {Object} pids_stats
* @property {number} pids_stats.current
* @property {Object} networks
* @property {Object} blkio_stats
*/
//console.log(stats);
if (!stats.message) {
result.mem_usage = (stats.memory_stats && stats.memory_stats.usage ? stats.memory_stats.usage : 0);
result.mem_limit = (stats.memory_stats && stats.memory_stats.limit ? stats.memory_stats.limit : 0);
result.mem_percent = (stats.memory_stats && stats.memory_stats.usage && stats.memory_stats.limit ? stats.memory_stats.usage / stats.memory_stats.limit * 100.0 : 0);
result.cpu_percent = (stats.cpu_stats ? docker_calcCPUPercent(stats.cpu_stats, containerID) : 0);
result.pids = (stats.pids_stats && stats.pids_stats.current ? stats.pids_stats.current : 0);
if (stats.networks) result.netIO = docker_calcNetworkIO(stats.networks);
if (stats.blkio_stats)result.blockIO = docker_calcBlockIO(stats.blkio_stats);
}
} catch (err) {
}
}
if (callback) { callback(result) }
resolve(result);
});
} else {
if (callback) { callback(result) }
resolve(result);
}
});
});
}
exports.dockerContainerStats = dockerContainerStats;
function dockerAll(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) { callback(NOT_SUPPORTED) }
reject(error);
}
dockerContainers(true).then(result => {
if (result && Object.prototype.toString.call( result ) === '[object Array]' && result.length > 0) {
var l = result.length;
result.forEach( function(element) {
dockerContainerStats(element.id).then(res => {
// include stats in array
element.mem_usage = res.mem_usage;
element.mem_limit = res.mem_limit;
element.mem_percent = res.mem_percent;
element.cpu_percent = res.cpu_percent;
element.pids = res.pids;
element.netIO = res.netIO;
element.blockIO = res.blockIO;
// all done??
l -= 1;
if (l == 0) {
if (callback) { callback(result) }
resolve(result);
}
})
})
} else {
if (callback) { callback(result) }
resolve(result);
}
})
});
});
}
exports.dockerAll = dockerAll;
// ----------------------------------------------------------------------------------
// 12. get all
// ----------------------------------------------------------------------------------
// --------------------------
@ -2023,6 +2322,13 @@ function getDynamicData(srv, iface, callback) {
// get time
data.time = time();
/**
* @namespace
* @property {Object} versions
* @property {string} versions.node
* @property {string} versions.v8
*/
data.node = process.versions.node;
data.v8 = process.versions.v8;

View File

@ -28,7 +28,8 @@
"network connections",
"processes",
"users",
"internet"
"internet",
"docker"
],
"repository": {
"type": "git",