log.io-push
Version:
based on log.io :Realtime log monitoring in your browser
491 lines (411 loc) • 14.5 kB
JavaScript
// Generated by CoffeeScript 1.4.0
/* Log.io Log Server
Relays inbound log messages to web clients
LogServer receives log messages via TCP:
"+log|my_stream|my_server_host|info|this is a log message\r\n"
Announce a node, optionally with stream associations
"+node|my_server_host\r\n"
"+node|my_server_host|my_stream1,my_stream2,my_stream3\r\n"
Announce a stream, optionally with node associations
"+stream|my_stream1\r\n"
"+stream|my_stream1|my_server_host1,my_host_server2\r\n"
Remove a node or stream
"-node|my_server_host1\r\n"
"-stream|stream2\r\n"
WebServer listens for events emitted by LogServer and
forwards them to web clients via socket.io
# Usage:
logServer = new LogServer port: 28777
webServer = new WebServer logServer, port: 28778
webServer.run()
*/
(function() {
var LogNode, LogServer, LogStream, WebServer, events, express, fs, http, https, io, net, winston, _LogObject,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__slice = [].slice;
fs = require('fs');
net = require('net');
http = require('http');
https = require('https');
io = require('socket.io');
events = require('events');
winston = require('winston');
express = require('express');
_LogObject = (function() {
_LogObject.prototype._type = 'object';
_LogObject.prototype._pclass = function() {};
_LogObject.prototype._pcollection = function() {};
function _LogObject(logServer, name, _pairs) {
var pname, _i, _len;
this.logServer = logServer;
this.name = name;
if (_pairs == null) {
_pairs = [];
}
this.logServer.emit("add_" + this._type, this);
this.pairs = {};
this.pclass = this._pclass();
this.pcollection = this._pcollection();
for (_i = 0, _len = _pairs.length; _i < _len; _i++) {
pname = _pairs[_i];
this.addPair(pname);
}
}
_LogObject.prototype.addPair = function(pname) {
var pair;
if (!(pair = this.pairs[pname])) {
if (!(pair = this.pcollection[pname])) {
pair = this.pcollection[pname] = new this.pclass(this.logServer, pname);
}
pair.pairs[this.name] = this;
this.pairs[pname] = pair;
return this.logServer.emit("add_" + this._type + "_pair", this, pname);
}
};
_LogObject.prototype.remove = function() {
var name, p, _ref, _results;
this.logServer.emit("remove_" + this._type, this);
_ref = this.pairs;
_results = [];
for (name in _ref) {
p = _ref[name];
_results.push(delete p.pairs[this.name]);
}
return _results;
};
_LogObject.prototype.toDict = function() {
var name, obj;
return {
name: this.name,
pairs: (function() {
var _ref, _results;
_ref = this.pairs;
_results = [];
for (name in _ref) {
obj = _ref[name];
_results.push(name);
}
return _results;
}).call(this)
};
};
return _LogObject;
})();
LogNode = (function(_super) {
__extends(LogNode, _super);
function LogNode() {
return LogNode.__super__.constructor.apply(this, arguments);
}
LogNode.prototype._type = 'node';
LogNode.prototype._pclass = function() {
return LogStream;
};
LogNode.prototype._pcollection = function() {
return this.logServer.logStreams;
};
return LogNode;
})(_LogObject);
LogStream = (function(_super) {
__extends(LogStream, _super);
function LogStream() {
return LogStream.__super__.constructor.apply(this, arguments);
}
LogStream.prototype._type = 'stream';
LogStream.prototype._pclass = function() {
return LogNode;
};
LogStream.prototype._pcollection = function() {
return this.logServer.logNodes;
};
return LogStream;
})(_LogObject);
/*
LogServer listens for TCP connections. It parses & validates
inbound TCP messages, and emits events.
*/
LogServer = (function(_super) {
__extends(LogServer, _super);
function LogServer(config) {
var _ref, _ref1;
if (config == null) {
config = {};
}
this._flush = __bind(this._flush, this);
this._receive = __bind(this._receive, this);
this.host = config.host, this.port = config.port;
this._log = (_ref = config.logging) != null ? _ref : winston;
this._delimiter = (_ref1 = config.delimiter) != null ? _ref1 : '\r\n';
this.logNodes = {};
this.logStreams = {};
}
LogServer.prototype.run = function() {
var _this = this;
this.listener = net.createServer(function(socket) {
socket._buffer = '';
socket.on('data', function(data) {
return _this._receive(data, socket);
});
socket.on('error', function() {
return _this._tearDown(socket);
});
return socket.on('close', function() {
return _this._tearDown(socket);
});
});
return this.listener.listen(this.port, this.host);
};
LogServer.prototype._tearDown = function(socket) {
this._log.error('Lost TCP connection...');
if (socket.node) {
this._removeNode(socket.node.name);
return delete socket.node;
}
};
LogServer.prototype._receive = function(data, socket) {
var part;
part = data.toString();
socket._buffer += part;
this._log.debug("Received TCP message: " + part);
if (socket._buffer.indexOf(this._delimiter >= 0)) {
return this._flush(socket);
}
};
LogServer.prototype._flush = function(socket) {
var msg, msgs, _i, _j, _len, _ref, _results;
socket.pause();
_ref = socket._buffer.split(this._delimiter), msgs = 2 <= _ref.length ? __slice.call(_ref, 0, _i = _ref.length - 1) : (_i = 0, []), socket._buffer = _ref[_i++];
socket.resume();
_results = [];
for (_j = 0, _len = msgs.length; _j < _len; _j++) {
msg = msgs[_j];
_results.push(this._handle(socket, msg));
}
return _results;
};
LogServer.prototype._handle = function(socket, msg) {
var args, mtype, _ref;
this._log.debug("Handling message: " + msg);
_ref = msg.split('|'), mtype = _ref[0], args = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
switch (mtype) {
case '+log':
return this._newLog.apply(this, args);
case '+node':
return this._addNode.apply(this, args);
case '+stream':
return this._addStream.apply(this, args);
case '-node':
return this._removeNode.apply(this, args);
case '-stream':
return this._removeStream.apply(this, args);
case '+bind':
return this._bindNode.apply(this, [socket].concat(__slice.call(args)));
default:
return this._log.error("Invalid TCP message: " + msg);
}
};
LogServer.prototype._addNode = function(nname, snames) {
if (snames == null) {
snames = '';
}
return this.__add(nname, snames, this.logNodes, LogNode, 'node');
};
LogServer.prototype._addStream = function(sname, nnames) {
if (nnames == null) {
nnames = '';
}
return this.__add(sname, nnames, this.logStreams, LogStream, 'stream');
};
LogServer.prototype._removeNode = function(nname) {
return this.__remove(nname, this.logNodes, 'node');
};
LogServer.prototype._removeStream = function(sname) {
return this.__remove(sname, this.logStreams, 'stream');
};
LogServer.prototype._newLog = function() {
var logLevel, message, nname, node, sname, stream;
sname = arguments[0], nname = arguments[1], logLevel = arguments[2], message = 4 <= arguments.length ? __slice.call(arguments, 3) : [];
message = message.join('|');
this._log.debug("Log message: (" + sname + ", " + nname + ", " + logLevel + ") " + message);
node = this.logNodes[nname] || this._addNode(nname, sname);
stream = this.logStreams[sname] || this._addStream(sname, nname);
return this.emit('new_log', stream, node, logLevel, message);
};
LogServer.prototype.__add = function(name, pnames, _collection, _objClass, objName) {
var obj, p, _i, _len, _results;
this._log.info("Adding " + objName + ": " + name + " (" + pnames + ")");
pnames = pnames.split(',');
obj = _collection[name] = _collection[name] || new _objClass(this, name, pnames);
_results = [];
for (_i = 0, _len = pnames.length; _i < _len; _i++) {
p = pnames[_i];
if (!obj.pairs[p]) {
_results.push(obj.addPair(p));
}
}
return _results;
};
LogServer.prototype.__remove = function(name, _collection, objType) {
var obj;
if (obj = _collection[name]) {
this._log.info("Removing " + objType + ": " + name);
obj.remove();
return delete _collection[name];
}
};
LogServer.prototype._bindNode = function(socket, obj, nname) {
var node;
if (node = this.logNodes[nname]) {
this._log.info("Binding node '" + nname + "' to TCP socket");
socket.node = node;
return this._ping(socket);
}
};
LogServer.prototype._ping = function(socket) {
var _this = this;
if (socket.node) {
socket.write('ping');
return setTimeout((function() {
return _this._ping(socket);
}), 2000);
}
};
return LogServer;
})(events.EventEmitter);
/*
WebServer relays LogServer events to web clients via socket.io.
*/
WebServer = (function() {
function WebServer(logServer, config) {
var app, _ref, _ref1, _ref2;
this.logServer = logServer;
this.host = config.host, this.port = config.port, this.auth = config.auth;
_ref = this.logServer, this.logNodes = _ref.logNodes, this.logStreams = _ref.logStreams;
this.restrictSocket = (_ref1 = config.restrictSocket) != null ? _ref1 : '*:*';
this._log = (_ref2 = config.logging) != null ? _ref2 : winston;
app = this._buildServer(config);
this.http = this._createServer(config, app);
}
WebServer.prototype._buildServer = function(config) {
var app, ips, staticPath, _ref,
_this = this;
app = express();
if (this.auth != null) {
app.use(express.basicAuth(this.auth.user, this.auth.pass));
}
if (config.restrictHTTP) {
ips = new RegExp(config.restrictHTTP.join('|'));
app.all('/', function(req, res, next) {
if (!req.ip.match(ips)) {
return res.send(403, "Your IP (" + req.ip + ") is not allowed.");
}
return next();
});
}
staticPath = (_ref = config.staticPath) != null ? _ref : __dirname + '/../';
return app.use(express["static"](staticPath));
};
WebServer.prototype._createServer = function(config, app) {
if (config.ssl) {
return https.createServer({
key: fs.readFileSync(config.ssl.key),
cert: fs.readFileSync(config.ssl.cert)
}, app);
} else {
return http.createServer(app);
}
};
WebServer.prototype.run = function() {
var _emit, _on,
_this = this;
this._log.info('Starting Log.io Web Server...');
this.logServer.run();
io = io.listen(this.http.listen(this.port, this.host));
io.set('log level', 1);
io.set('origins', this.restrictSocket);
this.listener = io.sockets;
_on = function() {
var args, _ref;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return (_ref = _this.logServer).on.apply(_ref, args);
};
_emit = function(_event, msg) {
_this._log.debug("Relaying: " + _event);
return _this.listener.emit(_event, msg);
};
_on('add_node', function(node) {
return _emit('add_node', node.toDict());
});
_on('add_stream', function(stream) {
return _emit('add_stream', stream.toDict());
});
_on('add_stream_pair', function(stream, nname) {
return _emit('add_pair', {
stream: stream.name,
node: nname
});
});
_on('add_node_pair', function(node, sname) {
return _emit('add_pair', {
stream: sname,
node: node.name
});
});
_on('remove_node', function(node) {
return _emit('remove_node', node.toDict());
});
_on('remove_stream', function(stream) {
return _emit('remove_stream', stream.toDict());
});
_on('new_log', function(stream, node, level, message) {
_emit('ping', {
stream: stream.name,
node: node.name
});
return _this.listener["in"]("" + stream.name + ":" + node.name).emit('new_log', {
stream: stream.name,
node: node.name,
level: level,
message: message
});
});
this.listener.on('connection', function(wclient) {
var n, node, s, stream, _ref, _ref1, _ref2, _ref3;
_ref = _this.logNodes;
for (n in _ref) {
node = _ref[n];
wclient.emit('add_node', node.toDict());
}
_ref1 = _this.logStreams;
for (s in _ref1) {
stream = _ref1[s];
wclient.emit('add_stream', stream.toDict());
}
_ref2 = _this.logNodes;
for (n in _ref2) {
node = _ref2[n];
_ref3 = node.pairs;
for (s in _ref3) {
stream = _ref3[s];
wclient.emit('add_pair', {
stream: s,
node: n
});
}
}
wclient.emit('initialized');
wclient.on('watch', function(pid) {
return wclient.join(pid);
});
return wclient.on('unwatch', function(pid) {
return wclient.leave(pid);
});
});
return this._log.info('Server started, listening...');
};
return WebServer;
})();
exports.LogServer = LogServer;
exports.WebServer = WebServer;
}).call(this);