From 2b96eee830a55fbc76119aaf646c47f20e82b408 Mon Sep 17 00:00:00 2001 From: Chris Oloff Date: Sun, 18 Jan 2015 08:09:03 +0200 Subject: [PATCH] implemented filters --- README.md | 21 +++++++++++++++++ lib/winston.js | 3 ++- lib/winston/logger.js | 14 +++++++++++ test/log-filter-test.js | 51 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 test/log-filter-test.js diff --git a/README.md b/README.md index 62430b445..c98066170 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ There are two different ways to use winston: directly via the default logger, or * [Working with multiple Loggers in winston](#working-with-multiple-loggers-in-winston) * [Using winston in a CLI tool](#using-winston-in-a-cli-tool) * [Extending another object with Logging](#extending-another-object-with-logging) + * [Filters](#filters) * [Working with transports](#working-with-transports) * [Adding Custom Transports](#adding-custom-transports) * [Installation](#installation) @@ -627,6 +628,26 @@ Often in a given code base with lots of Loggers it is useful to add logging meth myObject.info("127.0.0.1 - there's no place like home"); ``` +### Filters +Filters allow modifying the contents of log messages, e.g. to mask data that +should not appear in logs. + +``` js +logger.addFilter(function(msg) { + return maskCardNumbers(msg); +}); +logger.info('transaction with card number 123456789012345 successful.'); +``` + +This may result in this output: + +``` +info: transaction with card number 123456****2345 successful. +``` + +See [log-filter-test.js](./test/log-filter-test.js), where card number masking +is implemented as an example. + ## Working with Transports There are many transports supported by winston core. If you have a transport you would like to add either open an issue or fork and submit a pull request. Commits are welcome, but I'll give you extra street cred if you __add tests too :D__ diff --git a/lib/winston.js b/lib/winston.js index 040078f53..43aa6d119 100644 --- a/lib/winston.js +++ b/lib/winston.js @@ -78,7 +78,8 @@ var methods = [ 'cli', 'handleExceptions', 'unhandleExceptions', - 'addRewriter' + 'addRewriter', + 'addFilter' ]; common.setLevels(winston, null, defaultLogger.levels); methods.forEach(function (method) { diff --git a/lib/winston/logger.js b/lib/winston/logger.js index bcf3b8347..8d6b9ec41 100755 --- a/lib/winston/logger.js +++ b/lib/winston/logger.js @@ -51,6 +51,7 @@ var Logger = exports.Logger = function (options) { // this.transports = {}; this.rewriters = []; + this.filters = []; this.exceptionHandlers = {}; this.profilers = {}; this._names = []; @@ -153,6 +154,10 @@ Logger.prototype.log = function (level) { meta = rewriter(level, msg, meta); }); + this.filters.forEach(function(filter) { + msg = filter(msg); + }); + // // For consideration of terminal 'color" programs like colors.js, // which can add ANSI escape color codes to strings, we destyle the @@ -472,6 +477,15 @@ Logger.prototype.addRewriter = function (rewriter) { this.rewriters.push(rewriter); } +// +// ### function addFilter (filter) +// #### @filter {function} Filter function, called with the message as single +// argument, expected to return the filtered message. +// +Logger.prototype.addFilter = function (filter) { + this.filters.push(filter); +} + // // ### function clear () // Remove all transports from this instance diff --git a/test/log-filter-test.js b/test/log-filter-test.js new file mode 100644 index 000000000..8af69c6b0 --- /dev/null +++ b/test/log-filter-test.js @@ -0,0 +1,51 @@ +/* log-filter-test.js: Test filtering of message content in winston. + * (c) 2015 Chris Oloff + * MIT LICENSE + */ + +var assert = require('assert'), + vows = require('vows'), + winston = require('../lib/winston'), + helpers = require('./helpers'); + +/* To demo a filter, we filter out credit card numbers, assuming that a credit + * card number consists of 13 or more digits (without spaces). This function + * does the actual masking. + */ +function maskCardNumbers(s) { + var match; + while (match = s.match(/(\d{13}\d*)/)) { + var toBeMasked = match[1]; + s = s.replace(toBeMasked, toBeMasked.substring(0,6) + '****' + toBeMasked.substring(toBeMasked.length - 4)); + } + return s; +} + +vows.describe('winston/logger/filter').addBatch({ + "An instance of winston.Logger": { + topic: new (winston.Logger)({transports: [ + new (winston.transports.Console)({ level: 'info' }) + ]}), + "the addFilter() method": { + topic: function (logger) { + logger.addFilter(function (msg) { + return maskCardNumbers(msg); + }); + return logger; + }, + "should add the filter": function(logger) { + assert.equal(helpers.size(logger.filters), 1); + }, + "the log() method": { + topic: function (logger) { + logger.once('logging', this.callback); + logger.log('info', 'card number 123456789012345 for testing'); + }, + "should filter the card number": function (transport, level, msg, meta) { + assert.equal(msg, 'card number 123456****2345 for testing'); + } + } + } + } +}).export(module); +