glutenfree
Version:
A profiler/loganalyzer for nginx/Cetrea Aw.
196 lines (181 loc) • 7.26 kB
JavaScript
// Generated by CoffeeScript 1.6.3
var argv, cluster, dgram, file, fs, http, input, ioc, ios, iosock, lsocket, me, mode, optimist, port, reporting, reports, slaves, util, uuid, winston, _;
dgram = require("dgram");
optimist = require("optimist");
winston = require("winston");
http = require("http");
uuid = require("node-uuid");
util = require("util");
_ = require("underscore");
fs = require("fs");
cluster = require("cluster");
argv = optimist.usage("Usage: $0 -i [inputfile] -s [server] -p [port] -u [user] -w [password] -n [workers] -t [time] -h \n\nThe Profiler (Pr) can operate in two modes; master and slave.\nThe master-mode is entered by providing an input file (the statistics structure outputted from a LogAnalyzer then ArgumentGenerator w glutenfree targeting).\nThe slave-mode is entered into by default (when no parameters are given).").alias("i", "input").describe("i", "Input file").describe("s", "The hostname of the server (Aw) to connect to.").alias("s", "server").describe("p", "The port of the server (Aw) to connect to.").alias("p", "port").describe("u", "Username (used in basic-auth)").alias("u", "user").describe("w", "Password (used in basic-auth)").alias("w", "password").alias("h", "help").describe("t", "Time to wait between requests (in ms)").alias("t", "time").describe("h", "Display usage.").alias("n", "workers").describe("n", "Number of workers per slave. Default is number of CPUs on slave machine. Set value to force higher concurrency.").argv;
if (argv.h != null) {
optimist.showHelp();
process.exit(0);
}
mode = argv.i != null ? "master" : "slave";
slaves = {};
if (mode === "master") {
winston.info("Pr in MASTER mode");
if (!((argv.s != null) && (argv.p != null) && (argv.u != null) && (argv.w != null))) {
optimist.showHelp();
winston.error("Missing server, port, user or password. Please provide all four.");
process.exit(0);
}
file = argv.i[0] === "/" ? argv.i : "./" + argv.i;
input = require(file);
port = Math.floor((Math.random() * 1000) + 3000);
ios = require('socket.io').listen(port, {
log: false
});
winston.info("control interface running on port " + port);
ios.sockets.on("connection", function(socket) {
socket.on("enslave", function(slave) {
if (slaves[socket.id] == null) {
winston.info("" + slave.id + " enslaved");
slaves[socket.id] = _.extend(slave, {
socket: socket
});
return socket.emit("profile", {
targeting: input,
server: argv.s,
port: argv.p,
user: argv.u,
password: argv.w,
workerCount: argv.n,
pause: argv.t
});
}
});
socket.on("report", function(hits) {
var csv, slave;
slave = slaves[socket.id];
winston.debug("sample", hits[0]);
csv = _.reduce(hits, function(memo, hit) {
return memo += _.map(_.values(hit), function(value) {
if (typeof value === "string" && value.indexOf(",") > 0) {
return "\"" + value + "\"";
} else {
return value;
}
}).join(",") + "\n";
}, "");
return fs.appendFile("" + slave.id + ".csv", csv, function(err) {
if (err != null) {
return winston.error("Could not write results to file.", err);
} else {
return winston.info("Results from " + slave.id + " appended to file.");
}
});
});
return socket.on("disconnect", function() {
var slave;
slave = slaves[socket.id];
delete slaves[socket.id];
return winston.info("slave " + slave.id + " freed");
});
});
setInterval(function() {
var client, message;
message = new Buffer("GLUTENFREE|Pr(MASTER)|ONLINE|" + port);
client = dgram.createSocket("udp4");
return client.send(message, 0, message.length, 5354, "224.0.0.251", function(err, bytes) {
return client.close();
});
}, 5000);
} else {
ioc = require("socket.io-client");
winston.info("Pr in SLAVE mode");
me = {
id: uuid.v4(),
state: "AVAILABLE"
};
lsocket = dgram.createSocket("udp4");
iosock = {};
reports = [];
reporting = {};
lsocket.on("message", function(msg, rinfo) {
var interfaceport, protocol, report, state, type, _ref;
if (me.state === "AVAILABLE") {
_ref = ("" + msg).split("|"), protocol = _ref[0], type = _ref[1], state = _ref[2], interfaceport = _ref[3];
report = function(iosock, interval) {
var payload;
if ((reports != null) && reports.length > 0) {
payload = _.flatten(_.pluck(reports, "hits"));
iosock.emit("report", payload);
reports = [];
}
if (me.state === "SLAVED" && iosock) {
return setTimeout(function() {
return report(iosock, interval);
}, interval);
}
};
iosock = ioc.connect("http://" + rinfo.address + ":" + interfaceport);
iosock.emit("enslave", me);
iosock.on("connect", function() {
me.state = "SLAVED";
return winston.info("enslaved");
});
iosock.on("profile", function(order) {
var targeting, w, workerCount, _fn, _i;
targeting = order.targeting;
cluster.setupMaster({
exec: "" + __dirname + "/ProfilerWorker"
});
workerCount = order.workerCount || require("os").cpus().length;
_fn = function(w) {
return cluster.fork();
};
for (w = _i = 1; 1 <= workerCount ? _i <= workerCount : _i >= workerCount; w = 1 <= workerCount ? ++_i : --_i) {
_fn(w);
}
cluster.on("exit", function(worker) {
var _ref1;
if (me.state === "SLAVED") {
winston.warn("worker (" + (worker != null ? (_ref1 = worker.process) != null ? _ref1.pid : void 0 : void 0) + ") died - forking new");
return cluster.fork();
}
});
cluster.on("online", function(worker) {
worker.on("message", function(msg) {
var rprt;
switch (msg.subject) {
case "report":
rprt = msg.report;
return reports.push(rprt);
}
});
return setTimeout(function() {
winston.info("sending targeting to", worker.id);
return worker.send({
subject: "targeting",
clusterId: me.id,
server: order.server,
port: order.port,
user: order.user,
password: order.password,
targeting: targeting,
pause: order.pause
});
}, 1000);
});
return report(iosock, 10000);
});
return iosock.on("disconnect", function() {
me.state = "AVAILABLE";
winston.info("freed, now asking workers to die");
return cluster.disconnect();
});
}
});
lsocket.on("listening", function() {
var address, multicastadr;
address = lsocket.address();
multicastadr = "224.0.0.251";
winston.info("Pr SLAVE listening for MASTERs at " + address.address + ":" + address.port + " (multicast at " + multicastadr + ")");
return lsocket.addMembership(multicastadr);
});
lsocket.bind(5354);
}