Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit cae9b6fdbf776814f45920601887879425c1ac51 @jbrisbin committed
Showing with 447 additions and 0 deletions.
  1. 0 README.md
  2. +48 −0 index.js
  3. +309 −0 optparse.js
  4. +8 −0 package.json
  5. +82 −0 viewer.js
0 README.md
No changes.
48 index.js
@@ -0,0 +1,48 @@
+var util = require('util');
+
+var Log = function(bucket) {
+
+ var db = require('riak-js').getClient({debug:false});
+ var bucketName = bucket || 'node-rlog';
+
+ function formatMsg(msg) {
+ var _msg = [];
+ for (i in msg) {
+ if (typeof msg[i] === 'object') {
+ _msg.push(util.inspect(msg[i]));
+ } else {
+ _msg.push(msg[i]);
+ }
+ }
+ return _msg.join(' ');
+ }
+
+ function now() {
+ return new Date().getTime();
+ }
+
+ function save(level, msg) {
+ db.save(bucketName, now(), msg, { level: level });
+ }
+
+ return {
+ debug: function() {
+ save('debug', formatMsg(arguments));
+ },
+ info: function() {
+ save('info', formatMsg(arguments));
+ },
+ warn: function() {
+ save('warn', formatMsg(arguments));
+ },
+ error: function() {
+ save('error', formatMsg(arguments));
+ }
+ }
+}
+
+module.exports = {
+ getLogger: function(b) {
+ return new Log(b);
+ }
+}
309 optparse.js
@@ -0,0 +1,309 @@
+// Optparse.js 1.0.2 - Option Parser for Javascript
+//
+// Copyright (c) 2009 Johan Dahlberg
+//
+// See README.md for license.
+//
+var optparse = {};
+try{ optparse = exports } catch(e) {}; // Try to export the lib for node.js
+(function(self) {
+var VERSION = '1.0.2';
+var LONG_SWITCH_RE = /^--\w/;
+var SHORT_SWITCH_RE = /^-\w/;
+var NUMBER_RE = /^(0x[A-Fa-f0-9]+)|([0-9]+\.[0-9]+)|(\d+)$/;
+var DATE_RE = /^\d{4}-(0[0-9]|1[0,1,2])-([0,1,2][0-9]|3[0,1])$/;
+var EMAIL_RE = /^([0-9a-zA-Z]+([_.-]?[0-9a-zA-Z]+)*@[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$/;
+var EXT_RULE_RE = /(\-\-[\w_-]+)\s+([\w\[\]_-]+)|(\-\-[\w_-]+)/;
+var ARG_OPTIONAL_RE = /\[(.+)\]/;
+
+// The default switch argument filter to use, when argument name doesnt match
+// any other names.
+var DEFAULT_FILTER = '_DEFAULT';
+var PREDEFINED_FILTERS = {};
+
+// The default switch argument filter. Parses the argument as text.
+function filter_text(value) {
+ return value;
+}
+
+// Switch argument filter that expects an integer, HEX or a decimal value. An
+// exception is throwed if the criteria is not matched.
+// Valid input formats are: 0xFFFFFFF, 12345 and 1234.1234
+function filter_number(value) {
+ var m = NUMBER_RE(value);
+ if(m == null) throw OptError('Expected a number representative');
+ if(m[1]) {
+ // The number is in HEX format. Convert into a number, then return it
+ return parseInt(m[1], 16);
+ } else {
+ // The number is in regular- or decimal form. Just run in through
+ // the float caster.
+ return parseFloat(m[2] || m[3]);
+ }
+};
+
+// Switch argument filter that expects a Date expression. The date string MUST be
+// formated as: "yyyy-mm-dd" An exception is throwed if the criteria is not
+// matched. An DATE object is returned on success.
+function filter_date(value) {
+ var m = DATE_RE(value);
+ if(m == null) throw OptError('Expected a date representation in the "yyyy-mm-dd" format.');
+ return new Date(parseInt(m[0]), parseInt(m[1]), parseInt(m[2]));
+};
+
+// Switch argument filter that expects an email address. An exception is throwed
+// if the criteria doesn`t match.
+function filter_email(value) {
+ var m = EMAIL_RE(value);
+ if(m == null) throw OptError('Excpeted an email address.');
+ return m[1];
+}
+
+// Register all predefined filters. This dict is used by each OptionParser
+// instance, when parsing arguments. Custom filters can be added to the parser
+// instance by calling the "add_filter" -method.
+PREDEFINED_FILTERS[DEFAULT_FILTER] = filter_text;
+PREDEFINED_FILTERS['TEXT'] = filter_text;
+PREDEFINED_FILTERS['NUMBER'] = filter_number;
+PREDEFINED_FILTERS['DATE'] = filter_date;
+PREDEFINED_FILTERS['EMAIL'] = filter_email;
+
+// Buildes rules from a switches collection. The switches collection is defined
+// when constructing a new OptionParser object.
+function build_rules(filters, arr) {
+ var rules = [];
+ for(var i=0; i<arr.length; i++) {
+ var r = arr[i], rule
+ if(!contains_expr(r)) throw OptError('Rule MUST contain an option.');
+ switch(r.length) {
+ case 1:
+ rule = build_rule(filters, r[0]);
+ break;
+ case 2:
+ var expr = LONG_SWITCH_RE(r[0]) ? 0 : 1;
+ var alias = expr == 0 ? -1 : 0;
+ var desc = alias == -1 ? 1 : -1;
+ rule = build_rule(filters, r[alias], r[expr], r[desc]);
+ break;
+ case 3:
+ rule = build_rule(filters, r[0], r[1], r[2]);
+ break;
+ default:
+ case 0:
+ continue;
+ }
+ rules.push(rule)
+ }
+ return rules;
+}
+
+// Builds a rule with specified expression, short style switch and help. This
+// function expects a dict with filters to work correctly.
+//
+// Return format:
+// name The name of the switch.
+// short The short style switch
+// long The long style switch
+// decl The declaration expression (the input expression)
+// desc The optional help section for the switch
+// optional_arg Indicates that switch argument is optional
+// filter The filter to use when parsing the arg. An
+// <<undefined>> value means that the switch does
+// not take anargument.
+function build_rule(filters, short, expr, desc) {
+ var optional, filter;
+ var m = expr.match(EXT_RULE_RE);
+ if(m == null) throw OptError('The switch is not well-formed.');
+ var long = m[1] || m[3];
+ if(m[2] != undefined) {
+ // A switch argument is expected. Check if the argument is optional,
+ // then find a filter that suites.
+ var optional_match = ARG_OPTIONAL_RE(m[2]);
+ var filter_name = optional_match === null ? m[2] : optional_match[1];
+ optional = optional_match !== null;
+ filter = filters[filter_name];
+ if(filter === undefined) filter = filters[DEFAULT_FILTER];
+ }
+ return {
+ name: long.substr(2),
+ short: short,
+ long: long,
+ decl: expr,
+ desc: desc,
+ optional_arg: optional,
+ filter: filter
+ }
+}
+
+// Loop's trough all elements of an array and check if there is valid
+// options expression within. An valid option is a token that starts
+// double dashes. E.G. --my_option
+function contains_expr(arr) {
+ if(!arr || !arr.length) return false;
+ var l = arr.length;
+ while(l-- > 0) if(LONG_SWITCH_RE(arr[l])) return true;
+ return false;
+}
+
+// Extends destination object with members of source object
+function extend(dest, src) {
+ var result = dest;
+ for(var n in src) {
+ result[n] = src[n];
+ }
+ return result;
+}
+
+// Appends spaces to match specified number of chars
+function spaces(arg1, arg2) {
+ var l, builder = [];
+ if(arg1.constructor === Number) {
+ l = arg1;
+ } else {
+ if(arg1.length == arg2) return arg1;
+ l = arg2 - arg1.length;
+ builder.push(arg1);
+ }
+ while(l-- > 0) builder.push(' ');
+ return builder.join('');
+}
+
+// Create a new Parser object that can be used to parse command line arguments.
+//
+//
+function Parser(rules) {
+ return new OptionParser(rules);
+}
+
+// Creates an error object with specified error message.
+function OptError(msg) {
+ return new function() {
+ this.msg = msg;
+ this.toString = function() {
+ return this.msg;
+ }
+ }
+}
+
+function OptionParser(rules) {
+ this.banner = 'Usage: [Options]';
+ this.options_title = 'Available options:'
+ this._rules = rules;
+ this._halt = false;
+ this.filters = extend({}, PREDEFINED_FILTERS);
+ this.on_args = {};
+ this.on_switches = {};
+ this.on_halt = function() {};
+ this.default_handler = function() {};
+}
+
+OptionParser.prototype = {
+
+ // Adds args and switchs handler.
+ on: function(value, fn) {
+ if(value.constructor === Function ) {
+ this.default_handler = value;
+ } else if(value.constructor === Number) {
+ this.on_args[value] = fn;
+ } else {
+ this.on_switches[value] = fn;
+ }
+ },
+
+ // Adds a custom filter to the parser. It's possible to override the
+ // default filter by passing the value "_DEFAULT" to the ´´name´´
+ // argument. The name of the filter is automatically transformed into
+ // upper case.
+ filter: function(name, fn) {
+ this.filters[name.toUpperCase()] = fn;
+ },
+
+ // Parses specified args. Returns remaining arguments.
+ parse: function(args) {
+ var result = [], callback;
+ var rules = build_rules(this.filters, this._rules);
+ var tokens = args.concat([]);
+ while((token = tokens.shift()) && this._halt == false) {
+ if(LONG_SWITCH_RE(token) || SHORT_SWITCH_RE(token)) {
+ var arg = undefined;
+ // The token is a long or a short switch. Get the corresponding
+ // rule, filter and handle it. Pass the switch to the default
+ // handler if no rule matched.
+ for(var i = 0; i < rules.length; i++) {
+ var rule = rules[i];
+ if(rule.long == token || rule.short == token) {
+ if(rule.filter !== undefined) {
+ arg = tokens.shift();
+ if(!LONG_SWITCH_RE(arg) && !SHORT_SWITCH_RE(arg)) {
+ try {
+ arg = rule.filter(arg);
+ } catch(e) {
+ throw OptError(token + ': ' + e.toString());
+ }
+ } else if(rule.optional_arg) {
+ tokens.unshift(arg);
+ } else {
+ throw OptError('Expected switch argument.');
+ }
+ }
+ callback = this.on_switches[rule.name];
+ if (!callback) callback = this.on_switches['*'];
+ if(callback) callback.apply(this, [rule.name, arg]);
+ break;
+ }
+ }
+ if(i == rules.length) this.default_handler.apply(this, [token]);
+ } else {
+ // Did not match long or short switch. Parse the token as a
+ // normal argument.
+ callback = this.on_args[result.length];
+ result.push(token);
+ if(callback) callback.apply(this, [token]);
+ }
+ }
+ return this._halt ? this.on_halt.apply(this, []) : result;
+ },
+
+ // Returns an Array with all defined option rules
+ options: function() {
+ return build_rules(this.filters, this._rules);
+ },
+
+ // Add an on_halt callback if argument ´´fn´´ is specified. on_switch handlers can
+ // call instance.halt to abort the argument parsing. This can be useful when
+ // displaying help or version information.
+ halt: function(fn) {
+ this._halt = fn === undefined
+ if(fn) this.on_halt = fn;
+ },
+
+ // Returns a string representation of this OptionParser instance.
+ toString: function() {
+ var builder = [this.banner, '', this.options_title],
+ shorts = false, longest = 0, rule;
+ var rules = build_rules(this.filters, this._rules);
+ for(var i = 0; i < rules.length; i++) {
+ rule = rules[i];
+ // Quick-analyze the options.
+ if(rule.short) shorts = true;
+ if(rule.decl.length > longest) longest = rule.decl.length;
+ }
+ for(var i = 0; i < rules.length; i++) {
+ var text;
+ rule = rules[i];
+ if(shorts) {
+ if(rule.short) text = spaces(2) + rule.short + ', ';
+ else text = spaces(6);
+ }
+ text += spaces(rule.decl, longest) + spaces(3);
+ text += rule.desc;
+ builder.push(text);
+ }
+ return builder.join('\n');
+ }
+}
+
+self.VERSION = VERSION;
+self.OptionParser = OptionParser;
+
+})(optparse);
8 package.json
@@ -0,0 +1,8 @@
+{
+ "name": "node-rlog",
+ "description": "Remote logging to Riak",
+ "version": "0.1.0",
+ "author": "J. Brisbin <jon@jbrisbin.com>",
+ "main": "./index.js",
+ "bin": { "noderlog": "./viewer" }
+}
82 viewer.js
@@ -0,0 +1,82 @@
+var sys = require('sys');
+var util = require('util')
+var optparse = require('./optparse');
+var db = require('riak-js').getClient({debug:false});
+
+var options = {
+ bucket: null,
+ level: 'debug,info,warn,error',
+ regex: false
+};
+
+var SWITCHES = [
+ ['-d', '--debug', 'Show DEBUG level and up log lines'],
+ ['-i', '--info', 'Show INFO level and up log lines'],
+ ['-w', '--warn', 'Show WARN level and up log lines'],
+ ['-e', '--error', 'Show ERROR level log lines'],
+ ['-b', '--bucket BUCKET', 'The log bucket to look in'],
+ ['-r', '--regex REGEX', 'A regular expression to apply to log lines'],
+ ['-h', '--help', 'Print this help']
+];
+var parser = new optparse.OptionParser(SWITCHES);
+parser.banner = 'Usage: rlog [options]';
+
+parser.on('help', function() {
+ console.log(parser.toString());
+});
+parser.on('bucket', function(name, value) {
+ options.bucket = value;
+});
+parser.on('regex', function(name, value) {
+ options.regex = value;
+});
+parser.on('debug', function() {
+ options.level = 'debug,info,warn,error';
+});
+parser.on('info', function() {
+ options.level = 'info,warn,error';
+});
+parser.on('warn', function() {
+ options.level = 'warn,error';
+});
+parser.on('error', function() {
+ options.level = 'error';
+});
+parser.parse(process.argv);
+
+var mapFunc = function(v, b, arg) {
+ var data = v.values[0].data;
+ var meta = v.values[0].metadata;
+ if (new RegExp("(.*)" + meta['X-Riak-Meta']['X-Riak-Meta-Level'] + "(.*)").test(arg.level)) {
+ //ejsLog('/tmp/mapred.log', 'arg: ' + JSON.stringify(arg));
+ if (!arg.regex || new RegExp(arg.regex).test(data)) {
+ return [
+ [v.key, meta['X-Riak-Meta']['X-Riak-Meta-Level'], data]
+ ];
+ }
+ }
+ return [];
+}
+
+if (options.bucket) {
+ db.add(options.bucket)
+ .map(mapFunc, {level: options.level, regex: options.regex})
+ .run(function(err, data) {
+ if (err) {
+ console.log("ERROR: " + err.message);
+ } else {
+ for (i in data.sort(function(x, y) {
+ if (x[0] > y[0]) {
+ return 1;
+ } else if (x[0] < y[0]) {
+ return -1;
+ } else {
+ return 0;
+ }
+ })) {
+ var date = new Date(parseInt(data[i][0])).toISOString();
+ console.log(date, "[" + data[i][1].toUpperCase() + "]", data[i][2]);
+ }
+ }
+ });
+}

0 comments on commit cae9b6f

Please sign in to comment.
Something went wrong with that request. Please try again.