Comparing version 2.0.0 to 3.0.0
217
bole.js
@@ -1,10 +0,21 @@ | ||
var stringify = require('json-stringify-safe') | ||
, format = require('util').format | ||
, is = require('core-util-is') | ||
, individual = require('individual')('$$bole', { }) | ||
var _stringify = require('fast-safe-stringify') | ||
, individual = require('individual')('$$bole', { fastTime: false }) // singleton | ||
, format = require('./format') | ||
, levels = 'debug info warn error'.split(' ') | ||
, hostname = require('os').hostname() | ||
, hostnameSt = _stringify(hostname) | ||
, pid = process.pid | ||
, hasObjMode = false | ||
, scache = [] | ||
levels.forEach(function (level) { | ||
// prepare a common part of the stringified output | ||
scache[level] = ',"hostname":' + hostnameSt + ',"pid":' + pid + ',"level":"' + level | ||
Number(scache[level]) // convert internal representation to plain string | ||
if (!Array.isArray(individual[level])) | ||
individual[level] = [] | ||
}) | ||
function stackToString (e) { | ||
@@ -14,3 +25,3 @@ var s = e.stack | ||
if (is.isFunction(e.cause) && (ce = e.cause())) | ||
if (typeof e.cause === 'function' && (ce = e.cause())) | ||
s += '\nCaused by: ' + stackToString(ce) | ||
@@ -22,60 +33,124 @@ | ||
function levelLogger (level, name) { | ||
return function (inp) { | ||
var outputs = individual[level] | ||
function errorToOut (err, out) { | ||
out.err = { | ||
name : err.name | ||
, message : err.message | ||
, code : err.code // perhaps | ||
, stack : stackToString(err) | ||
} | ||
} | ||
if (!outputs) | ||
return // no outputs for this level | ||
var out = { | ||
time : new Date().toISOString() | ||
, hostname : hostname | ||
, pid : pid | ||
, level : level | ||
, name : name | ||
} | ||
, k | ||
, i = 0 | ||
, stringified | ||
function requestToOut (req, out) { | ||
out.req = { | ||
method : req.method | ||
, url : req.url | ||
, headers : req.headers | ||
, remoteAddress : req.connection.remoteAddress | ||
, remotePort : req.connection.remotePort | ||
} | ||
} | ||
if (is.isError(inp)) { | ||
if (arguments.length > 1) | ||
out.message = format.apply(null, Array.prototype.slice.call(arguments, 1)) | ||
out.err = { | ||
name : inp.name | ||
, message : inp.message | ||
, code : inp.code // perhaps | ||
, stack : stackToString(inp) | ||
} | ||
} else if (is.isObject(inp) && inp.method && inp.url && inp.headers && inp.socket) { | ||
if (arguments.length > 1) | ||
out.message = format.apply(null, Array.prototype.slice.call(arguments, 1)) | ||
function objectToOut (obj, out) { | ||
var k | ||
out.req = { | ||
method : inp.method | ||
, url : inp.url | ||
, headers : inp.headers | ||
, remoteAddress : inp.connection.remoteAddress | ||
, remotePort : inp.connection.remotePort | ||
for (k in obj) { | ||
if (Object.prototype.hasOwnProperty.call(obj, k)) | ||
out[k] = obj[k] | ||
} | ||
} | ||
function objectMode (stream) { | ||
return stream._writableState && stream._writableState.objectMode === true | ||
} | ||
function stringify (level, name, message, obj) { | ||
var k | ||
, s = '{"time":' | ||
+ (individual.fastTime ? Date.now() : ('"' + new Date().toISOString() + '"')) | ||
+ scache[level] | ||
+ '","name":' | ||
+ name | ||
+ (message !== undefined ? (',"message":' + _stringify(message)) : '') | ||
for (k in obj) | ||
s += ',' + _stringify(k) + ':' + _stringify(obj[k]) | ||
s += '}' | ||
Number(s) // convert internal representation to plain string | ||
return s | ||
} | ||
function extend (level, name, message, obj) { | ||
var k | ||
, newObj = { | ||
time : individual.fastTime ? Date.now() : new Date().toISOString() | ||
, hostname : hostname | ||
, pid : pid | ||
, level : level | ||
, name : name | ||
} | ||
} else if (is.isObject(inp)) { | ||
if (arguments.length > 1) | ||
out.message = format.apply(null, Array.prototype.slice.call(arguments, 1)) | ||
for (k in inp) { | ||
if (Object.prototype.hasOwnProperty.call(inp, k)) | ||
out[k] = inp[k] | ||
if (message !== undefined) | ||
obj.message = message | ||
for (k in obj) | ||
newObj[k] = obj[k] | ||
return newObj | ||
} | ||
function levelLogger (level, name) { | ||
var outputs = individual[level] | ||
, nameSt = _stringify(name) | ||
return function namedLevelLogger (inp, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) { | ||
if (outputs.length === 0) | ||
return | ||
var out = {} | ||
, objectOut | ||
, i = 0 | ||
, l = outputs.length | ||
, stringified | ||
, message | ||
if (typeof inp === 'string' || inp == null) { | ||
if (!(message = format(inp, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16))) | ||
message = undefined | ||
} else { | ||
if (!(message = format(a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16))) | ||
message = undefined | ||
if (typeof inp === 'boolean') | ||
message = String(inp) | ||
else if (inp instanceof Error) { | ||
errorToOut(inp, out) | ||
} else if (typeof inp === 'object') { | ||
if (inp.method && inp.url && inp.headers && inp.socket) | ||
requestToOut(inp, out) | ||
else | ||
objectToOut(inp, out) | ||
} | ||
} else if (!is.isUndefined(inp)) { | ||
out.message = format.apply(null, arguments) | ||
} | ||
if (l === 1 && !hasObjMode) { // fast, standard case | ||
outputs[0].write(new Buffer(stringify(level, nameSt, message, out) + '\n')) | ||
return | ||
} | ||
for (; i < outputs.length; i++) { | ||
if (outputs[i]._writableState && outputs[i]._writableState.objectMode === true) { | ||
outputs[i].write(out) | ||
for (; i < l; i++) { | ||
if (objectMode(outputs[i])) { | ||
if (objectOut === undefined) // lazy object completion | ||
objectOut = extend(level, name, message, out) | ||
outputs[i].write(objectOut) | ||
} else { | ||
if (!stringified) // lazy stringify | ||
stringified = stringify(out) + '\n' | ||
if (stringified === undefined) // lazy stringify | ||
stringified = new Buffer(stringify(level, nameSt, message, out) + '\n') | ||
outputs[i].write(stringified) | ||
@@ -102,28 +177,46 @@ } | ||
bole.output = function (opt) { | ||
if (Array.isArray(opt)) | ||
return opt.forEach(bole.output) | ||
bole.output = function output (opt) { | ||
var i = 0, b | ||
var i = 0 | ||
, b = false | ||
if (Array.isArray(opt)) { | ||
opt.forEach(bole.output) | ||
return bole | ||
} | ||
if (typeof opt.level !== 'string') | ||
throw new TypeError('Must provide a "level" option') | ||
for (; i < levels.length; i++) { | ||
if (levels[i] === opt.level) | ||
if (!b && levels[i] === opt.level) | ||
b = true | ||
if (b) { | ||
if (!individual[levels[i]]) | ||
individual[levels[i]] = [] | ||
if (opt.stream && objectMode(opt.stream)) | ||
hasObjMode = true | ||
individual[levels[i]].push(opt.stream) | ||
} | ||
} | ||
return bole | ||
} | ||
bole.reset = function () { | ||
for (var k in individual) | ||
delete individual[k] | ||
bole.reset = function reset () { | ||
levels.forEach(function (level) { | ||
individual[level].splice(0, individual[level].length) | ||
}) | ||
individual.fastTime = false | ||
return bole | ||
} | ||
bole.setFastTime = function setFastTime (b) { | ||
if (!arguments.length) | ||
individual.fastTime = true | ||
else | ||
individual.fastTime = b | ||
return bole | ||
} | ||
module.exports = bole |
{ | ||
"name": "bole", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "A tiny JSON logger", | ||
@@ -20,12 +20,11 @@ "main": "bole.js", | ||
"dependencies": { | ||
"core-util-is": ">=1.0.1 <1.1.0-0", | ||
"individual": ">=3.0.0 <3.1.0-0", | ||
"json-stringify-safe": ">=5.0.0 <5.1.0-0" | ||
"fast-safe-stringify": "~1.0.9", | ||
"individual": "~3.0.0" | ||
}, | ||
"devDependencies": { | ||
"bl": ">=0.9.3 <0.10.0-0", | ||
"hyperquest": ">=1.0.1 <1.1.0-0", | ||
"list-stream": ">=1.0.0 <1.1.0-0", | ||
"tape": ">=3.0.3 <3.1.0-0" | ||
"bl": "~1.1.2", | ||
"hyperquest": "~1.3.0", | ||
"list-stream": "~1.0.1", | ||
"tape": "~4.5.1" | ||
} | ||
} |
@@ -107,4 +107,4 @@ # bole | ||
bole.output([ | ||
{ level: 'debug', fs.createWriteStream('app.log') }, | ||
{ level: 'info', process.stdout } | ||
{ level: 'debug', stream: fs.createWriteStream('app.log') }, | ||
{ level: 'info', stream: process.stdout } | ||
]) | ||
@@ -117,2 +117,8 @@ ``` | ||
### bole.setFastTime() | ||
If speed is something you care about and you can handle time in milliseconds since epoch (`Date.now()`) rather than the full ISO string (`new Date().toISOString()`) in your logs then use `bole.setFastTime(true)` to shave off some precious microseconds. | ||
Note that this will reset to the default of `false` when you use `bole.reset()` | ||
## Additional features | ||
@@ -119,0 +125,0 @@ |
79
test.js
@@ -11,5 +11,5 @@ var http = require('http') | ||
function mklogobj (name, level, inp) { | ||
function mklogobj (name, level, inp, fastTime) { | ||
var out = { | ||
time : new Date().toISOString() | ||
time : fastTime ? Date.now() : new Date().toISOString() | ||
, hostname : host | ||
@@ -72,2 +72,32 @@ , pid : pid | ||
test('test complex object logging', function (t) { | ||
t.plan(1) | ||
t.on('end', bole.reset) | ||
var sink = bl() | ||
, log = bole('simple') | ||
, expected = [] | ||
, cplx = { | ||
aDebug : 'object' | ||
, deep : { deeper: { deeperStill: { tooDeep: 'whoa' }, arr: [ 1, 2, 3, { eh: 'wut?' } ] } } | ||
} | ||
bole.output({ | ||
level : 'debug' | ||
, stream : sink | ||
}) | ||
expected.push(mklogobj('simple', 'debug', cplx)) | ||
log.debug(cplx) | ||
sink.end(function () { | ||
var exp = expected.reduce(function (p, c) { | ||
return p + JSON.stringify(c) + '\n' | ||
}, '') | ||
t.equal(safe(sink.slice().toString()), safe(exp)) | ||
}) | ||
}) | ||
test('test multiple logs', function (t) { | ||
@@ -186,3 +216,3 @@ t.plan(1) | ||
test('test string formatting', function (t) { | ||
t.plan(7) | ||
t.plan(8) | ||
t.on('end', bole.reset) | ||
@@ -217,2 +247,7 @@ | ||
testSingle('error', { message: 'a string [str]' }, [ 'a string [%s]', 'str' ]) | ||
testSingle( | ||
'error' | ||
, { message: 'a string [str], a number [101], s, 1, 2 a b c' } | ||
, [ 'a string [%s], a number [%d], %s, %s, %s', 'str', 101, 's', 1, 2, 'a', 'b', 'c' ] | ||
) | ||
testSingle('error', { message: 'foo bar baz' }, [ 'foo', 'bar', 'baz' ]) | ||
@@ -329,3 +364,3 @@ }) | ||
server.listen(function () { | ||
server.listen(0, '127.0.0.1', function () { | ||
hreq.get('http://' + (host = this.address().address + ':' + this.address().port) + '/foo?bar=baz') | ||
@@ -380,3 +415,3 @@ }) | ||
server.listen(function () { | ||
server.listen(0, '127.0.0.1', function () { | ||
hreq.get('http://' + (host = this.address().address + ':' + this.address().port) + '/foo?bar=baz') | ||
@@ -458,1 +493,35 @@ }) | ||
}) | ||
test('test fast time', function (t) { | ||
t.plan(1) | ||
t.on('end', bole.reset) | ||
var sink = bl() | ||
, log = bole('simple') | ||
, expected = [] | ||
bole.output({ | ||
level : 'debug' | ||
, stream : sink | ||
}) | ||
bole.setFastTime(true) | ||
expected.push(mklogobj('simple', 'debug', { aDebug : 'object' }, true)) | ||
log.debug({ aDebug: 'object' }) | ||
expected.push(mklogobj('simple', 'info', { anInfo : 'object' }, true)) | ||
log.info({ anInfo: 'object' }) | ||
expected.push(mklogobj('simple', 'warn', { aWarn : 'object' }, true)) | ||
log.warn({ aWarn: 'object' }) | ||
expected.push(mklogobj('simple', 'error', { anError : 'object' }, true)) | ||
log.error({ anError: 'object' }) | ||
sink.end(function () { | ||
var exp = expected.reduce(function (p, c) { | ||
return p + JSON.stringify(c) + '\n' | ||
}, '') | ||
t.equal(safe(sink.slice().toString()), safe(exp)) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29244
2
8
616
133
+ Addedfast-safe-stringify@~1.0.9
+ Addedfast-safe-stringify@1.0.10(transitive)
- Removedcore-util-is@>=1.0.1 <1.1.0-0
- Removedjson-stringify-safe@>=5.0.0 <5.1.0-0
- Removedcore-util-is@1.0.3(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
Updatedindividual@~3.0.0