Add log.level(...)
and log.levels(...)
API for changing logger stream levels.
This commit is contained in:
parent
632c044ad3
commit
352c4177b7
5 changed files with 181 additions and 16 deletions
|
@ -2,6 +2,9 @@
|
|||
|
||||
## bunyan 0.5.0 (not yet released)
|
||||
|
||||
- Add `log.level(...)` and `log.levels(...)` API for changing logger stream
|
||||
levels.
|
||||
- Add `TRACE|DEBUG|INFO|WARN|ERROR|FATAL` level constants to exports.
|
||||
- Add `log.info(err)` special case for logging an `Error` instance. For
|
||||
example `log.info(new TypeError("boom")` will produce:
|
||||
|
||||
|
|
16
README.md
16
README.md
|
@ -220,6 +220,22 @@ Integers are used for the actual level values (1 for "trace", ..., 6 for
|
|||
"fatal") and constants are defined for the (Logger.TRACE ... Logger.DEBUG).
|
||||
The lowercase level names are aliases supported in the API.
|
||||
|
||||
Here is the API for changing levels in an existing logger:
|
||||
|
||||
log.level() -> INFO // gets current level (lowest level of all streams)
|
||||
|
||||
log.level(INFO) // set all streams to level INFO
|
||||
log.level("info") // set all streams to level INFO
|
||||
|
||||
log.levels() -> [DEBUG, INFO] // get array of levels of all streams
|
||||
log.levels(0) -> DEBUG // get level of stream at index 0
|
||||
log.levels("foo") // get level of stream with name "foo"
|
||||
|
||||
log.levels(0, INFO) // set level of stream 0 to INFO
|
||||
log.levels(0, "info") // can use "info" et al aliases
|
||||
log.levels("foo", WARN) // set stream named "foo" to WARN
|
||||
|
||||
|
||||
|
||||
# Log Record Fields
|
||||
|
||||
|
|
4
TODO.md
4
TODO.md
|
@ -1,8 +1,8 @@
|
|||
- line/file: possible to get quickly with v8? Yunong asked.
|
||||
file/line/func (?)
|
||||
- Logger.setLevel()? How to change level for a given stream. Default all,
|
||||
else, give an index... or type ... or support stream "names". Some positives
|
||||
to stream names.
|
||||
- service -> name
|
||||
- 10, 20,...
|
||||
- bunyan cli: more layouts (http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/EnhancedPatternLayout.html)
|
||||
Custom log formats (in config file? in '-f' arg) using printf or hogan.js
|
||||
or whatever. Dap wants field width control for lining up. Hogan.js is
|
||||
|
|
47
examples/level.js
Normal file
47
examples/level.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Play with setting levels.
|
||||
//
|
||||
// TODO: put this in a damn test suite
|
||||
|
||||
var Logger = require('../lib/bunyan'),
|
||||
DEBUG = Logger.DEBUG,
|
||||
INFO = Logger.INFO,
|
||||
WARN = Logger.WARN;
|
||||
var assert = require('assert');
|
||||
|
||||
// Basic usage.
|
||||
var log = new Logger({
|
||||
service: 'example-level',
|
||||
streams: [
|
||||
{
|
||||
name: 'stdout',
|
||||
stream: process.stdout,
|
||||
level: 'debug'
|
||||
},
|
||||
{
|
||||
name: 'stderr',
|
||||
stream: process.stderr
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
assert.equal(log.level(), DEBUG);
|
||||
assert.equal(log.levels()[0], DEBUG);
|
||||
assert.equal(log.levels()[1], INFO);
|
||||
assert.equal(log.levels(0), DEBUG);
|
||||
assert.equal(log.levels(1), INFO);
|
||||
|
||||
assert.equal(log.levels('stdout'), DEBUG)
|
||||
try {
|
||||
log.levels('foo')
|
||||
} catch (e) {
|
||||
assert.ok(e.message.indexOf('name') !== -1)
|
||||
}
|
||||
|
||||
log.trace("no one should see this")
|
||||
log.debug("should see this once (on stdout)")
|
||||
log.info("should see this twice")
|
||||
log.levels('stdout', INFO)
|
||||
log.debug("no one should see this either")
|
||||
log.level('trace')
|
||||
log.trace('should see this twice as 4th and 5th emitted log messages')
|
||||
|
127
lib/bunyan.js
127
lib/bunyan.js
|
@ -22,6 +22,7 @@ var xxx = function xxx() {}; // uncomment to turn of debug logging
|
|||
var os = require('os');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
|
||||
|
||||
|
||||
|
@ -55,7 +56,7 @@ if (!format) {
|
|||
}
|
||||
return objects.join(' ');
|
||||
}
|
||||
|
||||
|
||||
var i = 1;
|
||||
var args = arguments;
|
||||
var len = args.length;
|
||||
|
@ -178,7 +179,7 @@ function Logger(options, _childOptions, _childSimple) {
|
|||
if (! this instanceof Logger) {
|
||||
return new Logger(options, _childOptions);
|
||||
}
|
||||
|
||||
|
||||
// Input arg validation.
|
||||
var parent;
|
||||
if (_childOptions !== undefined) {
|
||||
|
@ -194,14 +195,14 @@ function Logger(options, _childOptions, _childSimple) {
|
|||
if ((options.stream || options.level) && options.streams) {
|
||||
throw new TypeError('cannot mix "streams" with "stream" or "level" options');
|
||||
}
|
||||
|
||||
|
||||
// Fast path for simple child creation.
|
||||
if (parent && _childSimple) {
|
||||
// Single to stream close handling that this child owns none of its
|
||||
// streams.
|
||||
this._isSimpleChild = true;
|
||||
|
||||
this.level = parent.level;
|
||||
this._level = parent._level;
|
||||
this.streams = parent.streams;
|
||||
this.serializers = parent.serializers;
|
||||
this.src = parent.src;
|
||||
|
@ -217,7 +218,7 @@ function Logger(options, _childOptions, _childSimple) {
|
|||
// Null values.
|
||||
var self = this;
|
||||
if (parent) {
|
||||
this.level = parent.level;
|
||||
this._level = parent._level;
|
||||
this.streams = [];
|
||||
for (var i = 0; i < parent.streams.length; i++) {
|
||||
var s = objCopy(parent.streams[i]);
|
||||
|
@ -228,13 +229,13 @@ function Logger(options, _childOptions, _childSimple) {
|
|||
this.src = parent.src;
|
||||
this.fields = objCopy(parent.fields);
|
||||
} else {
|
||||
this.level = Number.POSITIVE_INFINITY;
|
||||
this._level = Number.POSITIVE_INFINITY;
|
||||
this.streams = [];
|
||||
this.serializers = null;
|
||||
this.src = false;
|
||||
this.fields = {};
|
||||
}
|
||||
|
||||
|
||||
// Helpers
|
||||
function addStream(s) {
|
||||
s = objCopy(s);
|
||||
|
@ -254,8 +255,8 @@ function Logger(options, _childOptions, _childSimple) {
|
|||
} else {
|
||||
s.level = INFO;
|
||||
}
|
||||
if (s.level < self.level) {
|
||||
self.level = s.level;
|
||||
if (s.level < self._level) {
|
||||
self._level = s.level;
|
||||
}
|
||||
|
||||
switch (s.type) {
|
||||
|
@ -324,7 +325,7 @@ function Logger(options, _childOptions, _childSimple) {
|
|||
this.src = true;
|
||||
}
|
||||
xxx("Logger: ", self)
|
||||
|
||||
|
||||
// Fields.
|
||||
// These are the default fields for log records (minus the attributes
|
||||
// removed in this constructor). To allow storing raw log records
|
||||
|
@ -399,6 +400,98 @@ Logger.prototype.child = function (options, simple) {
|
|||
//}
|
||||
|
||||
|
||||
/**
|
||||
* Get/set the level of all streams on this logger.
|
||||
*
|
||||
* Get Usage:
|
||||
* // Returns the current log level (lowest level of all its streams).
|
||||
* log.level() -> INFO
|
||||
*
|
||||
* Set Usage:
|
||||
* log.level(INFO) // set all streams to level INFO
|
||||
* log.level("info") // can use "info" et al aliases
|
||||
*/
|
||||
Logger.prototype.level = function level(value) {
|
||||
if (value === undefined) {
|
||||
return this._level;
|
||||
}
|
||||
var newLevel = resolveLevel(value);
|
||||
var len = this.streams.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
this.streams[i].level = newLevel;
|
||||
}
|
||||
this._level = newLevel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get/set the level of a particular stream on this logger.
|
||||
*
|
||||
* Get Usage:
|
||||
* // Returns an array of the levels of each stream.
|
||||
* log.levels() -> [TRACE, INFO]
|
||||
*
|
||||
* // Returns a level of the identified stream.
|
||||
* log.levels(0) -> TRACE // level of stream at index 0
|
||||
* log.levels("foo") // level of stream with name "foo"
|
||||
*
|
||||
* Set Usage:
|
||||
* log.levels(0, INFO) // set level of stream 0 to INFO
|
||||
* log.levels(0, "info") // can use "info" et al aliases
|
||||
* log.levels("foo", WARN) // set stream named "foo" to WARN
|
||||
*
|
||||
* Stream names: When streams are defined, they can optionally be given
|
||||
* a name. For example,
|
||||
* log = new Logger({
|
||||
* streams: [
|
||||
* {
|
||||
* name: 'foo', // <--- proposed new option, yucky controlling uniqueness
|
||||
* path: '/var/log/my-service/foo.log'
|
||||
* level: 'trace'
|
||||
* },
|
||||
* ...
|
||||
*
|
||||
* @param name {String|Number} The stream index or name.
|
||||
* @param value {Number|String} The level value (INFO) or alias ("info").
|
||||
* If not given, this is a 'get' operation.
|
||||
* @throws {Error} If there is no stream with the given name.
|
||||
*/
|
||||
Logger.prototype.levels = function levels(name, value) {
|
||||
if (name === undefined) {
|
||||
assert.equal(value, undefined);
|
||||
return this.streams.map(function (s) { return s.level });
|
||||
}
|
||||
var stream;
|
||||
if (typeof name === 'number') {
|
||||
stream = this.streams[name];
|
||||
if (stream === undefined) {
|
||||
throw new Error('invalid stream index: ' + name);
|
||||
}
|
||||
} else {
|
||||
var len = this.streams.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var s = this.streams[i];
|
||||
if (s.name === name) {
|
||||
stream = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!stream) {
|
||||
throw new Error(format('no stream with name "%s"', name));
|
||||
}
|
||||
}
|
||||
if (value === undefined) {
|
||||
return stream.level;
|
||||
} else {
|
||||
var newLevel = resolveLevel(value);
|
||||
stream.level = newLevel;
|
||||
if (newLevel < this._level) {
|
||||
this._level = newLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply registered serializers to the appropriate keys in the given fields.
|
||||
*
|
||||
|
@ -418,9 +511,9 @@ Logger.prototype._applySerializers = function (fields, keys) {
|
|||
applyKeys[keys[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
xxx('_applySerializers: applyKeys', applyKeys);
|
||||
|
||||
|
||||
// Check each serializer against these (presuming number of serializers
|
||||
// is typically less than number of fields).
|
||||
Object.keys(this.serializers).forEach(function (name) {
|
||||
|
@ -760,7 +853,13 @@ var errSerializer = Logger.stdSerializers.err = function err(err) {
|
|||
//---- Exports
|
||||
|
||||
module.exports = Logger;
|
||||
|
||||
module.exports.TRACE = TRACE;
|
||||
module.exports.DEBUG = DEBUG;
|
||||
module.exports.INFO = INFO;
|
||||
module.exports.WARN = WARN;
|
||||
module.exports.ERROR = ERROR;
|
||||
module.exports.FATAL = FATAL;
|
||||
|
||||
module.exports.VERSION = VERSION;
|
||||
module.exports.LOG_VERSION = LOG_VERSION;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue