diff --git a/Readme.md b/Readme.md index 4e3cc8e..6fa912e 100644 --- a/Readme.md +++ b/Readme.md @@ -80,6 +80,12 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req skip: function(req, res) { return false; } // function to determine if logging is skipped, defaults to false. requestFilter: function (req, propName) { return req[propName]; } // A function to filter/return request values, defaults to returning all values allowed by whitelist. If the function returns undefined, the key/value will not be included in the meta. responseFilter: function (res, propName) { return res[propName]; } // A function to filter/return response values, defaults to returning all values allowed by whitelist. If the function returns undefined, the key/value will not be included in the meta. + requestWhitelist: [String] // Array of request properties to log. Overrides global requestWhitelist for this instance + responseWhitelist: [String] // Array of response properties to log. Overrides global responseWhitelist for this instance + bodyWhitelist: [String] // Array of body properties to log. Overrides global bodyWhitelist for this instance + bodyBlacklist: [String] // Array of body properties to omit from logs. Overrides global bodyBlacklist for this instance + ignoredRoutes: [String] // Array of paths to ignore/skip logging. Overrides global ignoredRoutes for this instance + ``` ### Error Logging @@ -111,6 +117,7 @@ The logger needs to be added AFTER the express router(`app.router)`) and BEFORE baseMeta: Object, // default meta data to be added to log, this will be merged with the error data. metaField: String, // if defined, the meta data will be added in this field instead of the meta root object. requestFilter: function (req, propName) { return req[propName]; } // A function to filter/return request values, defaults to returning all values allowed by whitelist. If the function returns undefined, the key/value will not be included in the meta. + requestWhitelist: [String] // Array of request properties to log. Overrides global requestWhitelist for this instance ``` To use winston's existing transports, set `transports` to the values (as in key-value) of the `winston.default.transports` object. This may be done, for example, by using underscorejs: `transports: _.values(winston.default.transports)`. diff --git a/index.js b/index.js index cf621a0..10a73bd 100644 --- a/index.js +++ b/index.js @@ -34,34 +34,34 @@ delete require.cache[require.resolve('underscore')]; * TODO: Include 'body' and get the defaultRequestFilter to filter the inner properties like 'password' or 'password_confirmation', etc. Pull requests anyone? * @type {Array} */ -var requestWhitelist = ['url', 'headers', 'method', 'httpVersion', 'originalUrl', 'query']; +var globalRequestWhitelist = ['url', 'headers', 'method', 'httpVersion', 'originalUrl', 'query']; /** * A default list of properties in the request body that are allowed to be logged. * This will normally be empty here, since it should be done at the route level. * @type {Array} */ -var bodyWhitelist = []; +var globalBodyWhitelist = []; /** * A default list of properties in the request body that are not allowed to be logged. * @type {Array} */ -var bodyBlacklist = []; +var globalBodyBlacklist = []; /** * A default list of properties in the response object that are allowed to be logged. * These properties will be safely included in the meta of the log. * @type {Array} */ -var responseWhitelist = ['statusCode']; +var globalResponseWhitelist = ['statusCode']; /** * A list of request routes that will be skipped instead of being logged. This would be useful if routes for health checks or pings would otherwise pollute * your log files. * @type {Array} */ -var ignoredRoutes = []; +var globalIgnoredRoutes = []; /** * A default function to filter the properties of the req object. @@ -118,6 +118,7 @@ function errorLogger(options) { ensureValidOptions(options); + options.requestWhitelist = options.requestWhitelist || globalRequestWhitelist; options.requestFilter = options.requestFilter || defaultRequestFilter; options.winstonInstance = options.winstonInstance || (new winston.Logger ({ transports: options.transports })); options.msg = options.msg || 'middlewareError'; @@ -133,7 +134,7 @@ function errorLogger(options) { // Let winston gather all the error data. var exceptionMeta = winston.exception.getAllInfo(err); - exceptionMeta.req = filterObject(req, requestWhitelist, options.requestFilter); + exceptionMeta.req = filterObject(req, options.requestWhitelist, options.requestFilter); if (options.metaField) { var newMeta = {}; @@ -161,8 +162,13 @@ function logger(options) { ensureValidOptions(options); ensureValidLoggerOptions(options); + options.requestWhitelist = options.requestWhitelist || globalRequestWhitelist; + options.bodyWhitelist = options.bodyWhitelist || globalBodyWhitelist; + options.bodyBlacklist = options.bodyBlacklist || globalBodyBlacklist; + options.responseWhitelist = options.responseWhitelist || globalResponseWhitelist; options.requestFilter = options.requestFilter || defaultRequestFilter; options.responseFilter = options.responseFilter || defaultResponseFilter; + options.ignoredRoutes = options.ignoredRoutes || globalIgnoredRoutes; options.winstonInstance = options.winstonInstance || (new winston.Logger ({ transports: options.transports })); options.level = options.level || "info"; options.statusLevels = options.statusLevels || false; @@ -181,7 +187,7 @@ function logger(options) { return function (req, res, next) { var currentUrl = req.originalUrl || req.url; - if (currentUrl && _.contains(ignoredRoutes, currentUrl)) return next(); + if (currentUrl && _.contains(options.ignoredRoutes, currentUrl)) return next(); if (options.ignoreRoute(req, res)) return next(); req._startTime = (new Date); @@ -225,10 +231,9 @@ function logger(options) { if(options.meta !== false) { var logData = {}; - var bodyWhitelist, blacklist; - requestWhitelist = requestWhitelist.concat(req._routeWhitelists.req || []); - responseWhitelist = responseWhitelist.concat(req._routeWhitelists.res || []); + var requestWhitelist = options.requestWhitelist.concat(req._routeWhitelists.req || []); + var responseWhitelist = options.responseWhitelist.concat(req._routeWhitelists.res || []); logData.res = res; @@ -244,8 +249,8 @@ function logger(options) { logData.req = filterObject(req, requestWhitelist, options.requestFilter); logData.res = filterObject(res, responseWhitelist, options.responseFilter); - bodyWhitelist = req._routeWhitelists.body || []; - blacklist = _.union(bodyBlacklist, (req._routeBlacklists.body || [])); + var bodyWhitelist = _.union(options.bodyWhitelist, (req._routeWhitelists.body || [])); + var blacklist = _.union(options.bodyBlacklist, (req._routeBlacklists.body || [])); var filteredBody = null; @@ -303,11 +308,11 @@ function ensureValidLoggerOptions(options) { module.exports.errorLogger = errorLogger; module.exports.logger = logger; -module.exports.requestWhitelist = requestWhitelist; -module.exports.bodyWhitelist = bodyWhitelist; -module.exports.bodyBlacklist = bodyBlacklist; -module.exports.responseWhitelist = responseWhitelist; +module.exports.requestWhitelist = globalRequestWhitelist; +module.exports.bodyWhitelist = globalBodyWhitelist; +module.exports.bodyBlacklist = globalBodyBlacklist; +module.exports.responseWhitelist = globalResponseWhitelist; module.exports.defaultRequestFilter = defaultRequestFilter; module.exports.defaultResponseFilter = defaultResponseFilter; module.exports.defaultSkip = defaultSkip; -module.exports.ignoredRoutes = ignoredRoutes; +module.exports.ignoredRoutes = globalIgnoredRoutes; diff --git a/test/test.js b/test/test.js index ab22563..1b19cce 100644 --- a/test/test.js +++ b/test/test.js @@ -196,6 +196,30 @@ describe('express-winston', function () { }); }); }); + + describe('requestWhitelist option', function () { + it('should default to global requestWhitelist', function () { + var options = { + req: {foo: "bar"} + }; + return errorLoggerTestHelper(options).then(function (result) { + result.log.meta.req.should.not.have.property('foo'); + }); + }); + + it('should use specified requestWhitelist', function () { + var options = { + req: {foo: "bar"}, + loggerOptions: { + requestWhitelist: ['foo'] + } + }; + return errorLoggerTestHelper(options).then(function (result) { + result.log.meta.req.should.have.property('foo'); + result.log.meta.req.should.not.have.property('method'); + }); + }); + }); }); describe('.logger()', function () { @@ -603,6 +627,77 @@ describe('express-winston', function () { }); }); }); + + describe('requestWhitelist option', function () { + it('should default to global requestWhitelist', function () { + var options = { + req: {foo: "bar"} + }; + return loggerTestHelper(options).then(function (result) { + result.log.meta.req.should.not.have.property('foo'); + }); + }); + + it('should use specified requestWhitelist', function () { + var options = { + req: {foo: "bar"}, + loggerOptions: { + requestWhitelist: ['foo'] + } + }; + return loggerTestHelper(options).then(function (result) { + result.log.meta.req.should.have.property('foo'); + result.log.meta.req.should.not.have.property('method'); + }); + }); + }); + + describe('responseWhitelist option', function () { + it('should default to global responseWhitelist', function () { + var options = { + res: {foo: "bar"} + }; + return loggerTestHelper(options).then(function (result) { + result.log.meta.res.should.not.have.property('foo'); + }); + }); + + it('should use specified responseWhitelist', function () { + var options = { + res: {foo: "bar"}, + loggerOptions: { + responseWhitelist: ['foo'] + } + }; + return loggerTestHelper(options).then(function (result) { + result.log.meta.res.should.have.property('foo'); + result.log.meta.res.should.not.have.property('method'); + }); + }); + }); + + describe('ignoredRoutes option', function () { + it('should default to global ignoredRoutes', function () { + var options = { + req: {url: "/ignored"} + }; + return loggerTestHelper(options).then(function (result) { + result.transportInvoked.should.eql(false); + }); + }); + + it('should use specified ignoredRoutes', function () { + var options = { + req: {url: "/ignored-option"}, + loggerOptions: { + ignoredRoutes: ['/ignored-option'] + } + }; + return loggerTestHelper(options).then(function (result) { + result.transportInvoked.should.eql(false); + }); + }); + }); }); describe('.requestWhitelist', function () {