mirror of
https://github.com/samsonjs/kwikemon.git
synced 2026-03-25 09:05:51 +00:00
first commit
This commit is contained in:
commit
131deb7c06
8 changed files with 253 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules
|
||||
27
Readme.md
Normal file
27
Readme.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# kwik-e-mon
|
||||
|
||||
Monitor one-off tasks on your servers.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
npm install -g kwikemon
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
I can't think of a concise example use of the command line tool. Here's how it works:
|
||||
|
||||
- you continuously pipe data to `kwikemon <name of thing you are watching>` on stdin
|
||||
- every time a full line of text is received on stdin it becomes the new status for <name of thing you are watching>
|
||||
- there's a simple web server, `kwikemond`, that serves up these monitors in a big list or individually
|
||||
|
||||
This is very much a work in progress and as the functionality is fleshed out this readme will improve as well.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2013 Sami Samhuri <sami@samhuri.net>
|
||||
|
||||
[MIT license](http://sjs.mit-license.org)
|
||||
|
||||
10
bin/kwikemon
Executable file
10
bin/kwikemon
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var kwikemon = require('../kwikemon.js')
|
||||
, name = process.argv[2]
|
||||
;
|
||||
|
||||
process.stdin.pipe(kwikemon.createWriter(name));
|
||||
process.stdin.on('end', function() {
|
||||
process.exit(0);
|
||||
});
|
||||
8
bin/kwikemond
Executable file
8
bin/kwikemond
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var server = require('../server.js')
|
||||
, port = process.argv[2]
|
||||
, host = process.argv[3]
|
||||
;
|
||||
|
||||
server.start(port, host);
|
||||
76
kwikemon.js
Normal file
76
kwikemon.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2013 Sami Samhuri
|
||||
|
||||
module.exports = {
|
||||
// read
|
||||
fetchMonitor: fetchMonitor
|
||||
, fetchMonitors: fetchMonitors
|
||||
|
||||
// write
|
||||
, monitor: monitor
|
||||
, createWriter: createWriter
|
||||
};
|
||||
|
||||
var redis = require('redis').createClient()
|
||||
, LineEmitter = require('./line_emitter.js')
|
||||
;
|
||||
|
||||
function monitor(name, text, options) {
|
||||
console.log(name,'=',text)
|
||||
options = options || {};
|
||||
if (typeof options == 'function') {
|
||||
options = { cb: options };
|
||||
}
|
||||
var key = 'kwikemon:monitor:' + name
|
||||
, timeout = options.timeout || 86400
|
||||
;
|
||||
console.log('set',key,text)
|
||||
redis.set(key, text, function(err, status) {
|
||||
console.log('set',key,text)
|
||||
if (err) throw err;
|
||||
if (timeout >= 0) {
|
||||
redis.expire(key, timeout);
|
||||
}
|
||||
redis.sadd('kwikemon:monitors', name, function(err, status) {
|
||||
if (options.cb) options.cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createWriter(name) {
|
||||
var le = new LineEmitter();
|
||||
le.on('line', function(line) {
|
||||
monitor(name, line);
|
||||
});
|
||||
return le;
|
||||
}
|
||||
|
||||
function fetchMonitor(name, cb) {
|
||||
redis.get('kwikemon:monitor:' + name, cb);
|
||||
}
|
||||
|
||||
function fetchMonitors(cb) {
|
||||
var monitors = {}
|
||||
, i = 0
|
||||
, n
|
||||
, checkIfDone = function() {
|
||||
i += 1;
|
||||
if (i == n) cb(null, monitors);
|
||||
}
|
||||
;
|
||||
redis.smembers('kwikemon:monitors', function(err, names) {
|
||||
if (err) return cb(err);
|
||||
n = names.length;
|
||||
names.forEach(function(name) {
|
||||
fetchMonitor(name, function(err, text) {
|
||||
if (err) {
|
||||
// missing? probably don't care
|
||||
}
|
||||
else {
|
||||
monitors[name] = text;
|
||||
}
|
||||
checkIfDone();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
54
line_emitter.js
Normal file
54
line_emitter.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2013 Sami Samhuri
|
||||
|
||||
module.exports = LineEmitter;
|
||||
|
||||
var stream = require('stream')
|
||||
, Transform = stream.Transform
|
||||
;
|
||||
|
||||
function LineEmitter(options) {
|
||||
Transform.call(this, options);
|
||||
this._buffer = [];
|
||||
}
|
||||
|
||||
LineEmitter.prototype = Object.create(Transform.prototype, {
|
||||
constructor: { value: LineEmitter }
|
||||
});
|
||||
|
||||
LineEmitter.prototype._transform = function(chunk, encoding, done) {
|
||||
// check for a newline
|
||||
var split = -1;
|
||||
for (var i = 0; i < chunk.length; i++) {
|
||||
if (chunk[i] === 10) { // '\n'
|
||||
split = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// buffer until we see a newline
|
||||
if (split == -1) {
|
||||
this._buffer.push(chunk);
|
||||
}
|
||||
|
||||
// construct & emit the line, buffering the rest of the next line
|
||||
else {
|
||||
this._buffer.push(chunk.slice(0, split));
|
||||
var line = Buffer.concat(this._buffer).toString();
|
||||
this.emit('line', line);
|
||||
|
||||
// skip over newline
|
||||
this._buffer = [chunk.slice(split + 1)];
|
||||
}
|
||||
|
||||
// no actual transform
|
||||
this.push(chunk);
|
||||
done();
|
||||
}
|
||||
|
||||
LineEmitter.prototype._flush = function(cb) {
|
||||
var line = Buffer.concat(this._buffer).toString();
|
||||
if (line) {
|
||||
this.emit('line', line);
|
||||
}
|
||||
this._buffer = [];
|
||||
}
|
||||
20
package.json
Normal file
20
package.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{ "name": "kwikemon"
|
||||
, "version": "0.0.1"
|
||||
, "description": "monitor one-off things on your servers"
|
||||
, "author": "Sami Samhuri <sami@samhuri.net>"
|
||||
, "license": "MIT"
|
||||
, "repository": "https://github.com/samsonjs/kwikemon"
|
||||
, "keywords": [ "monitor", "server", "watch", "one-off", "task" ]
|
||||
, "main": "kwikemon.js"
|
||||
, "bin": {
|
||||
"kwikemon": "./bin/kwikemon"
|
||||
, "kwikemond": "./bin/kwikemond"
|
||||
}
|
||||
, "dependencies": {
|
||||
"paramify": "0.0.x"
|
||||
, "redis": "0.8.x"
|
||||
}
|
||||
, "engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
}
|
||||
57
server.js
Normal file
57
server.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2013 Sami Samhuri
|
||||
|
||||
module.exports = {
|
||||
create: create
|
||||
, start: start
|
||||
, stop: stop
|
||||
};
|
||||
|
||||
var http = require('http')
|
||||
, paramify = require('paramify')
|
||||
, kwikemon = require('./kwikemon.js')
|
||||
, _server
|
||||
;
|
||||
|
||||
function create() {
|
||||
return http.createServer(handleRequest);
|
||||
}
|
||||
|
||||
function start(port, host) {
|
||||
port = port || 1111;
|
||||
host = host || '127.0.0.1';
|
||||
_server = create();
|
||||
_server.listen(port, host);
|
||||
console.log('kwikemond listening on ' + host + ':' + port);
|
||||
return _server;
|
||||
}
|
||||
|
||||
function stop() {
|
||||
_server.close();
|
||||
_server = null;
|
||||
}
|
||||
|
||||
function handleRequest(req, res) {
|
||||
var name = req.url.replace(/^\//, '');
|
||||
if (name) {
|
||||
kwikemon.fetchMonitor(name, function(err, text) {
|
||||
if (err) {
|
||||
res.end('error: ' + (err.message || 'unknown'));
|
||||
return;
|
||||
}
|
||||
res.end(text);
|
||||
});
|
||||
}
|
||||
// all
|
||||
else {
|
||||
kwikemon.fetchMonitors(function(err, monitors) {
|
||||
if (err) {
|
||||
res.end('error: ' + (err.message || 'unknown'));
|
||||
return;
|
||||
}
|
||||
Object.keys(monitors).sort().forEach(function(name) {
|
||||
res.write(name + ': ' + monitors[name] + '\n');
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue