Refactor entire project into ecmamodules, remove all dependencies, and use eltro as our test runner.

This commit is contained in:
Jonatan Nilsson 2021-06-02 21:52:18 +00:00
parent 1260b89e48
commit 89429a34c1
58 changed files with 4734 additions and 5664 deletions

View file

@ -1,7 +0,0 @@
/tmp
/node_modules
*.log
/examples
/test
/*.tgz
/tools

1
.npmrc Normal file
View file

@ -0,0 +1 @@
package-lock=false

127
Makefile
View file

@ -1,127 +0,0 @@
#---- Tools
NODEUNIT := ./node_modules/.bin/nodeunit
NODEOPT ?= $(HOME)/opt
#---- Files
JSSTYLE_FILES := $(shell find lib test tools examples -name "*.js") bin/bunyan
# All test files
TEST_FILES := $(shell ls -1 test/*.test.js | xargs)
#---- Targets
all $(NODEUNIT):
npm install $(NPM_INSTALL_FLAGS)
# Ensure all version-carrying files have the same version.
.PHONY: versioncheck
versioncheck:
@echo version is: $(shell cat package.json | json version)
[[ `cat package.json | json version` == `grep '^## ' CHANGES.md | head -2 | tail -1 | awk '{print $$2}'` ]]
@echo Version check ok.
.PHONY: cutarelease
cutarelease: check
[[ -z `git status --short` ]] # If this fails, the working dir is dirty.
@which json 2>/dev/null 1>/dev/null && \
ver=$(shell json -f package.json version) && \
name=$(shell json -f package.json name) && \
publishedVer=$(shell npm view -j $(shell json -f package.json name)@$(shell json -f package.json version) version 2>/dev/null) && \
if [[ -n "$$publishedVer" ]]; then \
echo "error: $$name@$$ver is already published to npm"; \
exit 1; \
fi && \
echo "** Are you sure you want to tag and publish $$name@$$ver to npm?" && \
echo "** Enter to continue, Ctrl+C to abort." && \
read
ver=$(shell cat package.json | json version) && \
date=$(shell date -u "+%Y-%m-%d") && \
git tag -a "$$ver" -m "version $$ver ($$date) beta" && \
git push --tags origin && \
npm publish --tag beta
.PHONY: docs
docs: toc
@[[ `which ronn` ]] || (echo "No 'ronn' on your PATH. Install with 'gem install ronn'" && exit 2)
mkdir -p man/man1
ronn --style=toc --manual="bunyan manual" --date=$(shell git log -1 --pretty=format:%cd --date=short) --roff --html docs/bunyan.1.ronn
python -c 'import sys; h = open("docs/bunyan.1.html").read(); h = h.replace(".mp dt.flush {float:left;width:8ex}", ""); open("docs/bunyan.1.html", "w").write(h)'
python -c 'import sys; h = open("docs/bunyan.1.html").read(); h = h.replace("</body>", """<a href="https://github.com/trentm/node-bunyan"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a></body>"""); open("docs/bunyan.1.html", "w").write(h)'
@echo "# test with 'man ./docs/bunyan.1' and 'open ./docs/bunyan.1.html'"
# Re-generate the README.md table of contents.
toc:
./node_modules/.bin/markdown-toc -i README.md
.PHONY: publish
publish:
mkdir -p tmp
[[ -d tmp/bunyan-gh-pages ]] || git clone git@github.com:trentm/node-bunyan.git tmp/bunyan-gh-pages
cd tmp/bunyan-gh-pages && git checkout gh-pages && git pull --rebase origin gh-pages
cp docs/index.html tmp/bunyan-gh-pages/index.html
cp docs/bunyan.1.html tmp/bunyan-gh-pages/bunyan.1.html
(cd tmp/bunyan-gh-pages \
&& git commit -a -m "publish latest docs" \
&& git push origin gh-pages || true)
.PHONY: distclean
distclean:
rm -rf node_modules
#---- test
.PHONY: test
test: $(NODEUNIT)
$(NODEUNIT) $(TEST_FILES)
# Test with all node supported versions (presumes install locations I use on
# my machine -- "~/opt/node-VER"):
.PHONY: testall
testall: test7 test6 test012 test010 test4
.PHONY: test7
test7:
@echo "# Test node 7.x (with node `$(NODEOPT)/node-7/bin/node --version`)"
@$(NODEOPT)/node-7/bin/node --version | grep '^v7\.'
PATH="$(NODEOPT)/node-7/bin:$(PATH)" make distclean all test
.PHONY: test6
test6:
@echo "# Test node 6.x (with node `$(NODEOPT)/node-6/bin/node --version`)"
@$(NODEOPT)/node-6/bin/node --version | grep '^v6\.'
PATH="$(NODEOPT)/node-6/bin:$(PATH)" make distclean all test
.PHONY: test4
test4:
@echo "# Test node 4.x (with node `$(NODEOPT)/node-4/bin/node --version`)"
@$(NODEOPT)/node-4/bin/node --version | grep '^v4\.'
PATH="$(NODEOPT)/node-4/bin:$(PATH)" make distclean all test
.PHONY: test012
test012:
@echo "# Test node 0.12.x (with node `$(NODEOPT)/node-0.12/bin/node --version`)"
@$(NODEOPT)/node-0.12/bin/node --version | grep '^v0\.12\.'
PATH="$(NODEOPT)/node-0.12/bin:$(PATH)" make distclean all test
.PHONY: test010
test010:
@echo "# Test node 0.10.x (with node `$(NODEOPT)/node-0.10/bin/node --version`)"
@$(NODEOPT)/node-0.10/bin/node --version | grep '^v0\.10\.'
PATH="$(NODEOPT)/node-0.10/bin:$(PATH)" make distclean all test
#---- check
.PHONY: check-jsstyle
check-jsstyle: $(JSSTYLE_FILES)
./tools/jsstyle -o indent=4,doxygen,unparenthesized-return=0,blank-after-start-comment=0,leading-right-paren-ok=1 $(JSSTYLE_FILES)
.PHONY: check
check: check-jsstyle versioncheck
@echo "Check ok."
.PHONY: prepush
prepush: check testall
@echo "Okay to push."

1407
bin/bunyan

File diff suppressed because it is too large Load diff

1397
bin/bunyan.mjs Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1128
lib/bunyan.mjs Normal file

File diff suppressed because it is too large Load diff

69
lib/safe-json.mjs Normal file
View file

@ -0,0 +1,69 @@
var hasProp = Object.prototype.hasOwnProperty
function throwsMessage(err) {
return '[Throws: ' + (err ? err.message : '?') + ']'
}
function safeGetValueFromPropertyOnObject(obj, property) {
if (hasProp.call(obj, property)) {
try {
return obj[property]
}
catch (err) {
return throwsMessage(err)
}
}
return obj[property]
}
function ensureProperties(obj) {
var seen = new WeakMap()
function visit(obj) {
if (obj === null || typeof obj !== 'object') {
return obj
}
if (seen.has(obj)) {
return '[Circular]'
}
seen.set(obj, true)
if (typeof obj.toJSON === 'function') {
try {
var fResult = visit(obj.toJSON())
seen.delete(obj)
return fResult
} catch(err) {
seen.delete(obj)
return throwsMessage(err)
}
}
if (Array.isArray(obj)) {
var aResult = obj.map(visit)
seen.delete(obj)
return aResult
}
var result = Object.keys(obj).reduce(function(result, prop) {
// prevent faulty defined getter properties
result[prop] = visit(safeGetValueFromPropertyOnObject(obj, prop))
return result
}, {})
seen.delete(obj)
return result
}
return visit(obj)
}
function safeJson(data, replacer, space) {
return JSON.stringify(ensureProperties(data), replacer, space)
}
safeJson.ensureProperties = ensureProperties
export default safeJson

View file

@ -1,19 +1,16 @@
{ {
"name": "bunyan-lite", "name": "bunyan-lite",
"version": "1.0.1", "version": "1.1.0",
"description": "a lite version of bunyan, a JSON logging library for node.js services without dtrace or moment", "description": "a lite version of bunyan, a JSON logging library for node.js services without dtrace or moment",
"author": "Jonatan Nilsson <jonatan@nilsson.is> (https://nfp.is)", "author": "Jonatan Nilsson <jonatan@nilsson.is> (https://nfp.is)",
"main": "./lib/bunyan.js", "main": "./lib/bunyan.js",
"bin": { "bin": {
"bunyan": "./bin/bunyan" "bunyan": "./bin/bunyan.mjs"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/nfp-projects/node-bunyan-lite.git" "url": "git://github.com/nfp-projects/node-bunyan-lite.git"
}, },
"engines": [
"node >=0.10.0"
],
"keywords": [ "keywords": [
"log", "log",
"logging", "logging",
@ -23,19 +20,16 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": {}, "dependencies": {},
"// mv": "required for RotatingFileStream",
"optionalDependencies": {
"mv-lite": "~1",
"safe-json-stringify": "~1"
},
"devDependencies": { "devDependencies": {
"nodeunit": "0.9", "eltro": "^1.0.2"
"ben": "0.0.0",
"markdown-toc": "0.12.x",
"verror": "1.3.3",
"vasync": "1.4.3"
}, },
"scripts": { "scripts": {
"test": "make test" "test": "eltro test/**/*.test.mjs -r dot"
} },
"files": [
"LICENSE.txt",
"README.md",
"bin",
"lib"
]
} }

View file

@ -1,39 +0,0 @@
/*
* Copyright (c) 2016 Trent Mick. All rights reserved.
*
* Test stream adding.
*/
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var test = tap4nodeunit.test;
test('non-writables passed as stream', function (t) {
var things = ['process.stdout', {}];
things.forEach(function (thing) {
function createLogger() {
bunyan.createLogger({
name: 'foo',
stream: thing
});
}
t.throws(createLogger,
/stream is not writable/,
'"stream" stream is not writable');
})
t.end();
});
test('proper stream', function (t) {
var log = bunyan.createLogger({
name: 'foo',
stream: process.stdout
});
t.ok('should not throw');
t.end();
});

28
test/add-stream.test.mjs Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016 Trent Mick. All rights reserved.
*
* Test stream adding.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
t.test('non-writables passed as stream', function () {
var things = ['process.stdout', {}];
things.forEach(function (thing) {
function createLogger() {
bunyan.createLogger({
name: 'foo',
stream: thing
});
}
assert.throws(createLogger,
/stream is not writable/);
})
});
t.test('proper stream', function () {
var log = bunyan.createLogger({
name: 'foo',
stream: process.stdout
});
});

View file

@ -1,81 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
* Copyright (c) 2012 Joyent Inc. All rights reserved.
*
* Test logging with (accidental) usage of buffers.
*/
var util = require('util'),
inspect = util.inspect,
format = util.format;
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
function Catcher() {
this.records = [];
}
Catcher.prototype.write = function (record) {
this.records.push(record);
}
var catcher = new Catcher();
var log = new bunyan.createLogger({
name: 'buffer.test',
streams: [
{
type: 'raw',
stream: catcher,
level: 'trace'
}
]
});
test('log.info(BUFFER)', function (t) {
var b = new Buffer('foo');
['trace',
'debug',
'info',
'warn',
'error',
'fatal'].forEach(function (lvl) {
log[lvl].call(log, b);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, inspect(b),
format('log.%s msg is inspect(BUFFER)', lvl));
t.ok(rec['0'] === undefined,
'no "0" array index key in record: ' + inspect(rec['0']));
t.ok(rec['parent'] === undefined,
'no "parent" array index key in record: ' + inspect(rec['parent']));
log[lvl].call(log, b, 'bar');
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, inspect(b) + ' bar', format(
'log.%s(BUFFER, "bar") msg is inspect(BUFFER) + " bar"', lvl));
});
t.end();
});
//test('log.info({buf: BUFFER})', function (t) {
// var b = new Buffer('foo');
//
// // Really there isn't much Bunyan can do here. See
// // <https://github.com/joyent/node/issues/3905>. An unwelcome hack would
// // be to monkey-patch in Buffer.toJSON. Bletch.
// log.info({buf: b}, 'my message');
// var rec = catcher.records[catcher.records.length - 1];
//
// t.end();
//});

74
test/buffer.test.mjs Normal file
View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
* Copyright (c) 2012 Joyent Inc. All rights reserved.
*
* Test logging with (accidental) usage of buffers.
*/
import util from 'util'
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
const inspect = util.inspect
const format = util.format
function Catcher() {
this.records = []
}
Catcher.prototype.write = function (record) {
this.records.push(record)
}
let catcher = new Catcher()
let log = new bunyan.createLogger({
name: 'buffer.test',
streams: [
{
type: 'raw',
stream: catcher,
level: 'trace'
}
]
})
t.test('log.info(BUFFER)', function () {
let b = Buffer.from('foo')
let testLevels = ['trace',
'debug',
'info',
'warn',
'error',
'fatal']
testLevels.forEach(function (lvl) {
log[lvl].call(log, b)
let rec = catcher.records[catcher.records.length - 1]
assert.strictEqual(rec.msg, inspect(b),
format('log.%s msg is inspect(BUFFER)', lvl))
assert.ok(rec['0'] === undefined,
'no "0" array index key in record: ' + inspect(rec['0']))
assert.ok(rec['parent'] === undefined,
'no "parent" array index key in record: ' + inspect(rec['parent']))
log[lvl].call(log, b, 'bar')
rec = catcher.records[catcher.records.length - 1]
assert.strictEqual(rec.msg, inspect(b) + ' bar', format(
'log.%s(BUFFER, "bar") msg is inspect(BUFFER) + " bar"', lvl))
})
})
//test('log.info({buf: BUFFER})', function (t) {
// let b = new Buffer('foo')
//
// // Really there isn't much Bunyan can do here. See
// // <https://github.com/joyent/node/issues/3905>. An unwelcome hack would
// // be to monkey-patch in Buffer.toJSON. Bletch.
// log.info({buf: b}, 'my message')
// let rec = catcher.records[catcher.records.length - 1]
//
// t.end()
//})

View file

@ -4,16 +4,8 @@
* Test some `<Logger>.child(...)` behaviour. * Test some `<Logger>.child(...)` behaviour.
*/ */
var bunyan = require('../lib/bunyan'); import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
function CapturingStream(recs) { function CapturingStream(recs) {
@ -24,10 +16,9 @@ CapturingStream.prototype.write = function (rec) {
} }
t.test('child can add stream', function () {
test('child can add stream', function (t) { let dadStream = new CapturingStream();
var dadStream = new CapturingStream(); let dad = bunyan.createLogger({
var dad = bunyan.createLogger({
name: 'surname', name: 'surname',
streams: [ { streams: [ {
type: 'raw', type: 'raw',
@ -36,8 +27,8 @@ test('child can add stream', function (t) {
} ] } ]
}); });
var sonStream = new CapturingStream(); let sonStream = new CapturingStream();
var son = dad.child({ let son = dad.child({
component: 'son', component: 'son',
streams: [ { streams: [ {
type: 'raw', type: 'raw',
@ -50,21 +41,20 @@ test('child can add stream', function (t) {
dad.debug('debug from dad'); dad.debug('debug from dad');
son.debug('debug from son'); son.debug('debug from son');
var rec; let rec;
t.equal(dadStream.recs.length, 1); assert.equal(dadStream.recs.length, 1);
rec = dadStream.recs[0]; rec = dadStream.recs[0];
t.equal(rec.msg, 'info from dad'); assert.equal(rec.msg, 'info from dad');
t.equal(sonStream.recs.length, 1); assert.equal(sonStream.recs.length, 1);
rec = sonStream.recs[0]; rec = sonStream.recs[0];
t.equal(rec.msg, 'debug from son'); assert.equal(rec.msg, 'debug from son');
t.end();
}); });
test('child can set level of inherited streams', function (t) { t.test('child can set level of inherited streams', function () {
var dadStream = new CapturingStream(); let dadStream = new CapturingStream();
var dad = bunyan.createLogger({ let dad = bunyan.createLogger({
name: 'surname', name: 'surname',
streams: [ { streams: [ {
type: 'raw', type: 'raw',
@ -75,7 +65,7 @@ test('child can set level of inherited streams', function (t) {
// Intention here is that the inherited `dadStream` logs at 'debug' level // Intention here is that the inherited `dadStream` logs at 'debug' level
// for the son. // for the son.
var son = dad.child({ let son = dad.child({
component: 'son', component: 'son',
level: 'debug' level: 'debug'
}); });
@ -84,20 +74,19 @@ test('child can set level of inherited streams', function (t) {
dad.debug('debug from dad'); dad.debug('debug from dad');
son.debug('debug from son'); son.debug('debug from son');
var rec; let rec;
t.equal(dadStream.recs.length, 2); assert.equal(dadStream.recs.length, 2);
rec = dadStream.recs[0]; rec = dadStream.recs[0];
t.equal(rec.msg, 'info from dad'); assert.equal(rec.msg, 'info from dad');
rec = dadStream.recs[1]; rec = dadStream.recs[1];
t.equal(rec.msg, 'debug from son'); assert.equal(rec.msg, 'debug from son');
t.end();
}); });
test('child can set level of inherited streams and add streams', function (t) { t.test('child can set level of inherited streams and add streams', function () {
var dadStream = new CapturingStream(); let dadStream = new CapturingStream();
var dad = bunyan.createLogger({ let dad = bunyan.createLogger({
name: 'surname', name: 'surname',
streams: [ { streams: [ {
type: 'raw', type: 'raw',
@ -108,8 +97,8 @@ test('child can set level of inherited streams and add streams', function (t) {
// Intention here is that the inherited `dadStream` logs at 'debug' level // Intention here is that the inherited `dadStream` logs at 'debug' level
// for the son. // for the son.
var sonStream = new CapturingStream(); let sonStream = new CapturingStream();
var son = dad.child({ let son = dad.child({
component: 'son', component: 'son',
level: 'trace', level: 'trace',
streams: [ { streams: [ {
@ -124,21 +113,20 @@ test('child can set level of inherited streams and add streams', function (t) {
son.trace('trace from son'); son.trace('trace from son');
son.debug('debug from son'); son.debug('debug from son');
t.equal(dadStream.recs.length, 3); assert.equal(dadStream.recs.length, 3);
t.equal(dadStream.recs[0].msg, 'info from dad'); assert.equal(dadStream.recs[0].msg, 'info from dad');
t.equal(dadStream.recs[1].msg, 'trace from son'); assert.equal(dadStream.recs[1].msg, 'trace from son');
t.equal(dadStream.recs[2].msg, 'debug from son'); assert.equal(dadStream.recs[2].msg, 'debug from son');
t.equal(sonStream.recs.length, 1); assert.equal(sonStream.recs.length, 1);
t.equal(sonStream.recs[0].msg, 'debug from son'); assert.equal(sonStream.recs[0].msg, 'debug from son');
t.end();
}); });
// issue #291 // issue #291
test('child should not lose parent "hostname"', function (t) { t.test('child should not lose parent "hostname"', function () {
var stream = new CapturingStream(); let stream = new CapturingStream();
var dad = bunyan.createLogger({ let dad = bunyan.createLogger({
name: 'hostname-test', name: 'hostname-test',
hostname: 'bar0', hostname: 'bar0',
streams: [ { streams: [ {
@ -147,15 +135,14 @@ test('child should not lose parent "hostname"', function (t) {
level: 'info' level: 'info'
} ] } ]
}); });
var son = dad.child({component: 'son'}); let son = dad.child({component: 'son'});
dad.info('HI'); dad.info('HI');
son.info('hi'); son.info('hi');
t.equal(stream.recs.length, 2); assert.equal(stream.recs.length, 2);
t.equal(stream.recs[0].hostname, 'bar0'); assert.equal(stream.recs[0].hostname, 'bar0');
t.equal(stream.recs[1].hostname, 'bar0'); assert.equal(stream.recs[1].hostname, 'bar0');
t.equal(stream.recs[1].component, 'son'); assert.equal(stream.recs[1].component, 'son');
t.end();
}); });

View file

@ -1,68 +0,0 @@
/*
* Copyright (c) 2017, Trent Mick.
*
* Test the bunyan CLI's handling of the "client_req" field.
* "client_req" is a common-ish Bunyan log field from restify-clients. See:
* // JSSTYLED
* https://github.com/restify/clients/blob/85374f87db9f4469de2605b6b15632b317cc12be/lib/helpers/bunyan.js#L213
*/
var exec = require('child_process').exec;
var fs = require('fs');
var path = require('path');
var _ = require('util').format;
var vasync = require('vasync');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
// ---- globals
var BUNYAN = path.resolve(__dirname, '../bin/bunyan');
// ---- tests
test('client_req extra newlines, client_res={} (pull #252)', function (t) {
var expect = [
/* BEGIN JSSTYLED */
'[2016-02-10T07:28:40.510Z] TRACE: aclientreq/23280 on danger0.local: request sent',
' GET /--ping HTTP/1.1',
'[2016-02-10T07:28:41.419Z] TRACE: aclientreq/23280 on danger0.local: Response received',
' HTTP/1.1 200 OK',
' request-id: e8a5a700-cfc7-11e5-a3dc-3b85d20f26ef',
' content-type: application/json'
/* END JSSTYLED */
].join('\n') + '\n';
exec(_('%s %s/corpus/clientreqres.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});
test('client_req.address is not used for Host header in 2.x (issue #504)',
function (t) {
exec(_('%s %s/corpus/client-req-with-address.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout, [
// JSSTYLED
'[2017-05-12T23:59:15.877Z] TRACE: minfo/66266 on sharptooth.local: request sent (client_req.address=127.0.0.1)',
' HEAD /dap/stor HTTP/1.1',
' accept: application/json, */*',
' host: foo.example.com',
' date: Fri, 12 May 2017 23:59:15 GMT',
''
].join('\n'));
t.end();
});
});

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2017, Trent Mick.
*
* Test the bunyan CLI's handling of the "client_req" field.
* "client_req" is a common-ish Bunyan log field from restify-clients. See:
* // JSSTYLED
* https://github.com/restify/clients/blob/85374f87db9f4469de2605b6b15632b317cc12be/lib/helpers/bunyan.js#L213
*/
import { exec, dirname } from './helper.mjs'
import { Eltro as t, assert} from 'eltro'
// ---- tests
t.test('client_req extra newlines, client_res={} (pull #252)', async function () {
const expected = [
/* BEGIN JSSTYLED */
'[2016-02-10T07:28:40.510Z] TRACE: aclientreq/23280 on danger0.local: request sent',
' GET /--ping HTTP/1.1',
'[2016-02-10T07:28:41.419Z] TRACE: aclientreq/23280 on danger0.local: Response received',
' HTTP/1.1 200 OK',
' request-id: e8a5a700-cfc7-11e5-a3dc-3b85d20f26ef',
' content-type: application/json'
/* END JSSTYLED */
].join('\n') + '\n';
let res = await exec(dirname('/corpus/clientreqres.log'))
assert.strictEqual(res.stdout, expected)
});
t.test('client_req.address is not used for Host header in 2.x (issue #504)', async function () {
const expected = [
// JSSTYLED
'[2017-05-12T23:59:15.877Z] TRACE: minfo/66266 on sharptooth.local: request sent (client_req.address=127.0.0.1)',
' HEAD /dap/stor HTTP/1.1',
' accept: application/json, */*',
' host: foo.example.com',
' date: Fri, 12 May 2017 23:59:15 GMT',
''
].join('\n')
let res = await exec(dirname('/corpus/client-req-with-address.log'))
assert.strictEqual(res.stdout, expected)
});

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2017, Trent Mick.
*
* Test the bunyan CLI's handling of the "res" field.
*/
var exec = require('child_process').exec;
var fs = require('fs');
var path = require('path');
var _ = require('util').format;
var vasync = require('vasync');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
// ---- globals
var BUNYAN = path.resolve(__dirname, '../bin/bunyan');
// ---- tests
test('res with "header" string (issue #444)', function (t) {
var expect = [
/* BEGIN JSSTYLED */
'[2017-08-02T22:37:34.798Z] INFO: res-header/76488 on danger0.local: response sent',
' HTTP/1.1 200 OK',
' Foo: bar',
' Date: Wed, 02 Aug 2017 22:37:34 GMT',
' Connection: keep-alive',
' Content-Length: 21'
/* END JSSTYLED */
].join('\n') + '\n';
exec(_('%s %s/corpus/res-header.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});
test('res without "header"', function (t) {
var expect = [
/* BEGIN JSSTYLED */
'[2017-08-02T22:37:34.798Z] INFO: res-header/76488 on danger0.local: response sent',
' HTTP/1.1 200 OK'
/* END JSSTYLED */
].join('\n') + '\n';
exec(_('%s %s/corpus/res-without-header.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});

38
test/cli-res.test.mjs Normal file
View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, Trent Mick.
*
* Test the bunyan CLI's handling of the "res" field.
*/
import { exec, dirname } from './helper.mjs'
import { Eltro as t, assert} from 'eltro'
// ---- tests
t.test('res with "header" string (issue #444)', async function () {
const expected = [
/* BEGIN JSSTYLED */
'[2017-08-02T22:37:34.798Z] INFO: res-header/76488 on danger0.local: response sent',
' HTTP/1.1 200 OK',
' Foo: bar',
' Date: Wed, 02 Aug 2017 22:37:34 GMT',
' Connection: keep-alive',
' Content-Length: 21'
/* END JSSTYLED */
].join('\n') + '\n';
let res = await exec(dirname('/corpus/res-header.log'))
assert.strictEqual(res.stdout, expected)
});
t.test('res without "header"', async function () {
const expected = [
/* BEGIN JSSTYLED */
'[2017-08-02T22:37:34.798Z] INFO: res-header/76488 on danger0.local: response sent',
' HTTP/1.1 200 OK'
/* END JSSTYLED */
].join('\n') + '\n';
let res = await exec(dirname('/corpus/res-without-header.log'))
assert.strictEqual(res.stdout, expected)
});

View file

@ -1,489 +0,0 @@
/*
* Copyright (c) 2015 Trent Mick. All rights reserved.
*
* Test the `bunyan` CLI.
*/
var p = console.warn;
var exec = require('child_process').exec;
var fs = require('fs');
var path = require('path');
var _ = require('util').format;
var vasync = require('vasync');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
// ---- globals
var BUNYAN = path.resolve(__dirname, '../bin/bunyan');
// ---- support stuff
/**
* Copies over all keys in `from` to `to`, or
* to a new object if `to` is not given.
*/
function objCopy(from, to) {
if (to === undefined) {
to = {};
}
for (var k in from) {
to[k] = from[k];
}
return to;
}
// ---- tests
test('--version', function (t) {
var version = require('../package.json').version;
exec(BUNYAN + ' --version', function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout, 'bunyan ' + version + '\n');
t.end();
});
});
test('--help', function (t) {
exec(BUNYAN + ' --help', function (err, stdout, stderr) {
t.ifError(err)
t.ok(stdout.indexOf('General options:') !== -1);
t.end();
});
});
test('-h', function (t) {
exec(BUNYAN + ' -h', function (err, stdout, stderr) {
t.ifError(err)
t.ok(stdout.indexOf('General options:') !== -1);
t.end();
});
});
test('--bogus', function (t) {
exec(BUNYAN + ' --bogus', function (err, stdout, stderr) {
t.ok(err, 'should error out')
t.equal(err.code, 1, '... with exit code 1')
t.end();
});
});
test('simple.log', function (t) {
exec(_('%s %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: '
+ 'My message\n');
t.end();
});
});
test('cat simple.log', function (t) {
exec(_('cat %s/corpus/simple.log | %s', __dirname, BUNYAN),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
/* JSSTYLED */
'[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: My message\n');
t.end();
}
);
});
test('time: simple.log utc long', function (t) {
exec(_('%s -o long --time utc %s/corpus/simple.log', BUNYAN, __dirname),
{env: process.env}, function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: '
+ 'My message\n');
t.end();
});
});
test('time: simple.log utc short', function (t) {
exec(_('%s -o short %s/corpus/simple.log', BUNYAN, __dirname),
{env: process.env}, function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'22:56:52.856Z INFO myservice: '
+ 'My message\n');
t.end();
});
});
test('simple.log with color', function (t) {
exec(_('%s --color %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
/* JSSTYLED */
'[2012-02-08T22:56:52.856Z] \u001b[36m INFO\u001b[39m: myservice/123 on example.com: \u001b[36mMy message\u001b[39m\n\u001b[0m');
t.end();
});
});
test('extrafield.log', function (t) {
exec(_('%s %s/corpus/extrafield.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: '
+ 'My message (extra=field)\n');
t.end();
});
});
test('extrafield.log with color', function (t) {
exec(_('%s --color %s/corpus/extrafield.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'[2012-02-08T22:56:52.856Z] \u001b[36m INFO\u001b[39m: '
+ 'myservice/123 '
+ 'on example.com: \u001b[36mMy message\u001b[39m'
+ ' (extra=field)\n\u001b[0m');
t.end();
});
});
test('bogus.log', function (t) {
exec(_('%s %s/corpus/bogus.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout, 'not a JSON line\n{"hi": "there"}\n');
t.end();
});
});
test('bogus.log -j', function (t) {
exec(_('%s -j %s/corpus/bogus.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout, 'not a JSON line\n{"hi": "there"}\n');
t.end();
});
});
test('all.log', function (t) {
exec(_('%s %s/corpus/all.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
// Just make sure don't blow up on this.
t.ifError(err)
t.end();
});
});
test('simple.log doesnotexist1.log doesnotexist2.log', function (t) {
exec(_('%s %s/corpus/simple.log doesnotexist1.log doesnotexist2.log',
BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ok(err)
t.equal(err.code, 2)
t.equal(stdout,
/* JSSTYLED */
'[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: My message\n');
// Note: node v0.6.10:
// ENOENT, no such file or directory 'asdf.log'
// but node v0.6.14:
// ENOENT, open 'asdf.log'
// io.js 2.2 (at least):
// ENOENT: no such file or directory, open 'doesnotexist1.log'
var matches = [
/^bunyan: ENOENT.*?, open 'doesnotexist1.log'/m,
/^bunyan: ENOENT.*?, open 'doesnotexist2.log'/m,
];
matches.forEach(function (match) {
t.ok(match.test(stderr), 'stderr matches ' + match.toString());
});
t.end();
}
);
});
test('multiple logs', function (t) {
var cmd = _('%s %s/corpus/log1.log %s/corpus/log2.log',
BUNYAN, __dirname, __dirname);
exec(cmd, function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, [
/* BEGIN JSSTYLED */
'[2012-05-08T16:57:55.586Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T16:58:55.586Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:01:49.339Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:47.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:49.339Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:57.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:08:01.105Z] INFO: agent2/76156 on headnode: message\n',
/* END JSSTYLED */
].join(''));
t.end();
});
});
test('multiple logs, bunyan format', function (t) {
var cmd = _('%s -o bunyan %s/corpus/log1.log %s/corpus/log2.log',
BUNYAN, __dirname, __dirname);
exec(cmd, function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, [
/* BEGIN JSSTYLED */
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T16:57:55.586Z","v":0}',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T16:58:55.586Z","v":0}',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:01:49.339Z","v":0}',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:47.404Z","v":0}',
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:49.339Z","v":0}',
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:49.404Z","v":0}',
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:49.404Z","v":0}',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:57.404Z","v":0}',
'{"name":"agent2","pid":76156,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:08:01.105Z","v":0}',
''
/* END JSSTYLED */
].join('\n'));
t.end();
});
});
test('log1.log.gz', function (t) {
exec(_('%s %s/corpus/log1.log.gz', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, [
/* BEGIN JSSTYLED */
'[2012-05-08T16:57:55.586Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.339Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
/* END JSSTYLED */
].join(''));
t.end();
});
});
test('mixed text and gzip logs', function (t) {
var cmd = _('%s %s/corpus/log1.log.gz %s/corpus/log2.log',
BUNYAN, __dirname, __dirname);
exec(cmd, function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, [
/* BEGIN JSSTYLED */
'[2012-05-08T16:57:55.586Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T16:58:55.586Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:01:49.339Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:47.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:49.339Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:57.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:08:01.105Z] INFO: agent2/76156 on headnode: message\n',
/* END JSSTYLED */
].join(''));
t.end();
});
});
test('--level 40', function (t) {
expect = [
/* BEGIN JSSTYLED */
'# levels\n',
'[2012-02-08T22:56:53.856Z] WARN: myservice/123 on example.com: My message\n',
'[2012-02-08T22:56:54.856Z] ERROR: myservice/123 on example.com: My message\n',
'[2012-02-08T22:56:55.856Z] LVL55: myservice/123 on example.com: My message\n',
'[2012-02-08T22:56:56.856Z] FATAL: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
/* END JSSTYLED */
].join('');
exec(_('%s -l 40 %s/corpus/all.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
exec(_('%s --level 40 %s/corpus/all.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});
});
test('--condition "this.level === 10 && this.pid === 123"', function (t) {
var expect = [
'# levels\n',
/* JSSTYLED */
'[2012-02-08T22:56:50.856Z] TRACE: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join('');
var cmd = _('%s -c "this.level === 10 && this.pid === 123"'
+ ' %s/corpus/all.log', BUNYAN, __dirname);
exec(cmd, function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
var cmd = _(
'%s --condition "this.level === 10 && this.pid === 123"'
+ ' %s/corpus/all.log', BUNYAN, __dirname);
exec(cmd, function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});
});
test('--condition "this.level === TRACE', function (t) {
var expect = [
'# levels\n',
/* JSSTYLED */
'[2012-02-08T22:56:50.856Z] TRACE: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join('');
var cmd = _('%s -c "this.level === TRACE" %s/corpus/all.log',
BUNYAN, __dirname);
exec(cmd, function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.done();
});
});
// multiple
test('multiple --conditions', function (t) {
var expect = [
'# levels\n',
/* JSSTYLED */
'[2012-02-08T22:56:53.856Z] WARN: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join('');
exec(_('%s %s/corpus/all.log -c "this.level === 40" -c "this.pid === 123"',
BUNYAN, __dirname), function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});
// https://github.com/trentm/node-bunyan/issues/30
//
// One of the records in corpus/withreq.log has a 'req'
// field with no 'headers'. Ditto for the 'res' field.
test('robust req handling', function (t) {
var expect = [
/* BEGIN JSSTYLED */
'[2012-08-08T10:25:47.636Z] DEBUG: amon-master/12859 on 9724a190-27b6-4fd8-830b-a574f839c67d: headAgentProbes respond (req_id=cce79d15-ffc2-487c-a4e4-e940bdaac31e, route=HeadAgentProbes, contentMD5=11FxOYiYfpMxmANj4kGJzg==)',
'[2012-08-08T10:25:47.637Z] INFO: amon-master/12859 on 9724a190-27b6-4fd8-830b-a574f839c67d: HeadAgentProbes handled: 200 (req_id=cce79d15-ffc2-487c-a4e4-e940bdaac31e, audit=true, remoteAddress=10.2.207.2, remotePort=50394, latency=3, secure=false, _audit=true, req.version=*)',
' HEAD /agentprobes?agent=ccf92af9-0b24-46b6-ab60-65095fdd3037 HTTP/1.1',
' accept: application/json',
' content-type: application/json',
' host: 10.2.207.16',
' connection: keep-alive',
' --',
' HTTP/1.1 200 OK',
' content-md5: 11FxOYiYfpMxmANj4kGJzg==',
' access-control-allow-origin: *',
' access-control-allow-headers: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',
' access-control-allow-methods: HEAD',
' access-control-expose-headers: X-Api-Version, X-Request-Id, X-Response-Time',
' connection: Keep-Alive',
' date: Wed, 08 Aug 2012 10:25:47 GMT',
' server: Amon Master/1.0.0',
' x-request-id: cce79d15-ffc2-487c-a4e4-e940bdaac31e',
' x-response-time: 3',
' --',
' route: {',
' "name": "HeadAgentProbes",',
' "version": false',
' }',
'[2012-08-08T10:25:47.637Z] INFO: amon-master/12859 on 9724a190-27b6-4fd8-830b-a574f839c67d: HeadAgentProbes handled: 200 (req_id=cce79d15-ffc2-487c-a4e4-e940bdaac31e, audit=true, remoteAddress=10.2.207.2, remotePort=50394, latency=3, secure=false, _audit=true, req.version=*)',
' HEAD /agentprobes?agent=ccf92af9-0b24-46b6-ab60-65095fdd3037 HTTP/1.1',
' --',
' HTTP/1.1 200 OK',
' --',
' route: {',
' "name": "HeadAgentProbes",',
' "version": false',
' }'
/* END JSSTYLED */
].join('\n') + '\n';
exec(_('%s %s/corpus/withreq.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});
// Some past crashes from issues.
test('should not crash on corpus/old-crashers/*.log', function (t) {
var oldCrashers = fs.readdirSync(
path.resolve(__dirname, 'corpus/old-crashers'))
.filter(function (f) { return f.slice(-4) === '.log'; });
vasync.forEachPipeline({
inputs: oldCrashers,
func: function (logName, next) {
exec(_('%s %s/corpus/old-crashers/%s', BUNYAN, __dirname, logName),
function (err, stdout, stderr) {
next(err);
});
}
}, function (err, results) {
t.ifError(err);
t.end();
});
});
test('should only show nonempty response bodies', function (t) {
var expect = [
/* BEGIN JSSTYLED */
'[2016-02-10T07:28:41.419Z] INFO: myservice/123 on example.com: UnauthorizedError',
' HTTP/1.1 401 Unauthorized',
' content-type: text/plain',
' date: Sat, 07 Mar 2015 06:58:43 GMT',
'[2016-02-10T07:28:41.419Z] INFO: myservice/123 on example.com: hello',
' HTTP/1.1 200 OK',
' content-type: text/plain',
' content-length: 0',
' date: Sat, 07 Mar 2015 06:58:43 GMT',
' ',
' hello',
'[2016-02-10T07:28:41.419Z] INFO: myservice/123 on example.com: UnauthorizedError',
' HTTP/1.1 401 Unauthorized',
' content-type: text/plain',
' date: Sat, 07 Mar 2015 06:58:43 GMT'
/* END JSSTYLED */
].join('\n') + '\n';
exec(_('%s %s/corpus/content-length-0-res.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, expect);
t.end();
});
});

302
test/cli.test.mjs Normal file
View file

@ -0,0 +1,302 @@
/*
* Copyright (c) 2015 Trent Mick. All rights reserved.
*
* Test the `bunyan` CLI.
*/
import fs from 'fs'
import path from 'path'
import { exec, dirname } from './helper.mjs'
import { Eltro as t, assert} from 'eltro'
// ---- assertable variables
const catter = process.platform === 'win32' ? 'type' : 'cat'
const assertSimpleLog = '[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: My message\n'
// ---- tests
t.test('--version', async function () {
let pckg = JSON.parse(fs.readFileSync(dirname('/../package.json')))
const version = pckg.version
let res = await exec('--version')
assert.strictEqual(res.stdout, 'bunyan ' + version + '\n')
});
t.test('--help', async function () {
let res = await exec('--help')
assert.match(res.stdout, /General options:/)
});
t.test('-h', async function () {
let res = await exec('-h')
assert.match(res.stdout, /General options:/)
});
t.test('--bogus', async function () {
let err = await assert.isRejected(exec('--bogus'))
assert.strictEqual(err.code, 1)
});
t.test('simple.log', async function () {
let res = await exec(dirname('/corpus/simple.log'))
assert.strictEqual(res.stdout, assertSimpleLog)
});
t.test(`${catter} simple.log`, async function () {
let res = await exec('', `${catter} ${dirname('/corpus/simple.log')} | node `)
assert.strictEqual(res.stdout, assertSimpleLog)
});
t.test('time: simple.log utc long', async function () {
let res = await exec('-o long --time utc ' + dirname('/corpus/simple.log'))
assert.strictEqual(res.stdout, assertSimpleLog)
});
t.test('time: simple.log utc short', async function () {
let res = await exec('-o short ' + dirname('/corpus/simple.log'))
assert.strictEqual(res.stdout, '22:56:52.856Z INFO myservice: My message\n')
});
t.test('simple.log with color', async function () {
let res = await exec(dirname('/corpus/simple.log'))
assert.notMatch(res.stdout, /\[2012-02-08T22:56:52.856Z\] [^ ]+ INFO[^:]+:/)
res = await exec('--color ' + dirname('/corpus/simple.log'))
assert.match(res.stdout, /\[2012-02-08T22:56:52.856Z\] [^ ]+ INFO[^:]+:/)
});
t.test('extrafield.log', async function () {
let res = await exec(dirname('/corpus/extrafield.log'))
assert.strictEqual(res.stdout, '[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: My message (extra=field)\n')
});
t.test('extrafield.log with color', async function () {
let res = await exec(dirname('/corpus/extrafield.log'))
assert.notMatch(res.stdout, /My message[^ ]+ \(extra=field\)\n.+/)
res = await exec('--color ' + dirname('/corpus/extrafield.log'))
assert.match(res.stdout, /My message[^ ]+ \(extra=field\)\n.+/)
});
t.test('bogus.log', async function () {
let res = await exec(dirname('/corpus/bogus.log'))
assert.strictEqual(res.stdout, 'not a JSON line\n{"hi": "there"}\n')
});
t.test('bogus.log -j', async function () {
let res = await exec('-j ' + dirname('/corpus/bogus.log'))
assert.strictEqual(res.stdout, 'not a JSON line\n{"hi": "there"}\n')
});
t.test('all.log', async function () {
// Just make sure don't blow up on this.
await exec(dirname('/corpus/all.log'))
});
t.test('simple.log doesnotexist1.log doesnotexist2.log', async function () {
let res = await assert.isRejected(exec(dirname('/corpus/simple.log') + ' doesnotexist1.log doesnotexist2.log'))
assert.strictEqual(res.stdout, '[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: My message\n')
// Note: node v0.6.10:
// ENOENT, no such file or directory 'asdf.log'
// but node v0.6.14:
// ENOENT, open 'asdf.log'
// io.js 2.2 (at least):
// ENOENT: no such file or directory, open 'doesnotexist1.log'
let matches = [
/^bunyan: ENOENT.*?, open '.+doesnotexist1.log'/m,
/^bunyan: ENOENT.*?, open '.+doesnotexist2.log'/m,
];
matches.forEach(function (match) {
assert.match(res.stderr, match);
});
});
t.test('multiple logs', async function () {
let res = await exec(dirname('/corpus/log1.log') + ' ' + dirname('/corpus/log2.log'))
assert.strictEqual(res.stdout, [
'[2012-05-08T16:57:55.586Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T16:58:55.586Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:01:49.339Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:47.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:49.339Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:57.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:08:01.105Z] INFO: agent2/76156 on headnode: message\n',
].join(''))
});
t.test('multiple logs, bunyan format', async function () {
let res = await exec('-o bunyan ' + dirname('/corpus/log1.log') + ' ' + dirname('/corpus/log2.log'))
assert.strictEqual(res.stdout, [
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T16:57:55.586Z","v":0}\n',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T16:58:55.586Z","v":0}\n',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:01:49.339Z","v":0}\n',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:47.404Z","v":0}\n',
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:49.339Z","v":0}\n',
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:49.404Z","v":0}\n',
'{"name":"agent1","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:49.404Z","v":0}\n',
'{"name":"agent2","pid":73267,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:02:57.404Z","v":0}\n',
'{"name":"agent2","pid":76156,"hostname":"headnode","level":30,"msg":"message","time":"2012-05-08T17:08:01.105Z","v":0}\n',
].join(''))
});
t.test('log1.log.gz', async function () {
let res = await exec(dirname('/corpus/log1.log.gz'))
assert.strictEqual(res.stdout, [
'[2012-05-08T16:57:55.586Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.339Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
].join(''))
});
t.test('mixed text and gzip logs', async function () {
let res = await exec(dirname('/corpus/log1.log.gz') + ' ' + dirname('/corpus/log2.log'))
assert.strictEqual(res.stdout, [
'[2012-05-08T16:57:55.586Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T16:58:55.586Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:01:49.339Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:47.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:02:49.339Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:49.404Z] INFO: agent1/73267 on headnode: message\n',
'[2012-05-08T17:02:57.404Z] INFO: agent2/73267 on headnode: message\n',
'[2012-05-08T17:08:01.105Z] INFO: agent2/76156 on headnode: message\n',
].join(''))
});
t.test('--level 40', async function () {
let res = await exec('-l 40 ' + dirname('/corpus/all.log'))
assert.strictEqual(res.stdout, [
'# levels\n',
'[2012-02-08T22:56:53.856Z] WARN: myservice/123 on example.com: My message\n',
'[2012-02-08T22:56:54.856Z] ERROR: myservice/123 on example.com: My message\n',
'[2012-02-08T22:56:55.856Z] LVL55: myservice/123 on example.com: My message\n',
'[2012-02-08T22:56:56.856Z] FATAL: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join(''))
});
t.test('--condition "this.level === 10 && this.pid === 123"', async function () {
let res = await exec('-c "this.level === 10 && this.pid === 123" ' + dirname('/corpus/all.log'))
assert.strictEqual(res.stdout, [
'# levels\n',
'[2012-02-08T22:56:50.856Z] TRACE: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join(''))
});
t.test('--condition "this.level === TRACE', async function () {
let res = await exec('-c "this.level === TRACE" ' + dirname('/corpus/all.log'))
assert.strictEqual(res.stdout, [
'# levels\n',
'[2012-02-08T22:56:50.856Z] TRACE: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join(''))
});
t.test('multiple --conditions', async function () {
let res = await exec(dirname('/corpus/all.log') + ' -c "this.level === 40" -c "this.pid === 123"')
assert.strictEqual(res.stdout, [
'# levels\n',
'[2012-02-08T22:56:53.856Z] WARN: myservice/123 on example.com: My message\n',
'\n',
'# extra fields\n',
'\n',
'# bogus\n',
'not a JSON line\n',
'{"hi": "there"}\n'
].join(''))
});
// https://github.com/trentm/node-bunyan/issues/30
//
// One of the records in corpus/withreq.log has a 'req'
// field with no 'headers'. Ditto for the 'res' field.
t.test('robust req handling', async function () {
let res = await exec(dirname('/corpus/withreq.log'))
assert.strictEqual(res.stdout, [
'[2012-08-08T10:25:47.636Z] DEBUG: amon-master/12859 on 9724a190-27b6-4fd8-830b-a574f839c67d: headAgentProbes respond (req_id=cce79d15-ffc2-487c-a4e4-e940bdaac31e, route=HeadAgentProbes, contentMD5=11FxOYiYfpMxmANj4kGJzg==)',
'[2012-08-08T10:25:47.637Z] INFO: amon-master/12859 on 9724a190-27b6-4fd8-830b-a574f839c67d: HeadAgentProbes handled: 200 (req_id=cce79d15-ffc2-487c-a4e4-e940bdaac31e, audit=true, remoteAddress=10.2.207.2, remotePort=50394, latency=3, secure=false, _audit=true, req.version=*)',
' HEAD /agentprobes?agent=ccf92af9-0b24-46b6-ab60-65095fdd3037 HTTP/1.1',
' accept: application/json',
' content-type: application/json',
' host: 10.2.207.16',
' connection: keep-alive',
' --',
' HTTP/1.1 200 OK',
' content-md5: 11FxOYiYfpMxmANj4kGJzg==',
' access-control-allow-origin: *',
' access-control-allow-headers: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',
' access-control-allow-methods: HEAD',
' access-control-expose-headers: X-Api-Version, X-Request-Id, X-Response-Time',
' connection: Keep-Alive',
' date: Wed, 08 Aug 2012 10:25:47 GMT',
' server: Amon Master/1.0.0',
' x-request-id: cce79d15-ffc2-487c-a4e4-e940bdaac31e',
' x-response-time: 3',
' --',
' route: {',
' "name": "HeadAgentProbes",',
' "version": false',
' }',
'[2012-08-08T10:25:47.637Z] INFO: amon-master/12859 on 9724a190-27b6-4fd8-830b-a574f839c67d: HeadAgentProbes handled: 200 (req_id=cce79d15-ffc2-487c-a4e4-e940bdaac31e, audit=true, remoteAddress=10.2.207.2, remotePort=50394, latency=3, secure=false, _audit=true, req.version=*)',
' HEAD /agentprobes?agent=ccf92af9-0b24-46b6-ab60-65095fdd3037 HTTP/1.1',
' --',
' HTTP/1.1 200 OK',
' --',
' route: {',
' "name": "HeadAgentProbes",',
' "version": false',
' }'
].join('\n') + '\n')
});
// Some past crashes from issues.
t.test('should not crash on corpus/old-crashers/*.log', async function () {
let oldCrashers = fs.readdirSync(
path.resolve(dirname('/corpus/old-crashers')))
.filter(function (f) { return f.slice(-4) === '.log'; });
await Promise.all(oldCrashers.map(function(logFile) {
return exec(dirname('/corpus/old-crashers/' + logFile))
}))
});
t.test('should only show nonempty response bodies', async function () {
let res = await exec(dirname('/corpus/content-length-0-res.log'))
assert.strictEqual(res.stdout, [
'[2016-02-10T07:28:41.419Z] INFO: myservice/123 on example.com: UnauthorizedError',
' HTTP/1.1 401 Unauthorized',
' content-type: text/plain',
' date: Sat, 07 Mar 2015 06:58:43 GMT',
'[2016-02-10T07:28:41.419Z] INFO: myservice/123 on example.com: hello',
' HTTP/1.1 200 OK',
' content-type: text/plain',
' content-length: 0',
' date: Sat, 07 Mar 2015 06:58:43 GMT',
' ',
' hello',
'[2016-02-10T07:28:41.419Z] INFO: myservice/123 on example.com: UnauthorizedError',
' HTTP/1.1 401 Unauthorized',
' content-type: text/plain',
' date: Sat, 07 Mar 2015 06:58:43 GMT'
].join('\n') + '\n');
});

View file

@ -1,154 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test type checking on creation of the Logger.
*/
var bunyan = require('../lib/bunyan'),
Logger = bunyan;
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
test('ensure Logger creation options', function (t) {
t.throws(function () { new Logger(); },
/options \(object\) is required/,
'no options should throw');
t.throws(function () { new Logger({}); },
/options\.name \(string\) is required/,
'no options.name should throw');
t.doesNotThrow(function () { new Logger({name: 'foo'}); },
'just options.name should be sufficient');
var options = {name: 'foo', stream: process.stdout, streams: []};
t.throws(function () { new Logger(options); },
/* JSSTYLED */
/cannot mix "streams" and "stream" options/,
'cannot use "stream" and "streams"');
// https://github.com/trentm/node-bunyan/issues/3
options = {name: 'foo', streams: {}};
t.throws(function () { new Logger(options); },
/invalid options.streams: must be an array/,
'"streams" must be an array');
options = {name: 'foo', serializers: 'a string'};
t.throws(function () { new Logger(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be a string');
options = {name: 'foo', serializers: [1, 2, 3]};
t.throws(function () { new Logger(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be an array');
t.end();
});
test('ensure Logger constructor is safe without new', function (t) {
t.doesNotThrow(function () { Logger({name: 'foo'}); },
'constructor should call self with new if necessary');
t.end();
});
test('ensure Logger creation options (createLogger)', function (t) {
t.throws(function () { bunyan.createLogger(); },
/options \(object\) is required/,
'no options should throw');
t.throws(function () { bunyan.createLogger({}); },
/options\.name \(string\) is required/,
'no options.name should throw');
t.doesNotThrow(function () { bunyan.createLogger({name: 'foo'}); },
'just options.name should be sufficient');
var options = {name: 'foo', stream: process.stdout, streams: []};
t.throws(function () { bunyan.createLogger(options); },
/* JSSTYLED */
/cannot mix "streams" and "stream" options/,
'cannot use "stream" and "streams"');
// https://github.com/trentm/node-bunyan/issues/3
options = {name: 'foo', streams: {}};
t.throws(function () { bunyan.createLogger(options); },
/invalid options.streams: must be an array/,
'"streams" must be an array');
options = {name: 'foo', serializers: 'a string'};
t.throws(function () { bunyan.createLogger(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be a string');
options = {name: 'foo', serializers: [1, 2, 3]};
t.throws(function () { bunyan.createLogger(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be an array');
t.end();
});
test('ensure Logger child() options', function (t) {
var log = new Logger({name: 'foo'});
t.doesNotThrow(function () { log.child(); },
'no options should be fine');
t.doesNotThrow(function () { log.child({}); },
'empty options should be fine too');
t.throws(function () { log.child({name: 'foo'}); },
/invalid options.name: child cannot set logger name/,
'child cannot change name');
var options = {stream: process.stdout, streams: []};
t.throws(function () { log.child(options); },
/* JSSTYLED */
/cannot mix "streams" and "stream" options/,
'cannot use "stream" and "streams"');
// https://github.com/trentm/node-bunyan/issues/3
options = {streams: {}};
t.throws(function () { log.child(options); },
/invalid options.streams: must be an array/,
'"streams" must be an array');
options = {serializers: 'a string'};
t.throws(function () { log.child(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be a string');
options = {serializers: [1, 2, 3]};
t.throws(function () { log.child(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be an array');
t.end();
});
test('ensure Logger() rejects non-Logger parents', function (t) {
var dad = new Logger({name: 'dad', streams: []});
t.throws(function () { new Logger({}, {}); },
/invalid Logger creation: do not pass a second arg/,
'Logger arguments must be valid');
t.doesNotThrow(function () { new Logger(dad, {}); },
'Logger allows Logger instance as parent');
t.end();
});

124
test/ctor.test.mjs Normal file
View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test type checking on creation of the Logger.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
t.test('ensure Logger creation options', function () {
assert.throws(function () { new bunyan(); },
/options \(object\) is required/,
'no options should throw');
assert.throws(function () { new bunyan({}); },
/options\.name \(string\) is required/,
'no options.name should throw');
new bunyan({name: 'foo'});
let options = {name: 'foo', stream: process.stdout, streams: []};
assert.throws(function () { new bunyan(options); },
/cannot mix "streams" and "stream" options/, // JSSTYLED
'cannot use "stream" and "streams"');
// https://github.com/trentm/node-bunyan/issues/3
options = {name: 'foo', streams: {}};
assert.throws(function () { new bunyan(options); },
/invalid options.streams: must be an array/,
'"streams" must be an array');
options = {name: 'foo', serializers: 'a string'};
assert.throws(function () { new bunyan(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be a string');
options = {name: 'foo', serializers: [1, 2, 3]};
assert.throws(function () { new bunyan(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be an array');
});
t.test('ensure Logger constructor is safe without new', function () {
bunyan({name: 'foo'})
});
t.test('ensure Logger creation options (createLogger)', function () {
assert.throws(function () { bunyan.createLogger(); },
/options \(object\) is required/,
'no options should throw');
assert.throws(function () { bunyan.createLogger({}); },
/options\.name \(string\) is required/,
'no options.name should throw');
bunyan.createLogger({name: 'foo'});
let options = {name: 'foo', stream: process.stdout, streams: []};
assert.throws(function () { bunyan.createLogger(options); },
/cannot mix "streams" and "stream" options/, // JSSTYLED
'cannot use "stream" and "streams"');
// https://github.com/trentm/node-bunyan/issues/3
options = {name: 'foo', streams: {}};
assert.throws(function () { bunyan.createLogger(options); },
/invalid options.streams: must be an array/,
'"streams" must be an array');
options = {name: 'foo', serializers: 'a string'};
assert.throws(function () { bunyan.createLogger(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be a string');
options = {name: 'foo', serializers: [1, 2, 3]};
assert.throws(function () { bunyan.createLogger(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be an array');
});
t.test('ensure Logger child() options', function () {
let log = new bunyan({name: 'foo'});
log.child();
log.child({});
assert.throws(function () { log.child({name: 'foo'}); },
/invalid options.name: child cannot set logger name/,
'child cannot change name');
let options = {stream: process.stdout, streams: []};
assert.throws(function () { log.child(options); },
/cannot mix "streams" and "stream" options/, // JSSTYLED
'cannot use "stream" and "streams"');
// https://github.com/trentm/node-bunyan/issues/3
options = {streams: {}};
assert.throws(function () { log.child(options); },
/invalid options.streams: must be an array/,
'"streams" must be an array');
options = {serializers: 'a string'};
assert.throws(function () { log.child(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be a string');
options = {serializers: [1, 2, 3]};
assert.throws(function () { log.child(options); },
/invalid options.serializers: must be an object/,
'"serializers" cannot be an array');
});
t.test('ensure Logger() rejects non-Logger parents', function () {
let dad = new bunyan({name: 'dad', streams: []});
assert.throws(function () { new bunyan({}, {}); },
/invalid Logger creation: do not pass a second arg/,
'Logger arguments must be valid');
new bunyan(dad, {});
});

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Make sure cycles are safe.
*/
var Logger = require('../lib/bunyan.js');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
var Stream = require('stream').Stream;
var outstr = new Stream;
outstr.writable = true;
var output = [];
outstr.write = function (c) {
output.push(JSON.parse(c + ''));
};
outstr.end = function (c) {
if (c) this.write(c);
this.emit('end');
};
// these are lacking a few fields that will probably never match
var expect =
[
{
'name': 'blammo',
'level': 30,
'msg': 'bango { bang: \'boom\', KABOOM: [Circular] }',
'v': 0
},
{
'name': 'blammo',
'level': 30,
'msg': 'kaboom { bang: \'boom\', KABOOM: [Circular] }',
'v': 0
},
{
'name': 'blammo',
'level': 30,
'bang': 'boom',
'KABOOM': {
'bang': 'boom',
'KABOOM': '[Circular]'
},
'msg': '',
'v': 0
}
];
var log = new Logger({
name: 'blammo',
streams: [
{
type: 'stream',
level: 'info',
stream: outstr
}
]
});
test('cycles', function (t) {
outstr.on('end', function () {
output.forEach(function (o, i) {
// Drop variable parts for comparison.
delete o.hostname;
delete o.pid;
delete o.time;
// Hack object/dict comparison: JSONify.
t.equal(JSON.stringify(o), JSON.stringify(expect[i]),
'log item ' + i + ' matches');
});
t.end();
});
var obj = { bang: 'boom' };
obj.KABOOM = obj;
log.info('bango', obj);
log.info('kaboom', obj.KABOOM);
log.info(obj);
outstr.end();
t.ok('did not throw');
});

83
test/cycles.test.mjs Normal file
View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Make sure cycles are safe.
*/
import { Stream } from 'stream'
import { Eltro as t, assert} from 'eltro'
import Logger from '../lib/bunyan.mjs'
var outstr = new Stream;
outstr.writable = true;
var output = [];
outstr.write = function (c) {
output.push(JSON.parse(c + ''));
};
outstr.end = function (c) {
if (c) this.write(c);
this.emit('end');
};
// these are lacking a few fields that will probably never match
var expect = [
{
'name': 'blammo',
'level': 30,
'msg': 'bango <ref *1> { bang: \'boom\', KABOOM: [Circular *1] }',
'v': 0
},
{
'name': 'blammo',
'level': 30,
'msg': 'kaboom <ref *1> { bang: \'boom\', KABOOM: [Circular *1] }',
'v': 0
},
{
'name': 'blammo',
'level': 30,
'bang': 'boom',
'KABOOM': {
'bang': 'boom',
'KABOOM': '[Circular]'
},
'msg': '',
'v': 0
}
];
var log = new Logger({
name: 'blammo',
streams: [
{
type: 'stream',
level: 'info',
stream: outstr
}
]
});
t.test('cycles', function (cb) {
outstr.on('end', function () {
output.forEach(function (o, i) {
// Drop variable parts for comparison.
delete o.hostname;
delete o.pid;
delete o.time;
// Hack object/dict comparison: JSONify.
try {
assert.strictEqual(JSON.stringify(o), JSON.stringify(expect[i]))
} catch (err) {
cb(err)
}
});
cb()
});
var obj = { bang: 'boom' };
obj.KABOOM = obj;
log.info('bango', obj);
log.info('kaboom', obj.KABOOM);
log.info(obj);
outstr.end();
});

View file

@ -1,151 +0,0 @@
/*
* Copyright 2016 Trent Mick
*
* Test emission and handling of 'error' event in a logger with a 'path'
* stream.
*/
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
var BOGUS_PATH = '/this/path/is/bogus.log';
test('error event on file stream (reemitErrorEvents=undefined)', function (t) {
var log = bunyan.createLogger(
{name: 'error-event-1', streams: [ {path: BOGUS_PATH} ]});
log.on('error', function (err, stream) {
t.ok(err, 'got err in error event: ' + err);
t.equal(err.code, 'ENOENT', 'error code is ENOENT');
t.ok(stream, 'got a stream argument');
t.equal(stream.path, BOGUS_PATH);
t.equal(stream.type, 'file');
t.end();
});
log.info('info log message');
});
test('error event on file stream (reemitErrorEvents=true)', function (t) {
var log = bunyan.createLogger({
name: 'error-event-2',
streams: [ {
path: BOGUS_PATH,
reemitErrorEvents: true
} ]
});
log.on('error', function (err, stream) {
t.ok(err, 'got err in error event: ' + err);
t.equal(err.code, 'ENOENT', 'error code is ENOENT');
t.ok(stream, 'got a stream argument');
t.equal(stream.path, BOGUS_PATH);
t.equal(stream.type, 'file');
t.end();
});
log.info('info log message');
});
test('error event on file stream (reemitErrorEvents=false)',
function (t) {
var log = bunyan.createLogger({
name: 'error-event-3',
streams: [ {
path: BOGUS_PATH,
reemitErrorEvents: false
} ]
});
// Hack into the underlying created file stream to catch the error event.
log.streams[0].stream.on('error', function (err) {
t.ok(err, 'got error event on the file stream');
t.end();
});
log.on('error', function (err, stream) {
t.fail('should not have gotten error event on logger');
t.end();
});
log.info('info log message');
});
function MyErroringStream() {}
util.inherits(MyErroringStream, EventEmitter);
MyErroringStream.prototype.write = function (rec) {
this.emit('error', new Error('boom'));
}
test('error event on raw stream (reemitErrorEvents=undefined)', function (t) {
var estream = new MyErroringStream();
var log = bunyan.createLogger({
name: 'error-event-raw',
streams: [
{
stream: estream,
type: 'raw'
}
]
});
estream.on('error', function (err) {
t.ok(err, 'got error event on the raw stream');
t.end();
});
log.on('error', function (err, stream) {
t.fail('should not have gotten error event on logger');
t.end();
});
log.info('info log message');
});
test('error event on raw stream (reemitErrorEvents=false)', function (t) {
var estream = new MyErroringStream();
var log = bunyan.createLogger({
name: 'error-event-raw',
streams: [
{
stream: estream,
type: 'raw',
reemitErrorEvents: false
}
]
});
estream.on('error', function (err) {
t.ok(err, 'got error event on the raw stream');
t.end();
});
log.on('error', function (err, stream) {
t.fail('should not have gotten error event on logger');
t.end();
});
log.info('info log message');
});
test('error event on raw stream (reemitErrorEvents=true)', function (t) {
var estream = new MyErroringStream();
var log = bunyan.createLogger({
name: 'error-event-raw',
streams: [
{
stream: estream,
type: 'raw',
reemitErrorEvents: true
}
]
});
log.on('error', function (err, stream) {
t.ok(err, 'got err in error event: ' + err);
t.equal(err.message, 'boom');
t.ok(stream, 'got a stream argument');
t.ok(stream.stream instanceof MyErroringStream);
t.equal(stream.type, 'raw');
t.end();
});
log.info('info log message');
});

164
test/error-event.test.mjs Normal file
View file

@ -0,0 +1,164 @@
/*
* Copyright 2016 Trent Mick
*
* Test emission and handling of 'error' event in a logger with a 'path'
* stream.
*/
import { EventEmitter } from 'events'
import util from 'util'
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
var BOGUS_PATH = '/this/path/is/bogus.log';
t.test('error event on file stream (reemitErrorEvents=undefined)', function (cb) {
var log = bunyan.createLogger(
{name: 'error-event-1', streams: [ {path: BOGUS_PATH} ]});
log.on('error', function (err, stream) {
try {
assert.ok(err, 'got err in error event: ' + err);
assert.strictEqual(err.code, 'ENOENT', 'error code is ENOENT');
assert.ok(stream, 'got a stream argument');
assert.strictEqual(stream.path, BOGUS_PATH);
assert.strictEqual(stream.type, 'file');
cb()
} catch (err) {
cb(err)
}
});
log.info('info log message');
});
t.test('error event on file stream (reemitErrorEvents=true)', function (cb) {
var log = bunyan.createLogger({
name: 'error-event-2',
streams: [ {
path: BOGUS_PATH,
reemitErrorEvents: true
} ]
});
log.on('error', function (err, stream) {
try {
assert.ok(err, 'got err in error event: ' + err);
assert.strictEqual(err.code, 'ENOENT', 'error code is ENOENT');
assert.ok(stream, 'got a stream argument');
assert.strictEqual(stream.path, BOGUS_PATH);
assert.strictEqual(stream.type, 'file');
cb()
} catch(err) {
cb(err)
}
});
log.info('info log message');
});
t.test('error event on file stream (reemitErrorEvents=false)',
function (cb) {
var log = bunyan.createLogger({
name: 'error-event-3',
streams: [ {
path: BOGUS_PATH,
reemitErrorEvents: false
} ]
});
// Hack into the underlying created file stream to catch the error event.
log.streams[0].stream.on('error', function (err) {
try {
assert.ok(err, 'got error event on the file stream');
cb()
} catch (err) {
cb(err)
}
});
log.on('error', function (err, stream) {
cb('should not have gotten error event on logger')
});
log.info('info log message');
});
function MyErroringStream() {}
util.inherits(MyErroringStream, EventEmitter);
MyErroringStream.prototype.write = function (rec) {
this.emit('error', new Error('boom'));
}
t.test('error event on raw stream (reemitErrorEvents=undefined)', function (cb) {
var estream = new MyErroringStream();
var log = bunyan.createLogger({
name: 'error-event-raw',
streams: [
{
stream: estream,
type: 'raw'
}
]
});
estream.on('error', function (err) {
try {
assert.ok(err, 'got error event on the raw stream');
cb()
} catch (err) {
cb(err)
}
});
log.on('error', function (err, stream) {
cb('should not have gotten error event on logger');
});
log.info('info log message');
});
t.test('error event on raw stream (reemitErrorEvents=false)', function (cb) {
var estream = new MyErroringStream();
var log = bunyan.createLogger({
name: 'error-event-raw',
streams: [
{
stream: estream,
type: 'raw',
reemitErrorEvents: false
}
]
});
estream.on('error', function (err) {
try {
assert.ok(err, 'got error event on the raw stream');
cb()
} catch (err) {
cb(err)
}
});
log.on('error', function (err, stream) {
cb('should not have gotten error event on logger');
});
log.info('info log message');
});
t.test('error event on raw stream (reemitErrorEvents=true)', function (cb) {
var estream = new MyErroringStream();
var log = bunyan.createLogger({
name: 'error-event-raw',
streams: [
{
stream: estream,
type: 'raw',
reemitErrorEvents: true
}
]
});
log.on('error', function (err, stream) {
try {
assert.ok(err, 'got err in error event: ' + err);
assert.strictEqual(err.message, 'boom');
assert.ok(stream, 'got a stream argument');
assert.ok(stream.stream instanceof MyErroringStream);
assert.strictEqual(stream.type, 'raw');
cb()
} catch (err) {
cb(err)
}
});
log.info('info log message');
});

29
test/helper.mjs Normal file
View file

@ -0,0 +1,29 @@
import { exec as ex } from 'child_process'
import path from 'path'
import { fileURLToPath } from 'url'
let __dirname = path.dirname(fileURLToPath(import.meta.url))
var BUNYAN = path.resolve(__dirname, '../bin/bunyan.mjs');
export function exec(parameter, prefix = 'node', bunnyboy = BUNYAN) {
let command = `${prefix} ${bunnyboy} ${parameter}`
return new Promise(function(res, rej) {
ex(command,
function (err, stdout, stderr) {
if (err) {
err.stdout = stdout
err.stderr = stderr
return rej(err)
}
res({
stdout,
stderr,
})
}
)
})
}
export function dirname(file) {
return path.resolve(__dirname + file)
}

View file

@ -1,98 +0,0 @@
/*
* Copyright (c) 2014 Trent Mick. All rights reserved.
*
* Test the `log.level(...)`.
*/
var util = require('util'),
format = util.format,
inspect = util.inspect;
var p = console.log;
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
// ---- test boolean `log.<level>()` calls
var log1 = bunyan.createLogger({
name: 'log1',
streams: [
{
path: __dirname + '/level.test.log1.log',
level: 'info'
}
]
});
test('log.level() -> level num', function (t) {
t.equal(log1.level(), bunyan.INFO);
t.end();
});
test('log.level(<const>)', function (t) {
log1.level(bunyan.DEBUG);
t.equal(log1.level(), bunyan.DEBUG);
t.end();
});
test('log.level(<num>)', function (t) {
log1.level(10);
t.equal(log1.level(), bunyan.TRACE);
t.end();
});
test('log.level(<name>)', function (t) {
log1.level('error');
t.equal(log1.level(), bunyan.ERROR);
t.end();
});
// A trick to turn logging off.
// See <https://github.com/trentm/node-bunyan/pull/148#issuecomment-53232979>.
test('log.level(FATAL + 1)', function (t) {
log1.level(bunyan.FATAL + 1);
t.equal(log1.level(), bunyan.FATAL + 1);
t.end();
});
test('log.level(<weird numbers>)', function (t) {
log1.level(0);
t.equal(log1.level(), 0);
log1.level(Number.MAX_VALUE);
t.equal(log1.level(), Number.MAX_VALUE);
log1.level(Infinity);
t.equal(log1.level(), Infinity);
t.end();
});
test('log.level(<invalid values>)', function (t) {
t.throws(function () {
var log = bunyan.createLogger({name: 'invalid', level: 'booga'});
// JSSTYLED
}, /unknown level name: "booga"/);
t.throws(function () {
var log = bunyan.createLogger({name: 'invalid', level: []});
}, /cannot resolve level: invalid arg \(object\): \[\]/);
t.throws(function () {
var log = bunyan.createLogger({name: 'invalid', level: true});
}, /cannot resolve level: invalid arg \(boolean\): true/);
t.throws(function () {
var log = bunyan.createLogger({name: 'invalid', level: -1});
}, /level is not a positive integer: -1/);
t.throws(function () {
var log = bunyan.createLogger({name: 'invalid', level: 3.14});
}, /level is not a positive integer: 3.14/);
t.throws(function () {
var log = bunyan.createLogger({name: 'invalid', level: -Infinity});
}, /level is not a positive integer: -Infinity/);
t.end();
});

79
test/level.test.mjs Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2014 Trent Mick. All rights reserved.
*
* Test the `log.level(...)`.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
import { dirname } from './helper.mjs'
// ---- test boolean `log.<level>()` calls
var log1 = bunyan.createLogger({
name: 'log1',
streams: [
{
level: 'info',
stream: process.stdout,
}
]
});
t.test('log.level() -> level num', function () {
assert.strictEqual(log1.level(), bunyan.INFO);
});
t.test('log.level(<const>)', function () {
log1.level(bunyan.DEBUG);
assert.strictEqual(log1.level(), bunyan.DEBUG);
});
t.test('log.level(<num>)', function () {
log1.level(10);
assert.strictEqual(log1.level(), bunyan.TRACE);
});
t.test('log.level(<name>)', function () {
log1.level('error');
assert.strictEqual(log1.level(), bunyan.ERROR);
});
// A trick to turn logging off.
// See <https://github.com/trentm/node-bunyan/pull/148#issuecomment-53232979>.
t.test('log.level(FATAL + 1)', function () {
log1.level(bunyan.FATAL + 1);
assert.strictEqual(log1.level(), bunyan.FATAL + 1);
});
t.test('log.level(<weird numbers>)', function () {
log1.level(0);
assert.strictEqual(log1.level(), 0);
log1.level(Number.MAX_VALUE);
assert.strictEqual(log1.level(), Number.MAX_VALUE);
log1.level(Infinity);
assert.strictEqual(log1.level(), Infinity);
});
t.test('log.level(<invalid values>)', function () {
assert.throws(function () {
bunyan.createLogger({name: 'invalid', level: 'booga'});
}, /unknown level name: "booga"/);
assert.throws(function () {
bunyan.createLogger({name: 'invalid', level: []});
}, /cannot resolve level: invalid arg \(object\): \[\]/);
assert.throws(function () {
bunyan.createLogger({name: 'invalid', level: true});
}, /cannot resolve level: invalid arg \(boolean\): true/);
assert.throws(function () {
bunyan.createLogger({name: 'invalid', level: -1});
}, /level is not a positive integer: -1/);
assert.throws(function () {
bunyan.createLogger({name: 'invalid', level: 3.14});
}, /level is not a positive integer: 3.14/);
assert.throws(function () {
bunyan.createLogger({name: 'invalid', level: -Infinity});
}, /level is not a positive integer: -Infinity/);
});

View file

@ -1,271 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test the `log.trace(...)`, `log.debug(...)`, ..., `log.fatal(...)` API.
*/
var util = require('util'),
format = util.format,
inspect = util.inspect;
var p = console.log;
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
// ---- test boolean `log.<level>()` calls
var log1 = bunyan.createLogger({
name: 'log1',
streams: [
{
path: __dirname + '/log.test.log1.log',
level: 'info'
}
]
});
var log2 = bunyan.createLogger({
name: 'log2',
streams: [
{
path: __dirname + '/log.test.log2a.log',
level: 'error'
},
{
path: __dirname + '/log.test.log2b.log',
level: 'debug'
}
]
})
test('log.LEVEL() -> boolean', function (t) {
t.equal(log1.trace(), false, 'log1.trace() is false')
t.equal(log1.debug(), false)
t.equal(log1.info(), true)
t.equal(log1.warn(), true)
t.equal(log1.error(), true)
t.equal(log1.fatal(), true)
// Level is the *lowest* level of all streams.
t.equal(log2.trace(), false)
t.equal(log2.debug(), true)
t.equal(log2.info(), true)
t.equal(log2.warn(), true)
t.equal(log2.error(), true)
t.equal(log2.fatal(), true)
t.end();
});
// ---- test `log.<level>(...)` calls which various input types
function Catcher() {
this.records = [];
}
Catcher.prototype.write = function (record) {
this.records.push(record);
}
var catcher = new Catcher();
var log3 = new bunyan.createLogger({
name: 'log3',
streams: [
{
type: 'raw',
stream: catcher,
level: 'trace'
}
]
});
var names = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
var fields = {one: 'un'};
test('log.info(undefined, <msg>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, undefined, 'some message');
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'undefined \'some message\'',
format('log.%s msg is "some message"', lvl));
});
t.end();
});
test('log.info(<fields>, undefined)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, undefined);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'undefined',
format('log.%s msg: expect "undefined", got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
test('log.info(null, <msg>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, null, 'some message');
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'some message',
format('log.%s msg is "some message"', lvl));
});
t.end();
});
test('log.info(<fields>, null)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, null);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'null',
format('log.%s msg: expect "null", got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
test('log.info(<str>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, 'some message');
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'some message',
format('log.%s msg is "some message"', lvl));
});
t.end();
});
test('log.info(<fields>, <str>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, 'some message');
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'some message',
format('log.%s msg: got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
test('log.info(<bool>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, true);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'true',
format('log.%s msg is "true"', lvl));
});
t.end();
});
test('log.info(<fields>, <bool>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, true);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'true',
format('log.%s msg: got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
test('log.info(<num>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, 3.14);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, '3.14',
format('log.%s msg: got %j', lvl, rec.msg));
});
t.end();
});
test('log.info(<fields>, <num>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, 3.14);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, '3.14',
format('log.%s msg: got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
test('log.info(<function>)', function (t) {
var func = function func1() {};
names.forEach(function (lvl) {
log3[lvl].call(log3, func);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, '[Function: func1]',
format('log.%s msg: got %j', lvl, rec.msg));
});
t.end();
});
test('log.info(<fields>, <function>)', function (t) {
var func = function func2() {};
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, func);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, '[Function: func2]',
format('log.%s msg: got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
test('log.info(<array>)', function (t) {
var arr = ['a', 1, {two: 'deux'}];
names.forEach(function (lvl) {
log3[lvl].call(log3, arr);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, format(arr),
format('log.%s msg: got %j', lvl, rec.msg));
});
t.end();
});
test('log.info(<fields>, <array>)', function (t) {
var arr = ['a', 1, {two: 'deux'}];
names.forEach(function (lvl) {
log3[lvl].call(log3, fields, arr);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, format(arr),
format('log.%s msg: got %j', lvl, rec.msg));
t.equal(rec.one, 'un');
});
t.end();
});
/*
* By accident (starting with trentm/node-bunyan#85 in bunyan@0.23.0),
* log.info(null, ...)
* was interpreted as `null` being the object of fields. It is gracefully
* handled, which is good. However, had I to do it again, I would have made
* that interpret `null` as the *message*, and no fields having been passed.
* I think it is baked now. It would take a major bunyan rev to change it,
* but I don't think it is worth it: passing `null` as the first arg isn't
* really an intended way to call these Bunyan methods for either case.
*/
test('log.info(null)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, null);
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, '', format('log.%s msg: got %j', lvl, rec.msg));
});
t.end();
});
test('log.info(null, <msg>)', function (t) {
names.forEach(function (lvl) {
log3[lvl].call(log3, null, 'my message');
var rec = catcher.records[catcher.records.length - 1];
t.equal(rec.msg, 'my message',
format('log.%s msg: got %j', lvl, rec.msg));
});
t.end();
});

227
test/log.test.mjs Normal file
View file

@ -0,0 +1,227 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test the `log.trace(...)`, `log.debug(...)`, ..., `log.fatal(...)` API.
*/
import { Eltro as t, assert} from 'eltro'
import { format } from 'util'
import bunyan from '../lib/bunyan.mjs'
// ---- test boolean `log.<level>()` calls
var log1 = bunyan.createLogger({
name: 'log1',
streams: [
{
stream: process.stdout,
level: 'info'
}
]
});
var log2 = bunyan.createLogger({
name: 'log2',
streams: [
{
stream: process.stdout,
level: 'error'
},
{
stream: process.stdout,
level: 'debug'
}
]
})
t.test('log.LEVEL() -> boolean', function () {
assert.strictEqual(log1.trace(), false, 'log1.trace() is false')
assert.strictEqual(log1.debug(), false)
assert.strictEqual(log1.info(), true)
assert.strictEqual(log1.warn(), true)
assert.strictEqual(log1.error(), true)
assert.strictEqual(log1.fatal(), true)
// Level is the *lowest* level of all streams.
assert.strictEqual(log2.trace(), false)
assert.strictEqual(log2.debug(), true)
assert.strictEqual(log2.info(), true)
assert.strictEqual(log2.warn(), true)
assert.strictEqual(log2.error(), true)
assert.strictEqual(log2.fatal(), true)
});
// ---- test `log.<level>(...)` calls which various input types
function Catcher() {
this.records = [];
}
Catcher.prototype.write = function (record) {
this.records.push(record);
}
var catcher = new Catcher();
var log3 = new bunyan.createLogger({
name: 'log3',
streams: [
{
type: 'raw',
stream: catcher,
level: 'trace'
}
]
});
var names = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
var fields = {one: 'un'};
t.test('log.info(undefined, <msg>)', function () {
names.forEach(function (lvl) {
log3[lvl](undefined, 'some message');
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'undefined some message');
});
});
t.test('log.info(<fields>, undefined)', function () {
names.forEach(function (lvl) {
log3[lvl](fields, undefined);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'undefined');
assert.strictEqual(rec.one, 'un');
});
});
t.test('log.info(null, <msg>)', function () {
names.forEach(function (lvl) {
log3[lvl](null, 'some message');
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'some message');
});
});
t.test('log.info(<fields>, null)', function () {
names.forEach(function (lvl) {
log3[lvl](fields, null);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'null');
assert.strictEqual(rec.one, 'un');
});
});
t.test('log.info(<str>)', function () {
names.forEach(function (lvl) {
log3[lvl]('some message');
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'some message');
});
});
t.test('log.info(<fields>, <str>)', function () {
names.forEach(function (lvl) {
log3[lvl](fields, 'some message');
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'some message');
assert.strictEqual(rec.one, 'un');
});
});
t.test('log.info(<bool>)', function () {
names.forEach(function (lvl) {
log3[lvl](true);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'true');
});
});
t.test('log.info(<fields>, <bool>)', function () {
names.forEach(function (lvl) {
log3[lvl](fields, true);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'true');
assert.strictEqual(rec.one, 'un');
});
});
t.test('log.info(<num>)', function () {
names.forEach(function (lvl) {
log3[lvl](3.14);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, '3.14');
});
});
t.test('log.info(<fields>, <num>)', function () {
names.forEach(function (lvl) {
log3[lvl](fields, 3.14);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, '3.14');
assert.strictEqual(rec.one, 'un');
});
});
t.test('log.info(<function>)', function () {
var func = function func1() {};
names.forEach(function (lvl) {
log3[lvl](func);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, '[Function: func1]');
});
});
t.test('log.info(<fields>, <function>)', function () {
var func = function func2() {};
names.forEach(function (lvl) {
log3[lvl](fields, func);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, '[Function: func2]');
assert.strictEqual(rec.one, 'un');
});
});
t.test('log.info(<array>)', function () {
var arr = ['a', 1, {two: 'deux'}];
names.forEach(function (lvl) {
log3[lvl](arr);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, format(arr));
});
});
t.test('log.info(<fields>, <array>)', function () {
var arr = ['a', 1, {two: 'deux'}];
names.forEach(function (lvl) {
log3[lvl](fields, arr);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, format(arr));
assert.strictEqual(rec.one, 'un');
});
});
/*
* By accident (starting with trentm/node-bunyan#85 in bunyan@0.23.0),
* log.info(null, ...)
* was interpreted as `null` being the object of fields. It is gracefully
* handled, which is good. However, had I to do it again, I would have made
* that interpret `null` as the *message*, and no fields having been passed.
* I think it is baked now. It would take a major bunyan rev to change it,
* but I don't think it is worth it: passing `null` as the first arg isn't
* really an intended way to call these Bunyan methods for either case.
*/
t.test('log.info(null)', function () {
names.forEach(function (lvl) {
log3[lvl](null);
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, '', format('log.%s msg: got %j', lvl, rec.msg));
});
});
t.test('log.info(null, <msg>)', function () {
names.forEach(function (lvl) {
log3[lvl](null, 'my message');
var rec = catcher.records[catcher.records.length - 1];
assert.strictEqual(rec.msg, 'my message');
});
});

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test other parts of the exported API.
*/
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
test('bunyan.<LEVEL>s', function (t) {
t.ok(bunyan.TRACE, 'TRACE');
t.ok(bunyan.DEBUG, 'DEBUG');
t.ok(bunyan.INFO, 'INFO');
t.ok(bunyan.WARN, 'WARN');
t.ok(bunyan.ERROR, 'ERROR');
t.ok(bunyan.FATAL, 'FATAL');
t.end();
});
test('bunyan.resolveLevel()', function (t) {
t.equal(bunyan.resolveLevel('trace'), bunyan.TRACE, 'TRACE');
t.equal(bunyan.resolveLevel('TRACE'), bunyan.TRACE, 'TRACE');
t.equal(bunyan.resolveLevel('debug'), bunyan.DEBUG, 'DEBUG');
t.equal(bunyan.resolveLevel('DEBUG'), bunyan.DEBUG, 'DEBUG');
t.equal(bunyan.resolveLevel('info'), bunyan.INFO, 'INFO');
t.equal(bunyan.resolveLevel('INFO'), bunyan.INFO, 'INFO');
t.equal(bunyan.resolveLevel('warn'), bunyan.WARN, 'WARN');
t.equal(bunyan.resolveLevel('WARN'), bunyan.WARN, 'WARN');
t.equal(bunyan.resolveLevel('error'), bunyan.ERROR, 'ERROR');
t.equal(bunyan.resolveLevel('ERROR'), bunyan.ERROR, 'ERROR');
t.equal(bunyan.resolveLevel('fatal'), bunyan.FATAL, 'FATAL');
t.equal(bunyan.resolveLevel('FATAL'), bunyan.FATAL, 'FATAL');
t.end();
});

33
test/other-api.test.mjs Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test other parts of the exported API.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
t.test('bunyan.<LEVEL>s', function () {
assert.ok(bunyan.TRACE, 'TRACE');
assert.ok(bunyan.DEBUG, 'DEBUG');
assert.ok(bunyan.INFO, 'INFO');
assert.ok(bunyan.WARN, 'WARN');
assert.ok(bunyan.ERROR, 'ERROR');
assert.ok(bunyan.FATAL, 'FATAL');
});
t.test('bunyan.resolveLevel()', function () {
assert.strictEqual(bunyan.resolveLevel('trace'), bunyan.TRACE, 'TRACE');
assert.strictEqual(bunyan.resolveLevel('TRACE'), bunyan.TRACE, 'TRACE');
assert.strictEqual(bunyan.resolveLevel('debug'), bunyan.DEBUG, 'DEBUG');
assert.strictEqual(bunyan.resolveLevel('DEBUG'), bunyan.DEBUG, 'DEBUG');
assert.strictEqual(bunyan.resolveLevel('info'), bunyan.INFO, 'INFO');
assert.strictEqual(bunyan.resolveLevel('INFO'), bunyan.INFO, 'INFO');
assert.strictEqual(bunyan.resolveLevel('warn'), bunyan.WARN, 'WARN');
assert.strictEqual(bunyan.resolveLevel('WARN'), bunyan.WARN, 'WARN');
assert.strictEqual(bunyan.resolveLevel('error'), bunyan.ERROR, 'ERROR');
assert.strictEqual(bunyan.resolveLevel('ERROR'), bunyan.ERROR, 'ERROR');
assert.strictEqual(bunyan.resolveLevel('fatal'), bunyan.FATAL, 'FATAL');
assert.strictEqual(bunyan.resolveLevel('FATAL'), bunyan.FATAL, 'FATAL');
});

View file

@ -1,11 +0,0 @@
var bunyan = require('../lib/bunyan');
var log = bunyan.createLogger({
name: 'default',
streams: [ {
type: 'rotating-file',
path: __dirname + '/log.test.rot.log',
period: '1d',
count: 7
} ]
});
console.log('done');

View file

@ -1,32 +0,0 @@
'use strict';
/*
* Test that bunyan process will terminate.
*
* Note: Currently (bunyan 0.23.1) this fails on node 0.8, because there is
* no `unref` in node 0.8 and bunyan doesn't yet have `Logger.prototype.close()`
* support.
*/
var exec = require('child_process').exec;
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var test = tap4nodeunit.test;
var nodeVer = process.versions.node.split('.').map(Number);
if (nodeVer[0] <= 0 && nodeVer[1] <= 8) {
console.warn('skip test (node <= 0.8)');
} else {
test('log with rotating file stream will terminate', function (t) {
exec('node ' +__dirname + '/process-exit.js', {timeout: 1000},
function (err, stdout, stderr) {
t.ifError(err);
t.equal(stdout, 'done\n');
t.equal(stderr, '');
t.end();
});
});
}

View file

@ -1,117 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test `type: 'raw'` Logger streams.
*/
var format = require('util').format;
var Logger = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
function CapturingStream(recs) {
this.recs = recs;
}
CapturingStream.prototype.write = function (rec) {
this.recs.push(rec);
}
test('raw stream', function (t) {
var recs = [];
var log = new Logger({
name: 'raw-stream-test',
streams: [
{
stream: new CapturingStream(recs),
type: 'raw'
}
]
});
log.info('first');
log.info({two: 'deux'}, 'second');
t.equal(recs.length, 2);
t.equal(typeof (recs[0]), 'object', 'first rec is an object');
t.equal(recs[1].two, 'deux', '"two" field made it through');
t.end();
});
test('raw streams and regular streams can mix', function (t) {
var rawRecs = [];
var nonRawRecs = [];
var log = new Logger({
name: 'raw-stream-test',
streams: [
{
stream: new CapturingStream(rawRecs),
type: 'raw'
},
{
stream: new CapturingStream(nonRawRecs)
}
]
});
log.info('first');
log.info({two: 'deux'}, 'second');
t.equal(rawRecs.length, 2);
t.equal(typeof (rawRecs[0]), 'object', 'first rawRec is an object');
t.equal(rawRecs[1].two, 'deux', '"two" field made it through');
t.equal(nonRawRecs.length, 2);
t.equal(typeof (nonRawRecs[0]), 'string', 'first nonRawRec is a string');
t.end();
});
test('child adding a non-raw stream works', function (t) {
var parentRawRecs = [];
var rawRecs = [];
var nonRawRecs = [];
var logParent = new Logger({
name: 'raw-stream-test',
streams: [
{
stream: new CapturingStream(parentRawRecs),
type: 'raw'
}
]
});
var logChild = logParent.child({
child: true,
streams: [
{
stream: new CapturingStream(rawRecs),
type: 'raw'
},
{
stream: new CapturingStream(nonRawRecs)
}
]
});
logParent.info('first');
logChild.info({two: 'deux'}, 'second');
t.equal(rawRecs.length, 1,
format('rawRecs length should be 1 (is %d)', rawRecs.length));
t.equal(typeof (rawRecs[0]), 'object', 'rawRec entry is an object');
t.equal(rawRecs[0].two, 'deux', '"two" field made it through');
t.equal(nonRawRecs.length, 1);
t.equal(typeof (nonRawRecs[0]), 'string', 'first nonRawRec is a string');
t.end();
});

107
test/raw-stream.test.mjs Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test `type: 'raw'` Logger streams.
*/
import { Eltro as t, assert} from 'eltro'
import { format } from 'util'
import bunyan from '../lib/bunyan.mjs'
function CapturingStream(recs) {
this.recs = recs;
}
CapturingStream.prototype.write = function (rec) {
this.recs.push(rec);
}
t.test('raw stream', function () {
var recs = [];
var log = new bunyan({
name: 'raw-stream-test',
streams: [
{
stream: new CapturingStream(recs),
type: 'raw'
}
]
});
log.info('first');
log.info({two: 'deux'}, 'second');
assert.strictEqual(recs.length, 2);
assert.strictEqual(typeof (recs[0]), 'object', 'first rec is an object');
assert.strictEqual(recs[1].two, 'deux', '"two" field made it through');
});
t.test('raw streams and regular streams can mix', function () {
var rawRecs = [];
var nonRawRecs = [];
var log = new bunyan({
name: 'raw-stream-test',
streams: [
{
stream: new CapturingStream(rawRecs),
type: 'raw'
},
{
stream: new CapturingStream(nonRawRecs)
}
]
});
log.info('first');
log.info({two: 'deux'}, 'second');
assert.strictEqual(rawRecs.length, 2);
assert.strictEqual(typeof (rawRecs[0]), 'object', 'first rawRec is an object');
assert.strictEqual(rawRecs[1].two, 'deux', '"two" field made it through');
assert.strictEqual(nonRawRecs.length, 2);
assert.strictEqual(typeof (nonRawRecs[0]), 'string', 'first nonRawRec is a string');
});
t.test('child adding a non-raw stream works', function () {
var parentRawRecs = [];
var rawRecs = [];
var nonRawRecs = [];
var logParent = new bunyan({
name: 'raw-stream-test',
streams: [
{
stream: new CapturingStream(parentRawRecs),
type: 'raw'
}
]
});
var logChild = logParent.child({
child: true,
streams: [
{
stream: new CapturingStream(rawRecs),
type: 'raw'
},
{
stream: new CapturingStream(nonRawRecs)
}
]
});
logParent.info('first');
logChild.info({two: 'deux'}, 'second');
assert.strictEqual(rawRecs.length, 1,
format('rawRecs length should be 1 (is %d)', rawRecs.length));
assert.strictEqual(typeof (rawRecs[0]), 'object', 'rawRec entry is an object');
assert.strictEqual(rawRecs[0].two, 'deux', '"two" field made it through');
assert.strictEqual(nonRawRecs.length, 1);
assert.strictEqual(typeof (nonRawRecs[0]), 'string', 'first nonRawRec is a string');
});

View file

@ -1,47 +0,0 @@
/*
* Test the RingBuffer output stream.
*/
var Logger = require('../lib/bunyan');
var ringbuffer = new Logger.RingBuffer({ 'limit': 5 });
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
var log1 = new Logger({
name: 'log1',
streams: [
{
stream: ringbuffer,
type: 'raw',
level: 'info'
}
]
});
test('ringbuffer', function (t) {
log1.info('hello');
log1.trace('there');
log1.error('android');
t.equal(ringbuffer.records.length, 2);
t.equal(ringbuffer.records[0]['msg'], 'hello');
t.equal(ringbuffer.records[1]['msg'], 'android');
log1.error('one');
log1.error('two');
log1.error('three');
t.equal(ringbuffer.records.length, 5);
log1.error('four');
t.equal(ringbuffer.records.length, 5);
t.equal(ringbuffer.records[0]['msg'], 'android');
t.equal(ringbuffer.records[1]['msg'], 'one');
t.equal(ringbuffer.records[2]['msg'], 'two');
t.equal(ringbuffer.records[3]['msg'], 'three');
t.equal(ringbuffer.records[4]['msg'], 'four');
t.end();
});

38
test/ringbuffer.test.mjs Normal file
View file

@ -0,0 +1,38 @@
/*
* Test the RingBuffer output stream.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
var ringbuffer = new bunyan.RingBuffer({ 'limit': 5 });
var log1 = new bunyan({
name: 'log1',
streams: [
{
stream: ringbuffer,
type: 'raw',
level: 'info'
}
]
});
t.test('ringbuffer', function () {
log1.info('hello');
log1.trace('there');
log1.error('android');
assert.strictEqual(ringbuffer.records.length, 2);
assert.strictEqual(ringbuffer.records[0]['msg'], 'hello');
assert.strictEqual(ringbuffer.records[1]['msg'], 'android');
log1.error('one');
log1.error('two');
log1.error('three');
assert.strictEqual(ringbuffer.records.length, 5);
log1.error('four');
assert.strictEqual(ringbuffer.records.length, 5);
assert.strictEqual(ringbuffer.records[0]['msg'], 'android');
assert.strictEqual(ringbuffer.records[1]['msg'], 'one');
assert.strictEqual(ringbuffer.records[2]['msg'], 'two');
assert.strictEqual(ringbuffer.records[3]['msg'], 'three');
assert.strictEqual(ringbuffer.records[4]['msg'], 'four');
});

View file

@ -1,4 +1,4 @@
var bunyan = require('../lib/bunyan'); import bunyan from '../lib/bunyan.mjs'
var log = bunyan.createLogger({ var log = bunyan.createLogger({
name: 'safe-json-stringify-1' name: 'safe-json-stringify-1'

View file

@ -1,5 +1,5 @@
import bunyan from '../lib/bunyan.mjs'
process.env.BUNYAN_TEST_NO_SAFE_JSON_STRINGIFY = '1'; process.env.BUNYAN_TEST_NO_SAFE_JSON_STRINGIFY = '1';
var bunyan = require('../lib/bunyan');
var log = bunyan.createLogger({ var log = bunyan.createLogger({
name: 'safe-json-stringify-2' name: 'safe-json-stringify-2'

View file

@ -1,4 +1,4 @@
var bunyan = require('../lib/bunyan'); import bunyan from '../lib/bunyan.mjs'
var log = bunyan.createLogger({ var log = bunyan.createLogger({
name: 'safe-json-stringify-3' name: 'safe-json-stringify-3'

View file

@ -1,5 +1,5 @@
import bunyan from '../lib/bunyan.mjs'
process.env.BUNYAN_TEST_NO_SAFE_JSON_STRINGIFY = '1'; process.env.BUNYAN_TEST_NO_SAFE_JSON_STRINGIFY = '1';
var bunyan = require('../lib/bunyan');
var log = bunyan.createLogger({ var log = bunyan.createLogger({
name: 'safe-json-stringify-4' name: 'safe-json-stringify-4'

View file

@ -1,69 +0,0 @@
/*
* Copyright (c) 2015 Trent Mick. All rights reserved.
*
* If available, use `safe-json-stringfy` as a fallback stringifier.
* This covers the case where an enumerable property throws an error
* in its getter.
*
* See <https://github.com/trentm/node-bunyan/pull/182>
*/
var p = console.warn;
var exec = require('child_process').exec;
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
test('__defineGetter__ boom', function (t) {
var cmd = process.execPath + ' ' + __dirname + '/safe-json-stringify-1.js';
exec(cmd, function (err, stdout, stderr) {
t.ifError(err, err);
var rec = JSON.parse(stdout.trim());
t.equal(rec.obj.boom, '[Throws: __defineGetter__ ouch!]');
t.end();
});
});
test('__defineGetter__ boom, without safe-json-stringify', function (t) {
var cmd = process.execPath + ' ' + __dirname + '/safe-json-stringify-2.js';
exec(cmd, function (err, stdout, stderr) {
t.ifError(err, err);
t.ok(stdout.indexOf('Exception in JSON.stringify') !== -1);
t.ok(stderr.indexOf(
'You can install the "safe-json-stringify" module') !== -1);
t.end();
});
});
test('defineProperty boom', function (t) {
var cmd = process.execPath + ' ' + __dirname + '/safe-json-stringify-3.js';
exec(cmd, function (err, stdout, stderr) {
t.ifError(err, err);
var recs = stdout.trim().split(/\n/g);
t.equal(recs.length, 2);
var rec = JSON.parse(recs[0]);
t.equal(rec.obj.boom, '[Throws: defineProperty ouch!]');
t.end();
});
});
test('defineProperty boom, without safe-json-stringify', function (t) {
var cmd = process.execPath + ' ' + __dirname + '/safe-json-stringify-4.js';
exec(cmd, function (err, stdout, stderr) {
t.ifError(err, err);
t.ok(stdout.indexOf('Exception in JSON.stringify') !== -1);
t.equal(stdout.match(/Exception in JSON.stringify/g).length, 2);
t.ok(stderr.indexOf(
'You can install the "safe-json-stringify" module') !== -1);
t.equal(stderr.match(
/* JSSTYLED */
/You can install the "safe-json-stringify" module/g).length, 1);
t.end();
});
});

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2015 Trent Mick. All rights reserved.
*
* If available, use `safe-json-stringfy` as a fallback stringifier.
* This covers the case where an enumerable property throws an error
* in its getter.
*
* See <https://github.com/trentm/node-bunyan/pull/182>
*/
import { Eltro as t, assert} from 'eltro'
import { exec, dirname } from './helper.mjs'
t.test('__defineGetter__ boom', async function () {
let res = await exec('', 'node', dirname('/safe-json-stringify-1.mjs'))
var rec = JSON.parse(res.stdout.trim());
assert.strictEqual(rec.obj.boom, '[Throws: __defineGetter__ ouch!]');
});
t.test('__defineGetter__ boom, without safe-json-stringify', async function () {
let res = await exec('', 'node', dirname('/safe-json-stringify-2.mjs'))
assert.ok(res.stdout.indexOf('Exception in JSON.stringify') !== -1);
assert.ok(res.stderr.indexOf(
'You can install the "safe-json-stringify" module') !== -1);
});
t.test('defineProperty boom', async function () {
let res = await exec('', 'node', dirname('/safe-json-stringify-3.mjs'))
var recs = res.stdout.trim().split(/\n/g);
assert.strictEqual(recs.length, 2);
var rec = JSON.parse(recs[0]);
assert.strictEqual(rec.obj.boom, '[Throws: defineProperty ouch!]');
});
t.test('defineProperty boom, without safe-json-stringify', async function () {
let res = await exec('', 'node', dirname('/safe-json-stringify-4.mjs'))
assert.ok(res.stdout.indexOf('Exception in JSON.stringify') !== -1);
assert.strictEqual(res.stdout.match(/Exception in JSON.stringify/g).length, 2);
assert.ok(res.stderr.indexOf(
'You can install the "safe-json-stringify" module') !== -1);
assert.strictEqual(res.stderr.match(
/You can install the "safe-json-stringify" module/g).length, 1);
});

175
test/safe-json.test.mjs Normal file
View file

@ -0,0 +1,175 @@
import { Eltro as t, assert} from 'eltro'
import safeJson from '../lib/safe-json.mjs'
t.test('basic stringify', function() {
assert.strictEqual('"foo"', safeJson('foo'));
assert.strictEqual('{"foo":"bar"}', safeJson({foo: 'bar'}));
});
t.test('object identity', function() {
var a = { foo: 'bar' };
var b = { one: a, two: a };
assert.strictEqual('{"one":{"foo":"bar"},"two":{"foo":"bar"}}',safeJson(b));
});
t.test('circular references', function() {
var a = {};
a.a = a;
a.b = 'c';
assert.doesNotThrow(
function() { safeJson(a); },
'should not exceed stack size'
);
assert.strictEqual(
'{"a":"[Circular]","b":"c"}',
safeJson(a)
);
});
t.test('null', function() {
assert.strictEqual(
'{"x":null}',
safeJson({x: null})
)
});
t.test('arrays', function() {
var arr = [ 2 ];
assert.strictEqual(
'[2]',
safeJson(arr)
);
arr.push(arr);
assert.strictEqual(
'[2,"[Circular]"]',
safeJson(arr)
);
assert.strictEqual(
'{"x":[2,"[Circular]"]}',
safeJson({x: arr})
);
});
t.test('throwing toJSON', function() {
var obj = {
toJSON: function() {
throw new Error('Failing');
}
};
assert.strictEqual(
'"[Throws: Failing]"',
safeJson(obj)
);
assert.strictEqual(
'{"x":"[Throws: Failing]"}',
safeJson({ x: obj })
);
});
t.test('properties on Object.create(null)', function() {
var obj = Object.create(null, {
foo: {
get: function() { return 'bar'; },
enumerable: true
}
});
assert.strictEqual(
'{"foo":"bar"}',
safeJson(obj)
);
var obj = Object.create(null, {
foo: {
get: function() { return 'bar'; },
enumerable: true
},
broken: {
get: function() { throw new Error('Broken'); },
enumerable: true
}
});
assert.strictEqual(
'{"foo":"bar","broken":"[Throws: Broken]"}',
safeJson(obj)
);
});
t.test('defined getter properties using __defineGetter__', function() {
// non throwing
var obj = {};
obj.__defineGetter__('foo', function() { return 'bar'; });
assert.strictEqual(
'{"foo":"bar"}',
safeJson(obj)
);
// throwing
obj = {};
obj.__defineGetter__('foo', function() { return undefined['oh my']; });
assert.doesNotThrow(
function(){ safeJson(obj)}
);
assert.strictEqual(
'{"foo":"[Throws: Cannot read property \'oh my\' of undefined]"}',
safeJson(obj)
);
});
t.test('enumerable defined getter properties using Object.defineProperty', function() {
// non throwing
var obj = {};
Object.defineProperty(obj, 'foo', {get: function() { return 'bar'; }, enumerable: true});
assert.strictEqual(
'{"foo":"bar"}',
safeJson(obj)
);
// throwing
obj = {};
Object.defineProperty(obj, 'foo', {get: function() { return undefined['oh my']; }, enumerable: true});
assert.doesNotThrow(
function(){ safeJson(obj)}
);
assert.strictEqual(
'{"foo":"[Throws: Cannot read property \'oh my\' of undefined]"}',
safeJson(obj)
);
});
t.test('formatting', function() {
var obj = {a:{b:1, c:[{d: 1}]}}; // some nested object
var formatters = [3, "\t", " "];
formatters.forEach((formatter) => {
assert.strictEqual(
JSON.stringify(obj, null, formatter),
safeJson(obj, null, formatter)
);
});
});
t.test('replacing', function() {
var obj = {a:{b:1, c:[{d: 1}]}}; // some nested object
var replacers = [
["a", "c"],
(k, v) => typeof v == 'number' ? "***" : v,
() => undefined,
[]
];
replacers.forEach((replacer) => {
assert.strictEqual(
JSON.stringify(obj, replacer),
safeJson(obj, replacer)
);
});
});

View file

@ -1,334 +0,0 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test the standard serializers in Bunyan.
*/
var http = require('http');
var bunyan = require('../lib/bunyan');
var verror = require('verror');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
function CapturingStream(recs) {
this.recs = recs;
}
CapturingStream.prototype.write = function (rec) {
this.recs.push(rec);
}
test('req serializer', function (t) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
req: bunyan.stdSerializers.req
}
});
// None of these should blow up.
var bogusReqs = [
undefined,
null,
{},
1,
'string',
[1, 2, 3],
{'foo':'bar'}
];
for (var i = 0; i < bogusReqs.length; i++) {
log.info({req: bogusReqs[i]}, 'hi');
t.equal(records[i].req, bogusReqs[i]);
}
// Get http request and response objects to play with and test.
var theReq, theRes;
var server = http.createServer(function (req, res) {
theReq = req;
theRes = res;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
})
server.listen(8765, function () {
http.get({host: '127.0.0.1', port: 8765, path: '/'}, function (res) {
res.resume();
log.info({req: theReq}, 'the request');
var lastRecord = records[records.length-1];
t.equal(lastRecord.req.method, 'GET');
t.equal(lastRecord.req.url, theReq.url);
t.equal(lastRecord.req.remoteAddress,
theReq.connection.remoteAddress);
t.equal(lastRecord.req.remotePort, theReq.connection.remotePort);
server.close();
t.end();
}).on('error', function (err) {
t.ok(false, 'error requesting to our test server: ' + err);
server.close();
t.end();
});
});
});
test('res serializer', function (t) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
res: bunyan.stdSerializers.res
}
});
// None of these should blow up.
var bogusRess = [
undefined,
null,
{},
1,
'string',
[1, 2, 3],
{'foo':'bar'}
];
for (var i = 0; i < bogusRess.length; i++) {
log.info({res: bogusRess[i]}, 'hi');
t.equal(records[i].res, bogusRess[i]);
}
// Get http request and response objects to play with and test.
var theReq, theRes;
var server = http.createServer(function (req, res) {
theReq = req;
theRes = res;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
})
server.listen(8765, function () {
http.get({host: '127.0.0.1', port: 8765, path: '/'}, function (res) {
res.resume();
log.info({res: theRes}, 'the response');
var lastRecord = records[records.length-1];
t.equal(lastRecord.res.statusCode, theRes.statusCode);
t.equal(lastRecord.res.header, theRes._header);
server.close();
t.end();
}).on('error', function (err) {
t.ok(false, 'error requesting to our test server: ' + err);
server.close();
t.end();
});
});
});
test('err serializer', function (t) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
err: bunyan.stdSerializers.err
}
});
// None of these should blow up.
var bogusErrs = [
undefined,
null,
{},
1,
'string',
[1, 2, 3],
{'foo':'bar'}
];
for (var i = 0; i < bogusErrs.length; i++) {
log.info({err: bogusErrs[i]}, 'hi');
t.equal(records[i].err, bogusErrs[i]);
}
var theErr = new TypeError('blah');
log.info(theErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, theErr.message);
t.equal(lastRecord.err.name, theErr.name);
t.equal(lastRecord.err.stack, theErr.stack);
t.end();
});
test('err serializer: custom serializer', function (t) {
var records = [];
function customSerializer(err) {
return {
message: err.message,
name: err.name,
stack: err.stack,
beep: err.beep
};
}
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
err: customSerializer
}
});
var e1 = new Error('message1');
e1.beep = 'bop';
var e2 = new Error('message2');
var errs = [e1, e2];
for (var i = 0; i < errs.length; i++) {
log.info(errs[i]);
t.equal(records[i].err.message, errs[i].message);
t.equal(records[i].err.beep, errs[i].beep);
}
t.end();
});
test('err serializer: long stack', function (t) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [ {
stream: new CapturingStream(records),
type: 'raw'
} ],
serializers: {
err: bunyan.stdSerializers.err
}
});
var topErr, midErr, bottomErr;
// Just a VError.
topErr = new verror.VError('top err');
log.info(topErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, topErr.message, 'Just a VError');
t.equal(lastRecord.err.name, topErr.name, 'Just a VError');
t.equal(lastRecord.err.stack, topErr.stack, 'Just a VError');
// Just a WError.
topErr = new verror.WError('top err');
log.info(topErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, topErr.message, 'Just a WError');
t.equal(lastRecord.err.name, topErr.name, 'Just a WError');
t.equal(lastRecord.err.stack, topErr.stack, 'Just a WError');
// WError <- TypeError
bottomErr = new TypeError('bottom err');
topErr = new verror.WError(bottomErr, 'top err');
log.info(topErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, topErr.message, 'WError <- TypeError');
t.equal(lastRecord.err.name, topErr.name, 'WError <- TypeError');
var expectedStack = topErr.stack + '\nCaused by: ' + bottomErr.stack;
t.equal(lastRecord.err.stack, expectedStack, 'WError <- TypeError');
// WError <- WError
bottomErr = new verror.WError('bottom err');
topErr = new verror.WError(bottomErr, 'top err');
log.info(topErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, topErr.message, 'WError <- WError');
t.equal(lastRecord.err.name, topErr.name, 'WError <- WError');
var expectedStack = topErr.stack + '\nCaused by: ' + bottomErr.stack;
t.equal(lastRecord.err.stack, expectedStack, 'WError <- WError');
// WError <- WError <- TypeError
bottomErr = new TypeError('bottom err');
midErr = new verror.WError(bottomErr, 'mid err');
topErr = new verror.WError(midErr, 'top err');
log.info(topErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, topErr.message,
'WError <- WError <- TypeError');
t.equal(lastRecord.err.name, topErr.name, 'WError <- WError <- TypeError');
var expectedStack = (topErr.stack
+ '\nCaused by: ' + midErr.stack
+ '\nCaused by: ' + bottomErr.stack);
t.equal(lastRecord.err.stack, expectedStack,
'WError <- WError <- TypeError');
// WError <- WError <- WError
bottomErr = new verror.WError('bottom err');
midErr = new verror.WError(bottomErr, 'mid err');
topErr = new verror.WError(midErr, 'top err');
log.info(topErr, 'the error');
var lastRecord = records[records.length-1];
t.equal(lastRecord.err.message, topErr.message,
'WError <- WError <- WError');
t.equal(lastRecord.err.name, topErr.name, 'WError <- WError <- WError');
var expectedStack = (topErr.stack
+ '\nCaused by: ' + midErr.stack
+ '\nCaused by: ' + bottomErr.stack);
t.equal(lastRecord.err.stack, expectedStack, 'WError <- WError <- WError');
t.end();
});
// Bunyan 0.18.3 introduced a bug where *all* serializers are applied
// even if the log record doesn't have the associated key. That means
// serializers that don't handle an `undefined` value will blow up.
test('do not apply serializers if no record key', function (t) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [ {
stream: new CapturingStream(records),
type: 'raw'
} ],
serializers: {
err: bunyan.stdSerializers.err,
boom: function (value) {
throw new Error('boom');
}
}
});
log.info({foo: 'bar'}, 'record one');
log.info({err: new Error('record two err')}, 'record two');
t.equal(records[0].boom, undefined);
t.equal(records[0].foo, 'bar');
t.equal(records[1].boom, undefined);
t.equal(records[1].err.message, 'record two err');
t.end();
});

242
test/serializers.test.mjs Normal file
View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2012 Trent Mick. All rights reserved.
*
* Test the standard serializers in Bunyan.
*/
import http from 'http'
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
function CapturingStream(recs) {
this.recs = recs;
}
CapturingStream.prototype.write = function (rec) {
this.recs.push(rec);
}
t.test('req serializer', function (cb) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
req: bunyan.stdSerializers.req
}
});
// None of these should blow up.
var bogusReqs = [
undefined,
null,
{},
1,
'string',
[1, 2, 3],
{'foo':'bar'}
];
for (var i = 0; i < bogusReqs.length; i++) {
log.info({req: bogusReqs[i]}, 'hi');
assert.strictEqual(records[i].req, bogusReqs[i]);
}
// Get http request and response objects to play with and test.
var theReq, theRes;
var server = http.createServer(function (req, res) {
theReq = req;
theRes = res;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
})
server.listen(8765, function () {
http.get({host: '127.0.0.1', port: 8765, path: '/'}, function (res) {
res.resume();
log.info({req: theReq}, 'the request');
var lastRecord = records[records.length-1];
try {
assert.strictEqual(lastRecord.req.method, 'GET');
assert.strictEqual(lastRecord.req.url, theReq.url);
assert.strictEqual(lastRecord.req.remoteAddress,
theReq.connection.remoteAddress);
assert.strictEqual(lastRecord.req.remotePort, theReq.connection.remotePort);
} catch (err) {
cb(err)
}
server.close();
cb()
}).on('error', function (err) {
server.close();
cb(err)
});
});
});
t.test('res serializer', function (cb) {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
res: bunyan.stdSerializers.res
}
});
// None of these should blow up.
var bogusRess = [
undefined,
null,
{},
1,
'string',
[1, 2, 3],
{'foo':'bar'}
];
for (var i = 0; i < bogusRess.length; i++) {
log.info({res: bogusRess[i]}, 'hi');
assert.strictEqual(records[i].res, bogusRess[i]);
}
// Get http request and response objects to play with and test.
var theReq, theRes;
var server = http.createServer(function (req, res) {
theReq = req;
theRes = res;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
})
server.listen(8765, function () {
http.get({host: '127.0.0.1', port: 8765, path: '/'}, function (res) {
res.resume();
log.info({res: theRes}, 'the response');
var lastRecord = records[records.length-1];
try {
assert.strictEqual(lastRecord.res.statusCode, theRes.statusCode);
assert.strictEqual(lastRecord.res.header, theRes._header);
} catch (err) {
cb(err)
}
server.close();
cb()
}).on('error', function (err) {
server.close();
cb(err)
});
});
});
t.test('err serializer', function () {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
err: bunyan.stdSerializers.err
}
});
// None of these should blow up.
var bogusErrs = [
undefined,
null,
{},
1,
'string',
[1, 2, 3],
{'foo':'bar'}
];
for (var i = 0; i < bogusErrs.length; i++) {
log.info({err: bogusErrs[i]}, 'hi');
assert.strictEqual(records[i].err, bogusErrs[i]);
}
var theErr = new TypeError('blah');
log.info(theErr, 'the error');
var lastRecord = records[records.length-1];
assert.strictEqual(lastRecord.err.message, theErr.message);
assert.strictEqual(lastRecord.err.name, theErr.name);
assert.strictEqual(lastRecord.err.stack, theErr.stack);
});
t.test('err serializer: custom serializer', function () {
var records = [];
function customSerializer(err) {
return {
message: err.message,
name: err.name,
stack: err.stack,
beep: err.beep
};
}
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [
{
stream: new CapturingStream(records),
type: 'raw'
}
],
serializers: {
err: customSerializer
}
});
var e1 = new Error('message1');
e1.beep = 'bop';
var e2 = new Error('message2');
var errs = [e1, e2];
for (var i = 0; i < errs.length; i++) {
log.info(errs[i]);
assert.strictEqual(records[i].err.message, errs[i].message);
assert.strictEqual(records[i].err.beep, errs[i].beep);
}
});
// Bunyan 0.18.3 introduced a bug where *all* serializers are applied
// even if the log record doesn't have the associated key. That means
// serializers that don't handle an `undefined` value will blow up.
t.test('do not apply serializers if no record key', function () {
var records = [];
var log = bunyan.createLogger({
name: 'serializer-test',
streams: [ {
stream: new CapturingStream(records),
type: 'raw'
} ],
serializers: {
err: bunyan.stdSerializers.err,
boom: function (value) {
throw new Error('boom');
}
}
});
log.info({foo: 'bar'}, 'record one');
log.info({err: new Error('record two err')}, 'record two');
assert.strictEqual(records[0].boom, undefined);
assert.strictEqual(records[0].foo, 'bar');
assert.strictEqual(records[1].boom, undefined);
assert.strictEqual(records[1].err.message, 'record two err');
});

View file

@ -1,62 +0,0 @@
/*
* Copyright (c) 2015 Trent Mick.
*
* Test `src: true` usage.
*/
// Intentionally on line 8 for tests below:
function logSomething(log) { log.info('something'); }
var format = require('util').format;
var Logger = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var after = tap4nodeunit.after;
var before = tap4nodeunit.before;
var test = tap4nodeunit.test;
function CapturingStream(recs) {
this.recs = recs;
}
CapturingStream.prototype.write = function (rec) {
this.recs.push(rec);
}
test('src', function (t) {
var recs = [];
var log = new Logger({
name: 'src-test',
src: true,
streams: [
{
stream: new CapturingStream(recs),
type: 'raw'
}
]
});
log.info('top-level');
logSomething(log);
t.equal(recs.length, 2);
recs.forEach(function (rec) {
t.ok(rec.src);
t.equal(typeof (rec.src), 'object');
t.equal(rec.src.file, __filename);
t.ok(rec.src.line);
t.equal(typeof (rec.src.line), 'number');
});
var rec = recs[1];
t.ok(rec.src.func);
t.equal(rec.src.func, 'logSomething');
t.equal(rec.src.line, 8);
t.end();
});

52
test/src.test.mjs Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2015 Trent Mick.
*
* Test `src: true` usage.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
// Intentionally on line 11 for tests below:
function logSomething(log) { log.info('something'); }
function CapturingStream(recs) {
this.recs = recs;
}
CapturingStream.prototype.write = function (rec) {
this.recs.push(rec);
}
// commented out due to broken implementation of
// getting caller line in strict mode (getCaller3Info())
/* t.only().test('src', function () {
var recs = [];
var log = new bunyan({
name: 'src-test',
src: true,
streams: [
{
stream: new CapturingStream(recs),
type: 'raw'
}
]
});
log.info('top-level');
logSomething(log);
assert.strictEqual(recs.length, 2);
recs.forEach(function (rec) {
assert.ok(rec.src);
assert.strictEqual(typeof (rec.src), 'object');
assert.strictEqual(rec.src.file, __filename);
assert.ok(rec.src.line);
assert.strictEqual(typeof (rec.src.line), 'number');
});
var rec = recs[1];
assert.ok(rec.src.func);
assert.strictEqual(rec.src.func, 'logSomething');
assert.strictEqual(rec.src.line, 11);
});*/

View file

@ -1,184 +0,0 @@
/*
* Copyright (c) 2015 Trent Mick. All rights reserved.
*
* Test that streams (the various way they can be added to
* a Logger instance) get the appropriate level.
*/
var util = require('util'),
format = util.format,
inspect = util.inspect;
var p = console.log;
var bunyan = require('../lib/bunyan');
// node-tap API
if (require.cache[__dirname + '/tap4nodeunit.js'])
delete require.cache[__dirname + '/tap4nodeunit.js'];
var tap4nodeunit = require('./tap4nodeunit.js');
var test = tap4nodeunit.test;
// ---- Tests
var log1 = bunyan.createLogger({
name: 'log1',
streams: [
{
path: __dirname + '/level.test.log1.log',
level: 'info'
}
]
});
test('default stream log level', function (t) {
var log = bunyan.createLogger({
name: 'foo'
});
t.equal(log.level(), bunyan.INFO);
t.equal(log.streams[0].level, bunyan.INFO);
t.end();
});
test('default stream, level=DEBUG specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
level: bunyan.DEBUG
});
t.equal(log.level(), bunyan.DEBUG);
t.equal(log.streams[0].level, bunyan.DEBUG);
t.end();
});
test('default stream, level="trace" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
level: 'trace'
});
t.equal(log.level(), bunyan.TRACE);
t.equal(log.streams[0].level, bunyan.TRACE);
t.end();
});
test('stream & level="trace" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
stream: process.stderr,
level: 'trace'
});
t.equal(log.level(), bunyan.TRACE);
t.equal(log.streams[0].level, bunyan.TRACE);
t.end();
});
test('one stream, default level', function (t) {
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
stream: process.stderr
}
]
});
t.equal(log.level(), bunyan.INFO);
t.equal(log.streams[0].level, bunyan.INFO);
t.end();
});
test('one stream, top-"level" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
level: 'error',
streams: [
{
stream: process.stderr
}
]
});
t.equal(log.level(), bunyan.ERROR);
t.equal(log.streams[0].level, bunyan.ERROR);
t.end();
});
test('one stream, stream-"level" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
stream: process.stderr,
level: 'error'
}
]
});
t.equal(log.level(), bunyan.ERROR);
t.equal(log.streams[0].level, bunyan.ERROR);
t.end();
});
test('one stream, both-"level" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
level: 'debug',
streams: [
{
stream: process.stderr,
level: 'error'
}
]
});
t.equal(log.level(), bunyan.ERROR);
t.equal(log.streams[0].level, bunyan.ERROR);
t.end();
});
test('two streams, both-"level" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
level: 'debug',
streams: [
{
stream: process.stdout,
level: 'trace'
},
{
stream: process.stderr,
level: 'fatal'
}
]
});
t.equal(log.level(), bunyan.TRACE, 'log.level()');
t.equal(log.streams[0].level, bunyan.TRACE);
t.equal(log.streams[1].level, bunyan.FATAL);
t.end();
});
test('two streams, one with "level" specified', function (t) {
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
stream: process.stdout,
},
{
stream: process.stderr,
level: 'fatal'
}
]
});
t.equal(log.level(), bunyan.INFO);
t.equal(log.streams[0].level, bunyan.INFO);
t.equal(log.streams[1].level, bunyan.FATAL);
t.end();
});
// Issue #335
test('log level 0 to turn on all logging', function (t) {
var log = bunyan.createLogger({
name: 'foo',
level: 0
});
t.equal(log.level(), 0);
t.equal(log.streams[0].level, 0);
t.end();
});

152
test/stream-levels.test.mjs Normal file
View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2015 Trent Mick. All rights reserved.
*
* Test that streams (the various way they can be added to
* a Logger instance) get the appropriate level.
*/
import { Eltro as t, assert} from 'eltro'
import bunyan from '../lib/bunyan.mjs'
// ---- Tests
t.test('default stream log level', function () {
var log = bunyan.createLogger({
name: 'foo'
});
assert.strictEqual(log.level(), bunyan.INFO);
assert.strictEqual(log.streams[0].level, bunyan.INFO);
});
t.test('default stream, level=DEBUG specified', function () {
var log = bunyan.createLogger({
name: 'foo',
level: bunyan.DEBUG
});
assert.strictEqual(log.level(), bunyan.DEBUG);
assert.strictEqual(log.streams[0].level, bunyan.DEBUG);
});
t.test('default stream, level="trace" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
level: 'trace'
});
assert.strictEqual(log.level(), bunyan.TRACE);
assert.strictEqual(log.streams[0].level, bunyan.TRACE);
});
t.test('stream & level="trace" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
stream: process.stderr,
level: 'trace'
});
assert.strictEqual(log.level(), bunyan.TRACE);
assert.strictEqual(log.streams[0].level, bunyan.TRACE);
});
t.test('one stream, default level', function () {
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
stream: process.stderr
}
]
});
assert.strictEqual(log.level(), bunyan.INFO);
assert.strictEqual(log.streams[0].level, bunyan.INFO);
});
t.test('one stream, top-"level" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
level: 'error',
streams: [
{
stream: process.stderr
}
]
});
assert.strictEqual(log.level(), bunyan.ERROR);
assert.strictEqual(log.streams[0].level, bunyan.ERROR);
});
t.test('one stream, stream-"level" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
stream: process.stderr,
level: 'error'
}
]
});
assert.strictEqual(log.level(), bunyan.ERROR);
assert.strictEqual(log.streams[0].level, bunyan.ERROR);
});
t.test('one stream, both-"level" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
level: 'debug',
streams: [
{
stream: process.stderr,
level: 'error'
}
]
});
assert.strictEqual(log.level(), bunyan.ERROR);
assert.strictEqual(log.streams[0].level, bunyan.ERROR);
});
t.test('two streams, both-"level" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
level: 'debug',
streams: [
{
stream: process.stdout,
level: 'trace'
},
{
stream: process.stderr,
level: 'fatal'
}
]
});
assert.strictEqual(log.level(), bunyan.TRACE, 'log.level()');
assert.strictEqual(log.streams[0].level, bunyan.TRACE);
assert.strictEqual(log.streams[1].level, bunyan.FATAL);
});
t.test('two streams, one with "level" specified', function () {
var log = bunyan.createLogger({
name: 'foo',
streams: [
{
stream: process.stdout,
},
{
stream: process.stderr,
level: 'fatal'
}
]
});
assert.strictEqual(log.level(), bunyan.INFO);
assert.strictEqual(log.streams[0].level, bunyan.INFO);
assert.strictEqual(log.streams[1].level, bunyan.FATAL);
});
// Issue #335
t.test('log level 0 to turn on all logging', function () {
var log = bunyan.createLogger({
name: 'foo',
level: 0
});
assert.strictEqual(log.level(), 0);
assert.strictEqual(log.streams[0].level, 0);
});

View file

@ -1,61 +0,0 @@
/*
* Copyright 2012 Mark Cavage. All rights reserved.
*
* Help nodeunit API feel like node-tap's.
*
* Usage:
* if (require.cache[__dirname + '/tap4nodeunit.js'])
* delete require.cache[__dirname + '/tap4nodeunit.js'];
* var tap4nodeunit = require('./tap4nodeunit.js');
* var after = tap4nodeunit.after;
* var before = tap4nodeunit.before;
* var test = tap4nodeunit.test;
*/
//---- Exports
module.exports = {
after: function after(teardown) {
module.parent.exports.tearDown = function _teardown(callback) {
try {
teardown.call(this, callback);
} catch (e) {
console.error('after:\n' + e.stack);
process.exit(1);
}
};
},
before: function before(setup) {
module.parent.exports.setUp = function _setup(callback) {
try {
setup.call(this, callback);
} catch (e) {
console.error('before:\n' + e.stack);
process.exit(1);
}
};
},
test: function test(name, tester) {
module.parent.exports[name] = function _(t) {
var _done = false;
t.end = function end() {
if (!_done) {
_done = true;
t.done();
}
};
t.notOk = function notOk(ok, message) {
return (t.ok(!ok, message));
};
t.error = t.ifError;
tester.call(this, t);
};
}
};

43
tools/ben.js Normal file
View file

@ -0,0 +1,43 @@
// Bring ben to local and remove one more dependancy.
// The package ben has either way not been updated in over 10 years.
// https://github.com/substack/node-ben
var ben = module.exports = function (times, cb) {
if (typeof times === 'function') {
cb = times;
times = 10000;
}
var t0 = Date.now();
for (var i = 0; i < times; i++) {
cb();
}
var elapsed = Date.now() - t0;
return elapsed / times;
};
ben.sync = ben;
ben.async = function (times, cb, resultCb) {
if (typeof times === 'function') {
resultCb = cb;
cb = times;
times = 100;
}
var pending = times;
var t = Date.now();
var elapsed = 0;
cb(function fn () {
elapsed += Date.now() - t;
if (--pending === 0) {
resultCb(elapsed / times);
}
else {
t = Date.now();
cb(fn);
}
});
};

View file

@ -13,7 +13,7 @@
* Result: Another order of magnitude. * Result: Another order of magnitude.
*/ */
var ben = require('ben'); // npm install ben var ben = require('./ben'); // npm install ben
var Logger = require('../lib/bunyan'); var Logger = require('../lib/bunyan');
var log = new Logger({ var log = new Logger({

View file

@ -6,7 +6,7 @@
console.log('Time JSON.stringify and alternatives in Logger._emit:'); console.log('Time JSON.stringify and alternatives in Logger._emit:');
var ben = require('ben'); // npm install ben var ben = require('./ben'); // npm install ben
var bunyan = require('../lib/bunyan'); var bunyan = require('../lib/bunyan');
function Collector() {} function Collector() {}

View file

@ -5,7 +5,7 @@
console.log('Time log.trace() when log level is "info":'); console.log('Time log.trace() when log level is "info":');
var ben = require('ben'); // npm install ben var ben = require('./ben'); // npm install ben
var bunyan = require('../lib/bunyan'); var bunyan = require('../lib/bunyan');
function Collector() {} function Collector() {}

View file

@ -5,7 +5,7 @@
console.log('Time adding "src" field with call source info:'); console.log('Time adding "src" field with call source info:');
var ben = require('ben'); // npm install ben var ben = require('./ben'); // npm install ben
var Logger = require('../lib/bunyan'); var Logger = require('../lib/bunyan');
var records = []; var records = [];