forked from arne/asdf-games
452 lines
11 KiB
JavaScript
452 lines
11 KiB
JavaScript
|
var http = require('http')
|
||
|
, hreq = require('hyperquest')
|
||
|
, test = require('tape')
|
||
|
, bl = require('bl')
|
||
|
, listStream = require('list-stream')
|
||
|
, bole = require('./')
|
||
|
, pid = process.pid
|
||
|
, host = require('os').hostname()
|
||
|
|
||
|
|
||
|
function mklogobj (name, level, inp) {
|
||
|
var out = {
|
||
|
time : new Date().toISOString()
|
||
|
, hostname : host
|
||
|
, pid : pid
|
||
|
, level : level
|
||
|
, name : name
|
||
|
}
|
||
|
, k
|
||
|
|
||
|
for (k in inp) {
|
||
|
if (Object.prototype.hasOwnProperty.call(inp, k))
|
||
|
out[k] = inp[k]
|
||
|
}
|
||
|
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
|
||
|
// take a log string and zero out the millisecond field
|
||
|
// to make comparison a little safer (not *entirely* safe)
|
||
|
function safe (str) {
|
||
|
return str.replace(/("time":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.)\d{3}Z"/g, '$1xxxZ')
|
||
|
.replace(/("remoteAddress":")(?:::ffff:)?(127.0.0.1")/g, '$1$2')
|
||
|
.replace(/("host":")(?:(?:localhost)|(?:::))(:\d+")/g, '$1$2')
|
||
|
}
|
||
|
|
||
|
|
||
|
test('test simple logging', function (t) {
|
||
|
t.plan(1)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log = bole('simple')
|
||
|
, expected = []
|
||
|
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected.push(mklogobj('simple', 'debug', { aDebug : 'object' }))
|
||
|
log.debug({ aDebug: 'object' })
|
||
|
expected.push(mklogobj('simple', 'info', { anInfo : 'object' }))
|
||
|
log.info({ anInfo: 'object' })
|
||
|
expected.push(mklogobj('simple', 'warn', { aWarn : 'object' }))
|
||
|
log.warn({ aWarn: 'object' })
|
||
|
expected.push(mklogobj('simple', 'error', { anError : 'object' }))
|
||
|
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))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test multiple logs', function (t) {
|
||
|
t.plan(1)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log1 = bole('simple1')
|
||
|
, log2 = bole('simple2')
|
||
|
, expected = []
|
||
|
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected.push(mklogobj('simple1', 'debug', { aDebug : 'object' }))
|
||
|
log1.debug({ aDebug: 'object' })
|
||
|
expected.push(mklogobj('simple1', 'info', { anInfo : 'object' }))
|
||
|
log1.info({ anInfo: 'object' })
|
||
|
expected.push(mklogobj('simple2', 'warn', { aWarn : 'object' }))
|
||
|
log2.warn({ aWarn: 'object' })
|
||
|
expected.push(mklogobj('simple2', 'error', { anError : 'object' }))
|
||
|
log2.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))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test multiple outputs', function (t) {
|
||
|
t.plan(4)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var debugSink = bl()
|
||
|
, infoSink = bl()
|
||
|
, warnSink = bl()
|
||
|
, errorSink = bl()
|
||
|
, log = bole('simple')
|
||
|
, expected = []
|
||
|
|
||
|
|
||
|
// add individual
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : debugSink
|
||
|
})
|
||
|
|
||
|
// add array
|
||
|
bole.output([
|
||
|
{
|
||
|
level : 'info'
|
||
|
, stream : infoSink
|
||
|
}
|
||
|
, {
|
||
|
level : 'warn'
|
||
|
, stream : warnSink
|
||
|
}
|
||
|
])
|
||
|
|
||
|
bole.output({
|
||
|
level : 'error'
|
||
|
, stream : errorSink
|
||
|
})
|
||
|
|
||
|
expected.push(mklogobj('simple', 'debug', { aDebug : 'object' }))
|
||
|
log.debug({ aDebug: 'object' })
|
||
|
expected.push(mklogobj('simple', 'info', { anInfo : 'object' }))
|
||
|
log.info({ anInfo: 'object' })
|
||
|
expected.push(mklogobj('simple', 'warn', { aWarn : 'object' }))
|
||
|
log.warn({ aWarn: 'object' })
|
||
|
expected.push(mklogobj('simple', 'error', { anError : 'object' }))
|
||
|
log.error({ anError: 'object' })
|
||
|
|
||
|
debugSink.end()
|
||
|
infoSink.end()
|
||
|
warnSink.end()
|
||
|
errorSink.end(function () {
|
||
|
// debug
|
||
|
var exp = expected.reduce(function (p, c) {
|
||
|
return p + JSON.stringify(c) + '\n'
|
||
|
}, '')
|
||
|
|
||
|
t.equal(safe(debugSink.slice().toString()), safe(exp))
|
||
|
|
||
|
// info
|
||
|
exp = expected.slice(1).reduce(function (p, c) {
|
||
|
return p + JSON.stringify(c) + '\n'
|
||
|
}, '')
|
||
|
|
||
|
t.equal(safe(infoSink.slice().toString()), safe(exp))
|
||
|
|
||
|
// warn
|
||
|
exp = expected.slice(2).reduce(function (p, c) {
|
||
|
return p + JSON.stringify(c) + '\n'
|
||
|
}, '')
|
||
|
|
||
|
t.equal(safe(warnSink.slice().toString()), safe(exp))
|
||
|
|
||
|
// error
|
||
|
exp = expected.slice(3).reduce(function (p, c) {
|
||
|
return p + JSON.stringify(c) + '\n'
|
||
|
}, '')
|
||
|
|
||
|
t.equal(safe(errorSink.slice().toString()), safe(exp))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test string formatting', function (t) {
|
||
|
t.plan(7)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
function testSingle (level, msg, args) {
|
||
|
var sink = bl()
|
||
|
, log = bole('strfmt')
|
||
|
, expected
|
||
|
|
||
|
bole.output({
|
||
|
level : level
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected = mklogobj('strfmt', level, msg)
|
||
|
log[level].apply(log, args)
|
||
|
|
||
|
sink.end(function () {
|
||
|
var exp = JSON.stringify(expected) + '\n'
|
||
|
t.equal(safe(sink.slice().toString()), safe(exp))
|
||
|
})
|
||
|
|
||
|
bole.reset()
|
||
|
}
|
||
|
|
||
|
testSingle('debug', {}, [])
|
||
|
testSingle('debug', { message: 'test' }, [ 'test' ])
|
||
|
testSingle('info', { message: 'true' }, [ true ])
|
||
|
testSingle('info', { message: 'false' }, [ false ])
|
||
|
testSingle('warn', { message: 'a number [42]' }, [ 'a number [%d]', 42 ])
|
||
|
testSingle('error', { message: 'a string [str]' }, [ 'a string [%s]', 'str' ])
|
||
|
testSingle('error', { message: 'foo bar baz' }, [ 'foo', 'bar', 'baz' ])
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test error formatting', function (t) {
|
||
|
t.plan(1)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log = bole('errfmt')
|
||
|
, err = new Error('error msg in here')
|
||
|
, expected
|
||
|
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected = mklogobj('errfmt', 'debug', { err: {
|
||
|
name : 'Error'
|
||
|
, message : 'error msg in here'
|
||
|
, stack : 'STACK'
|
||
|
}})
|
||
|
log.debug(err)
|
||
|
|
||
|
sink.end(function () {
|
||
|
var exp = JSON.stringify(expected) + '\n'
|
||
|
, act = safe(sink.slice().toString())
|
||
|
|
||
|
act = act.replace(/("stack":")Error:[^"]+/, '$1STACK')
|
||
|
t.equal(act, safe(exp))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test error formatting with message', function (t) {
|
||
|
t.plan(1)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log = bole('errfmt')
|
||
|
, err = new Error('error msg in here')
|
||
|
, expected
|
||
|
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected = mklogobj('errfmt', 'debug', {
|
||
|
message : 'this is a message'
|
||
|
, err : {
|
||
|
name : 'Error'
|
||
|
, message : 'error msg in here'
|
||
|
, stack : 'STACK'
|
||
|
}
|
||
|
})
|
||
|
log.debug(err, 'this is a %s', 'message')
|
||
|
|
||
|
sink.end(function () {
|
||
|
var exp = JSON.stringify(expected) + '\n'
|
||
|
, act = safe(sink.slice().toString())
|
||
|
|
||
|
act = act.replace(/("stack":")Error:[^"]+/, '$1STACK')
|
||
|
t.equal(act, safe(exp))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test request object', function (t) {
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log = bole('reqfmt')
|
||
|
, expected
|
||
|
, server
|
||
|
, host
|
||
|
|
||
|
bole.output({
|
||
|
level : 'info'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
server = http.createServer(function (req, res) {
|
||
|
expected = mklogobj('reqfmt', 'info', {
|
||
|
req: {
|
||
|
method : 'GET'
|
||
|
, url : '/foo?bar=baz'
|
||
|
, headers : {
|
||
|
host : host
|
||
|
, connection : 'close'
|
||
|
}
|
||
|
, remoteAddress : '127.0.0.1'
|
||
|
, remotePort : 'RPORT'
|
||
|
}
|
||
|
})
|
||
|
log.info(req)
|
||
|
|
||
|
res.end()
|
||
|
|
||
|
sink.end(function () {
|
||
|
var exp = JSON.stringify(expected) + '\n'
|
||
|
, act = safe(sink.slice().toString())
|
||
|
|
||
|
act = act.replace(/("remotePort":)\d+/, '$1"RPORT"')
|
||
|
t.equal(act, safe(exp))
|
||
|
|
||
|
server.close(t.end.bind(t))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
server.listen(function () {
|
||
|
hreq.get('http://' + (host = this.address().address + ':' + this.address().port) + '/foo?bar=baz')
|
||
|
})
|
||
|
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test request object with message', function (t) {
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log = bole('reqfmt')
|
||
|
, expected
|
||
|
, server
|
||
|
, host
|
||
|
|
||
|
bole.output({
|
||
|
level : 'info'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
server = http.createServer(function (req, res) {
|
||
|
expected = mklogobj('reqfmt', 'info', {
|
||
|
message : 'this is a message'
|
||
|
, req: {
|
||
|
method : 'GET'
|
||
|
, url : '/foo?bar=baz'
|
||
|
, headers : {
|
||
|
host : host
|
||
|
, connection : 'close'
|
||
|
}
|
||
|
, remoteAddress : '127.0.0.1'
|
||
|
, remotePort : 'RPORT'
|
||
|
}
|
||
|
})
|
||
|
log.info(req, 'this is a %s', 'message')
|
||
|
|
||
|
res.end()
|
||
|
|
||
|
sink.end(function () {
|
||
|
var exp = JSON.stringify(expected) + '\n'
|
||
|
, act = safe(sink.slice().toString())
|
||
|
|
||
|
act = act.replace(/("remotePort":)\d+/, '$1"RPORT"')
|
||
|
t.equal(act, safe(exp))
|
||
|
|
||
|
server.close(t.end.bind(t))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
server.listen(function () {
|
||
|
hreq.get('http://' + (host = this.address().address + ':' + this.address().port) + '/foo?bar=baz')
|
||
|
})
|
||
|
|
||
|
})
|
||
|
|
||
|
|
||
|
test('test sub logger', function (t) {
|
||
|
t.plan(1)
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = bl()
|
||
|
, log = bole('parent')
|
||
|
, expected = []
|
||
|
, sub1
|
||
|
, sub2
|
||
|
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected.push(mklogobj('parent', 'debug', { aDebug : 'object' }))
|
||
|
log.debug({ aDebug: 'object' })
|
||
|
expected.push(mklogobj('parent', 'info', { anInfo : 'object' }))
|
||
|
log.info({ anInfo: 'object' })
|
||
|
expected.push(mklogobj('parent', 'warn', { aWarn : 'object' }))
|
||
|
log.warn({ aWarn: 'object' })
|
||
|
expected.push(mklogobj('parent', 'error', { anError : 'object' }))
|
||
|
log.error({ anError: 'object' })
|
||
|
|
||
|
expected.push(mklogobj('parent:sub1', 'debug', { aDebug : 'object' }))
|
||
|
;(sub1 = log('sub1')).debug({ aDebug: 'object' })
|
||
|
expected.push(mklogobj('parent:sub1', 'info', { anInfo : 'object' }))
|
||
|
sub1.info({ anInfo: 'object' })
|
||
|
expected.push(mklogobj('parent:sub2', 'warn', { aWarn : 'object' }))
|
||
|
;(sub2 = log('sub2')).warn({ aWarn: 'object' })
|
||
|
expected.push(mklogobj('parent:sub2:subsub', 'error', { anError : 'object' }))
|
||
|
sub2('subsub').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))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('test object logging', function (t) {
|
||
|
t.on('end', bole.reset)
|
||
|
|
||
|
var sink = listStream.obj()
|
||
|
, log = bole('simple')
|
||
|
, expected = []
|
||
|
|
||
|
bole.output({
|
||
|
level : 'debug'
|
||
|
, stream : sink
|
||
|
})
|
||
|
|
||
|
expected.push(mklogobj('simple', 'debug', { aDebug : 'object' }))
|
||
|
log.debug({ aDebug: 'object' })
|
||
|
expected.push(mklogobj('simple', 'info', { anInfo : 'object' }))
|
||
|
log.info({ anInfo: 'object' })
|
||
|
expected.push(mklogobj('simple', 'warn', { aWarn : 'object' }))
|
||
|
log.warn({ aWarn: 'object' })
|
||
|
expected.push(mklogobj('simple', 'error', { anError : 'object' }))
|
||
|
log.error({ anError: 'object' })
|
||
|
|
||
|
sink.end(function () {
|
||
|
t.equal(sink.length, expected.length, 'correct number of log entries')
|
||
|
for (var i = 0; i < expected.length; i++)
|
||
|
t.deepEqual(sink.get(i), expected[i], 'correct log entry #' + i)
|
||
|
t.end()
|
||
|
})
|
||
|
})
|