Skip to content

Commit

Permalink
Merge pull request #105 from nwah/master
Browse files Browse the repository at this point in the history
Add per-instance equivalents of all global white/blacklists
  • Loading branch information
rosston committed Mar 8, 2016
2 parents ec84d44 + 649df26 commit 005bb1d
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 17 deletions.
7 changes: 7 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)`.
Expand Down
39 changes: 22 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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';
Expand All @@ -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 = {};
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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;
95 changes: 95 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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 () {
Expand Down

0 comments on commit 005bb1d

Please sign in to comment.