first stab. 'log.info(...)'
This commit is contained in:
commit
aa166b2f46
5 changed files with 302 additions and 0 deletions
47
README.md
Normal file
47
README.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
Bunyan -- a JSON Logger for node.js servers.
|
||||
|
||||
Server logs should be structured. JSON's a good format. Let's do that: a log
|
||||
record is one line of `JSON.stringify`'d output. Let's also specify some common
|
||||
names for the requisite and common fields for a log record (see below).
|
||||
|
||||
Also: log4j is way more than you need.
|
||||
|
||||
|
||||
# Usage
|
||||
|
||||
// hi.js
|
||||
var Logger = require('bunyan');
|
||||
var log = new Logger({facility: "myapp", level: "info"});
|
||||
log.info("hi");
|
||||
|
||||
$ node hi.js
|
||||
{"time":"2012-01-30T00:56:25.842Z","facility":"myapp","level":2,"message":"hi"}
|
||||
|
||||
$ node hi.js | bunyan # CLI tool to filter/pretty-print JSON logs.
|
||||
{
|
||||
"time": "2012-01-30T00:56:25.842Z",
|
||||
"facility": "myapp",
|
||||
"level": 2,
|
||||
"message": "hi"
|
||||
}
|
||||
|
||||
|
||||
# Levels
|
||||
|
||||
fatal
|
||||
error
|
||||
warn
|
||||
info
|
||||
debug
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
# Log Record Fields
|
||||
|
||||
TODO
|
||||
|
||||
# License
|
||||
|
||||
MIT.
|
||||
|
10
TODO.md
Normal file
10
TODO.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
- node-bunyan and push to priv
|
||||
- .bind or equiv with diff name
|
||||
- info's siblings
|
||||
- `bunyan` cli
|
||||
- expand set of fields
|
||||
- renderer support (i.e. repr of a restify request obj)
|
||||
- docs
|
||||
- feel out usage
|
||||
- Logger.set to mutate config or `this.fields`
|
||||
- Logger.del to remove a field
|
51
hi.js
Normal file
51
hi.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
var Logger = require('./lib/bunyan');
|
||||
var log = new Logger({facility: "myapp", level: "info"});
|
||||
console.log("log.info() is:", log.info())
|
||||
log.info("hi");
|
||||
log.info("hi", "trent");
|
||||
log.info("hi %s there", true);
|
||||
log.info({foo:"bar"}, "hi %d", 1, "two", 3);
|
||||
|
||||
|
||||
console.log("\n--\n")
|
||||
|
||||
|
||||
//console.log("\n--\n")
|
||||
//xxx = console.log;
|
||||
//var INFO = 2;
|
||||
//
|
||||
//function foo() {
|
||||
// console.log("function foo arguments:", arguments)
|
||||
//}
|
||||
//
|
||||
//function Bar() {
|
||||
// this.level = 1;
|
||||
//}
|
||||
//Bar.prototype.info = function (fields, msg) {
|
||||
// console.log("function info arguments:", arguments)
|
||||
// var msgArgs;
|
||||
// if (arguments.length === 0) { // `log.info()`
|
||||
// return (this.level <= INFO);
|
||||
// } else if (this.level > INFO) {
|
||||
// return;
|
||||
// } else if (typeof fields === 'string') { // `log.info(msg, ...)`
|
||||
// fields = null;
|
||||
// msgArgs = Array.prototype.slice.call(arguments);
|
||||
// xxx("msgArgs: ", msgArgs, arguments)
|
||||
// } else { // `log.info(fields, msg, ...)`
|
||||
// msgArgs = Array.prototype.slice.call(arguments, 1);
|
||||
// }
|
||||
// xxx("info start: arguments:", arguments.length, arguments, msgArgs)
|
||||
// //var rec = this._mkRecord(fields, INFO, msgArgs);
|
||||
// //this._emit(rec);
|
||||
//}
|
||||
//
|
||||
//
|
||||
//foo()
|
||||
//foo("one")
|
||||
//foo("one", "two")
|
||||
//
|
||||
//bar = new Bar();
|
||||
//bar.info()
|
||||
//bar.info("one")
|
||||
//bar.info("one", "two")
|
188
lib/bunyan.js
Normal file
188
lib/bunyan.js
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright 2012 (c) Trent Mick. All rights reserved.
|
||||
*/
|
||||
|
||||
// Bunyan log format version. This becomes the 'v' field on all log records.
|
||||
// `0` is until I release a version "1.0.0" of node-bunyan. Thereafter,
|
||||
// starting with `1`, this will be incremented if there is any backward
|
||||
// incompatible change to the log record format. Details will be in
|
||||
// "CHANGES.md" (the change log).
|
||||
var VERSION = 0;
|
||||
|
||||
var paul = function paul(s) { // internal dev/debug logging
|
||||
var args = ["PAUL: "+s].concat(Array.prototype.slice.call(arguments, 1));
|
||||
console.error.apply(this, args);
|
||||
};
|
||||
var paul = function paul() {}; // uncomment to turn of debug logging
|
||||
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
|
||||
|
||||
|
||||
//---- Internal support stuff
|
||||
|
||||
function objCopy(obj) {
|
||||
var copy = {};
|
||||
Object.keys(obj).forEach(function (k) {
|
||||
copy[k] = obj[k];
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
var format = util.format;
|
||||
if (!format) {
|
||||
// If not node 0.6, then use its `util.format`:
|
||||
// <https://github.com/joyent/node/blob/master/lib/util.js#L22>:
|
||||
var inspect = util.inspect;
|
||||
var formatRegExp = /%[sdj%]/g;
|
||||
format = function format(f) {
|
||||
if (typeof f !== 'string') {
|
||||
var objects = [];
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
objects.push(inspect(arguments[i]));
|
||||
}
|
||||
return objects.join(' ');
|
||||
}
|
||||
|
||||
var i = 1;
|
||||
var args = arguments;
|
||||
var len = args.length;
|
||||
var str = String(f).replace(formatRegExp, function(x) {
|
||||
if (i >= len) return x;
|
||||
switch (x) {
|
||||
case '%s': return String(args[i++]);
|
||||
case '%d': return Number(args[i++]);
|
||||
case '%j': return JSON.stringify(args[i++]);
|
||||
case '%%': return '%';
|
||||
default:
|
||||
return x;
|
||||
}
|
||||
});
|
||||
for (var x = args[i]; i < len; x = args[++i]) {
|
||||
if (x === null || typeof x !== 'object') {
|
||||
str += ' ' + x;
|
||||
} else {
|
||||
str += ' ' + inspect(x);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---- Levels
|
||||
|
||||
var DEBUG = 1;
|
||||
var INFO = 2;
|
||||
var WARN = 3;
|
||||
var ERROR = 4;
|
||||
var FATAL = 5;
|
||||
|
||||
var levelFromName = {
|
||||
'debug': DEBUG,
|
||||
'info': INFO,
|
||||
'warn': WARN,
|
||||
'error': ERROR,
|
||||
'fatal': FATAL
|
||||
};
|
||||
var nameFromLevel = {
|
||||
DEBUG: 'debug',
|
||||
INFO: 'info',
|
||||
WARN: 'warn',
|
||||
ERROR: 'error',
|
||||
FATAL: 'fatal'
|
||||
};
|
||||
|
||||
|
||||
//---- Logger class
|
||||
|
||||
function Logger(options) {
|
||||
paul('Logger start:', options)
|
||||
if (! this instanceof Logger) {
|
||||
return new Logger(options);
|
||||
}
|
||||
|
||||
// These are the default fields for log records (minus the attributes
|
||||
// removed in this constructor). To allow storing raw log records
|
||||
// (unrendered), `this.fields` must never be mutated. Create a copy, if
|
||||
// necessary.
|
||||
this.fields = objCopy(options);
|
||||
|
||||
if (options.stream) {
|
||||
this.stream = options.stream;
|
||||
delete this.fields.stream;
|
||||
} else {
|
||||
this.stream = process.stdout;
|
||||
}
|
||||
if (options.level) {
|
||||
this.level = (typeof(options.level) === 'string'
|
||||
? levelFromName[options.level]
|
||||
: options.level);
|
||||
if (! (DEBUG <= this.level && this.level <= FATAL)) {
|
||||
throw new Error('invalid level: ' + options.level);
|
||||
}
|
||||
delete this.fields.level;
|
||||
} else {
|
||||
this.level = 2; // INFO is default level.
|
||||
}
|
||||
paul('Logger default fields:', this.fields);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A log record is a 4-tuple:
|
||||
* [<default fields object>,
|
||||
* <log record fields object>,
|
||||
* <level integer>,
|
||||
* <msg args array>]
|
||||
* For Perf reasons, we only render this down to a single object when
|
||||
* it is emitted.
|
||||
*/
|
||||
Logger.prototype._mkRecord = function (fields, level, msgArgs) {
|
||||
var recFields = (fields ? objCopy(fields) : null);
|
||||
return [this.fields, recFields, level, msgArgs];
|
||||
}
|
||||
|
||||
Logger.prototype._emit = function (rec) {
|
||||
var obj = objCopy(rec[0]);
|
||||
var recFields = rec[1];
|
||||
if (recFields) {
|
||||
Object.keys(recFields).forEach(function (k) {
|
||||
obj[k] = recFields[k];
|
||||
});
|
||||
}
|
||||
obj.level = rec[2];
|
||||
paul("Record:", rec)
|
||||
obj.msg = format.apply(this, rec[3]);
|
||||
obj.v = VERSION;
|
||||
this.stream.write(JSON.stringify(obj) + '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Usages:
|
||||
* log.info(<object> fields, <string> msg, ...)
|
||||
* log.info(<string> msg, ...)
|
||||
* log.info() -> boolean is-info-enabled
|
||||
*/
|
||||
Logger.prototype.info = function () {
|
||||
var fields = null, msgArgs = null;
|
||||
if (arguments.length === 0) { // `log.info()`
|
||||
return (this.level <= INFO);
|
||||
} else if (this.level > INFO) {
|
||||
return;
|
||||
} else if (typeof arguments[0] === 'string') { // `log.info(msg, ...)`
|
||||
fields = null;
|
||||
msgArgs = Array.prototype.slice.call(arguments);
|
||||
} else { // `log.info(fields, msg, ...)`
|
||||
fields = arguments[0];
|
||||
msgArgs = Array.prototype.slice.call(arguments, 1);
|
||||
}
|
||||
var rec = this._mkRecord(fields, INFO, msgArgs);
|
||||
this._emit(rec);
|
||||
}
|
||||
|
||||
module.exports = Logger;
|
||||
|
||||
|
6
package.json
Normal file
6
package.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "bunyan",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "./lib/bunyan.js"
|
||||
}
|
Loading…
Reference in a new issue