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