Skip to content
This repository was archived by the owner on Dec 11, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ log.levels('foo', log.WARN) // set level of stream named 'foo' to WARN
* `writers`: Map of log level string names to console functions, default is
`null`. Use this to customize the functions used when `console` is `true`,
see [writers](#writers).
* `pedantic`: A boolean or string which indicates messages should be reformatted to end with a period. If a string, the string is used instead of a period.
* `capitalize`: A boolean which indicates all messages should be reformatted to begin with an uppercase letter.
* `normalize`: A shortcut for `pedantic: true` and `capitalize: true`.
* `formatter`: A custom function which accepts a string and returns a string. Applied to all messages after parameter interpolation.

If you specify any unknown properties in the configuration then these are considered *persistent fields* and are added to every log record. This is a convenient way to add labels for sub-components to log records.

Expand Down
49 changes: 46 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ var os = require('os');
var path = require('path'), basename = path.basename;
var util = require('util');
var circular = require('circular');
var merge = require('cli-util').merge;
var utils = require('cli-util');
var merge = utils.merge;
var ucfirst = utils.ucfirst;
var pedantic = utils.pedantic;

var pkg = require(path.join(__dirname, 'package.json'));
var major = parseInt(pkg.version.split('.')[0]), z;
Expand Down Expand Up @@ -51,7 +54,11 @@ var defaults = {
writers: null,
level: null,
stream: null,
streams: null
streams: null,
normalize: false,
pedantic: false,
capitalize: false,
formatter: null
}

/**
Expand Down Expand Up @@ -409,11 +416,17 @@ Logger.prototype.serialize = function(k, v) {
*/
Logger.prototype.write = function(level, record, parameters, force) {
var i, target, listeners = this.listeners('write'), json, params, event;
var msg = '' + record.msg, prefix;
var msg = '' + record.msg, prefix, conf = this.conf;
var formatter = conf.formatter, pedantic = conf.pedantic, normalize = conf.normalize,
capitalize = conf.capitalize;
level = level || record.level;
params = parameters.slice(0);
params.unshift(record.msg);
record.msg = util.format.apply(util, params);
// if we have not just stringified an object or array, try to format the string.
if (!/^[{\[].*[}\]]$/.test(record.msg)) {
record.msg = this._formatMessage(record.msg);
}
//console.log('writing %j', record);
for(i = 0;i < this.streams.length;i++) {
target = this.streams[i];
Expand Down Expand Up @@ -463,6 +476,36 @@ Logger.prototype.write = function(level, record, parameters, force) {
return (listeners.length === 0 && event !== undefined);
}

/**
* Potentially runs one or more of `utils.pedantic()` or `utils.ucfirst()` upon a log message.
* @api private
* @param {string} message Log message to reformat
* @returns {string}
*/
Logger.prototype._formatMessage = function _formatMessage(message) {
var conf = this.conf,
formatter = conf.formatter;
// if option "normalize" is true, the string "like this" should look "Like this."
// if set, it will override options "pedantic" and "ucfirst".
if (conf.normalize) {
message = ucfirst(pedantic(message));
}
else {
// if option "pedantic" is truthy, end the message with a period, or a user-defined string.
if (conf.pedantic) {
message = pedantic(message, typeof conf.pedantic === 'string' && conf.pedantic);
}
// if option "capitalize" is truthy, capitalize the first letter of the message.
if (conf.capitalize) {
message = ucfirst(message);
}
}
if (formatter && typeof formatter === 'function') {
message = formatter(message);
}
return message;
};

/**
* Log a message.
*
Expand Down
136 changes: 136 additions & 0 deletions test/unit/formatters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
var expect = require('chai').expect;
var logger = require('../..');

describe('cli-logger:', function () {
it('should write using normalize flag if present', function (done) {
var msg = 'mock write %s';
var parameters = ['info'];
var expected = 'Mock write info.';
var name = 'mock-write-logger';
var conf = {name: name, json: true, streams: [
{path: 'log/mock-write.log'}
], normalize: true};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
expect(record.err.message).to.eql('boom');
done();
});
log.info(new Error('boom'), msg, parameters[0]);
});
it('should prefer normalize flag over custom pedantic string', function (done) {
var msg = 'mock write %s';
var parameters = ['info'];
var expected = 'Mock write info.';
var name = 'mock-write-logger';
var conf = {name: name, json: true, streams: [
{path: 'log/mock-write.log'}
], normalize: true, pedantic: '?'};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
expect(record.err.message).to.eql('boom');
done();
});
log.info(new Error('boom'), msg, parameters[0]);
});
it('should not attempt format a stringified object', function (done) {
var msg = {foo: 'bar'};
var expected = JSON.stringify(msg);
var name = 'mock-write-logger';
var conf = {name: name, json: false, streams: [
{path: 'log/mock-write.log'}
], normalize: true, pedantic: true, capitalize: true, formatter: function formatter(msg) {
return msg.replace(/"/g, "'");
}};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
done();
});
log.info(msg);
});
it('should not attempt format a stringified array', function (done) {
var msg = ['bar'];
var expected = JSON.stringify(msg);
var name = 'mock-write-logger';
var conf = {name: name, json: false, streams: [
{path: 'log/mock-write.log'}
], normalize: true, pedantic: true, capitalize: true, formatter: function formatter(msg) {
return msg.replace(/"/g, "'");
}};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
done();
});
log.info(msg);
});
it('should capitalize the first letter of the message', function (done) {
var msg = 'mock write %s';
var parameters = ['info'];
var expected = 'Mock write info';
var name = 'mock-write-logger';
var conf = {name: name, json: true, streams: [
{path: 'log/mock-write.log'}
], capitalize: true};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
expect(record.err.message).to.eql('boom');
done();
});
log.info(new Error('boom'), msg, parameters[0]);
});
it('should end the string with a period', function (done) {
var msg = 'mock write %s';
var parameters = ['info'];
var expected = 'mock write info.';
var name = 'mock-write-logger';
var conf = {name: name, json: true, streams: [
{path: 'log/mock-write.log'}
], pedantic: true};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
expect(record.err.message).to.eql('boom');
done();
});
log.info(new Error('boom'), msg, parameters[0]);

});
it('should leverage custom pedantic "period" if present', function (done) {
var msg = 'mock write info';
var expected = 'mock write info!@!~!~!~!11!1!';
var name = 'mock-write-logger';
var conf = {name: name, json: true, streams: [
{path: 'log/mock-write.log'}
], pedantic: '!@!~!~!~!11!1!'};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
expect(record.err.message).to.eql('boom');
done();
});
log.info(new Error('boom'), msg);
});
it('should allow a user-defined formatter', function (done) {
var msg = 'mock write %s';
var formatter = function formatter(msg) {
return msg.replace('write', 'WRITE');
};
var parameters = ['info'];
var expected = 'mock WRITE info';
var name = 'mock-write-logger';
var conf = {name: name, json: true, streams: [
{path: 'log/mock-write.log'}
], formatter: formatter};
var log = logger(conf);
log.on('write', function (record) {
expect(record.msg).to.eql(expected);
expect(record.err.message).to.eql('boom');
done();
});
log.info(new Error('boom'), msg, parameters[0]);
});
});