Ensure a top-level level given in bunyan.createLogger is *used* for given streams

Fixes #164
This commit is contained in:
Trent Mick 2015-01-17 20:39:06 -08:00
parent b975c3a9f8
commit 1ed684d110
4 changed files with 198 additions and 11 deletions

View file

@ -8,7 +8,23 @@ Known issues:
## bunyan 1.3.1 (not yet released) ## bunyan 1.3.1 (not yet released)
(nothing yet) - [issue #164] Ensure a top-level `level` given in `bunyan.createLogger`
is *used* for given `streams`. For example, ensure that the following
results in the stream having a DEBUG level:
var log = bunyan.createLogger({
name: 'foo',
level: 'debug',
streams: [
{
path: '/var/tmp/foo.log'
}
]
});
This was broken in the 1.0.1 release. Between that release and 1.3.0
the "/var/tmp/foo.log" stream would be at the INFO level (Bunyan's
default level).
## bunyan 1.3.0 ## bunyan 1.3.0

View file

@ -171,7 +171,7 @@ streams at different levels**.
}, },
{ {
level: 'error', level: 'error',
path: '/var/log/myapp-error.log' // log ERROR and above to a file path: '/var/tmp/myapp-error.log' // log ERROR and above to a file
} }
] ]
}); });

View file

@ -363,8 +363,6 @@ function Logger(options, _childOptions, _childSimple) {
dtp.enable(); dtp.enable();
} }
// Helpers
// Handle *config* options (i.e. options that are not just plain data // Handle *config* options (i.e. options that are not just plain data
// for log records). // for log records).
if (options.stream) { if (options.stream) {
@ -372,10 +370,12 @@ function Logger(options, _childOptions, _childSimple) {
type: 'stream', type: 'stream',
stream: options.stream, stream: options.stream,
closeOnExit: false, closeOnExit: false,
level: (options.level ? resolveLevel(options.level) : INFO) level: options.level
}); });
} else if (options.streams) { } else if (options.streams) {
options.streams.forEach(self.addStream, self); options.streams.forEach(function (s) {
self.addStream(s, options.level);
});
} else if (parent && options.level) { } else if (parent && options.level) {
this.level(options.level); this.level(options.level);
} else if (!parent) { } else if (!parent) {
@ -391,14 +391,14 @@ function Logger(options, _childOptions, _childSimple) {
type: 'raw', type: 'raw',
stream: new ConsoleRawStream(), stream: new ConsoleRawStream(),
closeOnExit: false, closeOnExit: false,
level: (options.level ? resolveLevel(options.level) : INFO) level: options.level
}); });
} else { } else {
self.addStream({ self.addStream({
type: 'stream', type: 'stream',
stream: process.stdout, stream: process.stdout,
closeOnExit: false, closeOnExit: false,
level: (options.level ? resolveLevel(options.level) : INFO) level: options.level
}); });
} }
} }
@ -445,16 +445,21 @@ util.inherits(Logger, EventEmitter);
* - `type`: The stream type. See README.md for full details. * - `type`: The stream type. See README.md for full details.
* Often this is implied by the other fields. Examples are * Often this is implied by the other fields. Examples are
* 'file', 'stream' and "raw". * 'file', 'stream' and "raw".
* - `level`: Defaults to 'info'.
* - `path` or `stream`: The specify the file path or writeable * - `path` or `stream`: The specify the file path or writeable
* stream to which log records are written. E.g. * stream to which log records are written. E.g.
* `stream: process.stdout`. * `stream: process.stdout`.
* - `level`: Optional. Falls back to `defaultLevel`.
* - `closeOnExit` (boolean): Optional. Default is true for a * - `closeOnExit` (boolean): Optional. Default is true for a
* 'file' stream when `path` is given, false otherwise. * 'file' stream when `path` is given, false otherwise.
* See README.md for full details. * See README.md for full details.
* @param defaultLevel {Number|String} Optional. A level to use if
* `stream.level` is not set. If neither is given, this defaults to INFO.
*/ */
Logger.prototype.addStream = function addStream(s) { Logger.prototype.addStream = function addStream(s, defaultLevel) {
var self = this; var self = this;
if (defaultLevel === null || defaultLevel === undefined) {
defaultLevel = INFO;
}
s = objCopy(s); s = objCopy(s);
@ -472,7 +477,7 @@ Logger.prototype.addStream = function addStream(s) {
if (s.level) { if (s.level) {
s.level = resolveLevel(s.level); s.level = resolveLevel(s.level);
} else { } else {
s.level = INFO; s.level = resolveLevel(defaultLevel);
} }
if (s.level < self._level) { if (s.level < self._level) {
self._level = s.level; self._level = s.level;

166
test/stream-levels.test.js Normal file
View file

@ -0,0 +1,166 @@
/*
* 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();
});