diff --git a/browser.js b/browser.js index 2581a0371..97dcb49d9 100644 --- a/browser.js +++ b/browser.js @@ -41,25 +41,25 @@ function pino (opts) { } if (opts.enabled === false) opts.level = 'silent' var level = opts.level || 'info' - var val = pino.levels.values[level] - if (level === 'silent') val = Infinity var logger = Object.create(proto) if (!logger.log) logger.log = noop + Object.defineProperty(logger, 'levelVal', { + get: getLevelVal + }) + Object.defineProperty(logger, 'level', { + get: getLevel, + set: setLevel + }) + var setOpts = { transmit: transmit, serialize: serialize, asObject: opts.browser.asObject, - levels: levels, - level: level + levels: levels } - - set(setOpts, logger, val, 'error', 'log') // <-- must stay first - set(setOpts, logger, val, 'fatal', 'error') - set(setOpts, logger, val, 'warn', 'error') - set(setOpts, logger, val, 'info', 'log') - set(setOpts, logger, val, 'debug', 'log') - set(setOpts, logger, val, 'trace', 'log') + logger.levels = pino.levels + logger.level = level logger.setMaxListeners = logger.getMaxListeners = logger.emit = logger.addListener = logger.on = @@ -75,6 +75,29 @@ function pino (opts) { if (transmit) logger._logEvent = createLogEventShape() + function getLevelVal () { + return this.level === 'silent' + ? Infinity + : this.levels.values[this.level] + } + + function getLevel () { + return this._level + } + function setLevel (level) { + if (level !== 'silent' && !this.levels.values[level]) { + throw Error('unknown level ' + level) + } + this._level = level + + set(setOpts, logger, 'error', 'log') // <-- must stay first + set(setOpts, logger, 'fatal', 'error') + set(setOpts, logger, 'warn', 'error') + set(setOpts, logger, 'info', 'log') + set(setOpts, logger, 'debug', 'log') + set(setOpts, logger, 'trace', 'log') + } + function child (bindings) { if (!bindings) { throw new Error('missing bindings for child Pino') @@ -105,7 +128,6 @@ function pino (opts) { Child.prototype = this return new Child(this) } - logger.levels = pino.levels return logger } @@ -132,11 +154,12 @@ pino.levels = { pino.stdSerializers = stdSerializers -function set (opts, logger, val, level, fallback) { +function set (opts, logger, level, fallback) { + var val = logger.levelVal logger[level] = val > pino.levels.values[level] ? noop : (logger[level] ? logger[level] : (_console[level] || _console[fallback] || noop)) - wrap(opts, logger, val, level) + wrap(opts, logger, logger.val, level) } function wrap (opts, logger, val, level) { @@ -156,7 +179,7 @@ function wrap (opts, logger, val, level) { else write.apply(proto, args) if (opts.transmit) { - var transmitLevel = opts.transmit.level || opts.level + var transmitLevel = opts.transmit.level || logger.level var transmitValue = pino.levels.values[transmitLevel] var methodValue = pino.levels.values[level] if (methodValue < transmitValue) return @@ -165,7 +188,7 @@ function wrap (opts, logger, val, level) { methodLevel: level, methodValue: methodValue, transmitLevel: transmitLevel, - transmitValue: pino.levels.values[opts.transmit.level || opts.level], + transmitValue: pino.levels.values[opts.transmit.level || logger.level], send: opts.transmit.send, val: val }, args) diff --git a/test/browser.levels.test.js b/test/browser.levels.test.js new file mode 100644 index 000000000..27f5efc6a --- /dev/null +++ b/test/browser.levels.test.js @@ -0,0 +1,157 @@ +'use strict' +var test = require('tape') +var pino = require('../browser') + +test('set the level by string', function (t) { + t.plan(4) + var expected = [ + { + level: 50, + msg: 'this is an error' + }, + { + level: 60, + msg: 'this is fatal' + } + ] + var instance = pino({ + browser: { + write: function (actual) { + checkLogObjects(t, actual, expected.shift()) + } + } + }) + + instance.level = 'error' + instance.info('hello world') + instance.error('this is an error') + instance.fatal('this is fatal') + t.end() +}) + +test('set the level via constructor', function (t) { + t.plan(4) + var expected = [ + { + level: 50, + msg: 'this is an error' + }, + { + level: 60, + msg: 'this is fatal' + } + ] + var instance = pino({ + level: 'error', + browser: { + write: function (actual) { + checkLogObjects(t, actual, expected.shift()) + } + } + }) + + instance.info('hello world') + instance.error('this is an error') + instance.fatal('this is fatal') + t.end() +}) + +test('the wrong level throws', function (t) { + t.plan(1) + var instance = pino() + t.throws(function () { + instance.level = 'kaboom' + }) +}) + +test('the wrong level by number throws', function (t) { + t.plan(1) + var instance = pino() + t.throws(function () { + instance.levelVal = 55 + }) +}) + +test('exposes level string mappings', function (t) { + t.plan(1) + t.equal(pino.levels.values.error, 50) +}) + +test('exposes level number mappings', function (t) { + t.plan(1) + t.equal(pino.levels.labels[50], 'error') +}) + +test('returns level integer', function (t) { + t.plan(1) + var instance = pino({level: 'error'}) + t.equal(instance.levelVal, 50) +}) + +test('silent level via constructor', function (t) { + var instance = pino({ + level: 'silent', + browser: { + write: function (actual) { + t.fail('no data should be logged') + } + } + }) + + Object.keys(pino.levels.values).forEach(function (level) { + instance[level]('hello world') + }) + t.end() +}) + +test('silent level by string', function (t) { + var instance = pino({ + browser: { + write: function (actual) { + t.fail('no data should be logged') + } + } + }) + + instance.level = 'silent' + + Object.keys(pino.levels.values).forEach(function (level) { + instance[level]('hello world') + }) + t.end() +}) + +test('exposed levels', function (t) { + t.plan(1) + t.deepEqual(Object.keys(pino.levels.values), [ + 'fatal', + 'error', + 'warn', + 'info', + 'debug', + 'trace' + ]) +}) + +test('exposed labels', function (t) { + t.plan(1) + t.deepEqual(Object.keys(pino.levels.labels), [ + '10', + '20', + '30', + '40', + '50', + '60' + ]) +}) + +function checkLogObjects (t, actual, expected) { + t.ok(actual.time <= Date.now(), 'time is greater than Date.now()') + + var actualCopy = Object.assign({}, actual) + var expectedCopy = Object.assign({}, expected) + delete actualCopy.time + delete expectedCopy.time + + t.deepEqual(actualCopy, expectedCopy) +}