plex-web-downloader/node_modules/cluster/lib/plugins/stats.js

251 lines
6.4 KiB
JavaScript

/*!
* Cluster - stats
* Copyright (c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs = require('fs')
, Log = require('log')
, repl = require('./repl')
, utils = require('../utils')
, os = require('os');
/**
* Enable stat tracking with the given `options`.
*
* Options:
*
* - `connections` enable connection statistics
* - `requests` enable request statistics
* - `lightRequests` enable light-weight request statistics
*
* Real-time applications should utilize `lightRequests` for reporting
* when possible, although less data is available.
*
* TODO: UDP
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function(options){
options = options || {};
stats.enableInWorker = options.connections || options.requests;
function stats(master){
var server = master.server;
master.connectionStats = options.connections;
master.requestStats = options.requests;
master.lightRequestStats = options.lightRequests;
// worker stats
if (master.isWorker) {
var id = 0;
// connections
if (options.connections) {
server.on('connection', function(sock){
var data = { remoteAddress: sock.remoteAddress };
master.call('reportStats', 'connection', data);
sock.on('close', function(){
master.call('reportStats', 'disconnection', data);
});
});
}
// light-weight requests
if (options.lightRequests) {
utils.unshiftListener(server, 'request', function(req, res){
master.call('reportStats', 'light request', res.id = ++id);
var end = res.end;
res.end = function(str, encoding){
res.end = end;
res.end(str, encoding);
master.call('reportStats', 'light request complete', res.id);
};
});
}
// requests
if (options.requests) {
utils.unshiftListener(server, 'request', function(req, res){
var data = {
remoteAddress: req.socket.remoteAddress
, headers: req.headers
, httpVersion: req.httpVersion
, method: req.method
, url: req.url
, id: ++id
};
master.call('reportStats', 'request', data);
var end = res.end;
res.end = function(str, encoding){
res.end = end;
res.end(str, encoding);
master.call('reportStats', 'request complete', data);
};
});
}
// master stats
} else {
master.stats = {
start: new Date
, restarts: 0
, workersSpawned: 0
, workersKilled: 0
};
// 0.4.x
if (os) {
master.stats.totalmem = os.totalmem();
master.stats.freemem = os.freemem();
}
// worker stats
master.reportStats = function(worker, type, data){
master.emit('client ' + type, worker, data);
switch (type) {
case 'connection':
worker.stats.connectionsTotal++;
worker.stats.connectionsActive++;
break;
case 'disconnection':
worker.stats.connectionsActive--;
break;
case 'light request':
case 'request':
worker.stats.requestsTotal++;
}
};
// total workers spawned
master.on('worker', function(worker){
++master.stats.workersSpawned;
worker.stats = {
start: new Date
, connectionsTotal: 0
, connectionsActive: 0
, requestsTotal: 0
};
});
// total worker deaths
master.on('worker killed', function(worker){
++master.stats.workersKilled;
});
// restarting
master.on('restarting', function(data){
++master.stats.restarts;
data.stats = master.stats;
});
// restart
master.on('restart', function(data){
master.stats = data.stats;
master.stats.start = new Date(master.stats.start);
});
}
}
return stats;
};
/**
* REPL statistics command.
*/
repl.define('stats', function(master, sock){
var active = master.children.length
, total = master.stats.workersSpawned
, deaths = master.stats.workersKilled
, restarts = master.stats.restarts;
// master stats
sock.title('Master');
if (os) sock.row('os', os.type() + ' ' + os.release());
sock.row('state', master.state);
sock.row('started', master.stats.start.toUTCString());
sock.row('uptime', utils.formatDateRange(new Date, master.stats.start));
sock.row('restarts', restarts);
sock.row('workers', active);
sock.row('deaths', deaths);
// resources
if (os) {
sock.title('Resources');
sock.row('load average', os.loadavg().map(function(n){ return n.toFixed(2); }).join(' '));
sock.row('cores utilized', active + ' / ' + os.cpus().length);
var free = utils.formatBytes(master.stats.freemem);
var total = utils.formatBytes(master.stats.totalmem);
sock.row('memory at boot (free / total)', free + ' / ' + total);
var free = utils.formatBytes(os.freemem());
var total = utils.formatBytes(os.totalmem());
sock.row('memory now (free / total)', free + ' / ' + total);
}
// worker stats
sock.title('Workers');
// connections
if (master.connectionStats) {
sock.row('connections total', sum(master.children, 'connectionsTotal'));
sock.row('connections active', sum(master.children, 'connectionsActive'));
}
// requests
if (master.requestStats) {
sock.row('requests total', sum(master.children, 'requestsTotal'));
}
master.children.forEach(function(worker){
var stats = ''
, piped = [];
// uptime
stats += utils.formatDateRange(new Date, worker.stats.start);
// connections
if (master.connectionStats) {
piped.push(worker.stats.connectionsActive);
piped.push(worker.stats.connectionsTotal);
}
// requests
if (master.requestStats) {
piped.push(worker.stats.requestsTotal);
}
if (piped.length) {
stats += ' ' + piped.join('\033[90m|\033[0m');
}
sock.row(worker.id, stats);
});
sock.write('\n');
}, 'Display server statistics');
/**
* Return sum of each `prop` in `arr`.
*
* @param {Array} arr
* @param {String} prop
* @return {Number}
* @api private
*/
function sum(arr, prop){
return arr.reduce(function(sum, obj){
return sum + obj.stats[prop];
}, 0);
};