diff --git a/CHANGES.md b/CHANGES.md index ad6e2b8..374c42a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,23 @@ Known issues: ## 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 diff --git a/README.md b/README.md index 726c8cf..8325d06 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ streams at different levels**. }, { 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 } ] }); diff --git a/lib/bunyan.js b/lib/bunyan.js index 3c09ce4..43533f0 100644 --- a/lib/bunyan.js +++ b/lib/bunyan.js @@ -363,8 +363,6 @@ function Logger(options, _childOptions, _childSimple) { dtp.enable(); } - // Helpers - // Handle *config* options (i.e. options that are not just plain data // for log records). if (options.stream) { @@ -372,10 +370,12 @@ function Logger(options, _childOptions, _childSimple) { type: 'stream', stream: options.stream, closeOnExit: false, - level: (options.level ? resolveLevel(options.level) : INFO) + level: options.level }); } 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) { this.level(options.level); } else if (!parent) { @@ -391,14 +391,14 @@ function Logger(options, _childOptions, _childSimple) { type: 'raw', stream: new ConsoleRawStream(), closeOnExit: false, - level: (options.level ? resolveLevel(options.level) : INFO) + level: options.level }); } else { self.addStream({ type: 'stream', stream: process.stdout, 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. * Often this is implied by the other fields. Examples are * 'file', 'stream' and "raw". - * - `level`: Defaults to 'info'. * - `path` or `stream`: The specify the file path or writeable * stream to which log records are written. E.g. * `stream: process.stdout`. + * - `level`: Optional. Falls back to `defaultLevel`. * - `closeOnExit` (boolean): Optional. Default is true for a * 'file' stream when `path` is given, false otherwise. * 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; + if (defaultLevel === null || defaultLevel === undefined) { + defaultLevel = INFO; + } s = objCopy(s); @@ -472,7 +477,7 @@ Logger.prototype.addStream = function addStream(s) { if (s.level) { s.level = resolveLevel(s.level); } else { - s.level = INFO; + s.level = resolveLevel(defaultLevel); } if (s.level < self._level) { self._level = s.level; diff --git a/test/stream-levels.test.js b/test/stream-levels.test.js new file mode 100644 index 0000000..b373fdd --- /dev/null +++ b/test/stream-levels.test.js @@ -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(); +}); +