From 21a6660103d4385fb19488dff4ebb312e0b0a75e Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Fri, 25 Sep 2015 11:27:58 -0700 Subject: [PATCH] Adding filtering to the logger - Closes #5036 - Add `applyFilterToKey()` - Add test for `applyFilterToKey()` - Add `filter` attribute to config for reporters - Add `this.filter` method to `LogFormat` class --- src/server/logging/LogFormat.js | 16 +++++- src/server/logging/LogReporter.js | 2 +- .../logging/__tests__/applyFilterToKey.js | 49 +++++++++++++++++++ src/server/logging/applyFilterToKey.js | 23 +++++++++ src/server/logging/index.js | 5 +- 5 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/server/logging/__tests__/applyFilterToKey.js create mode 100644 src/server/logging/applyFilterToKey.js diff --git a/src/server/logging/LogFormat.js b/src/server/logging/LogFormat.js index db901d2ecc907..eb34d4fa40499 100644 --- a/src/server/logging/LogFormat.js +++ b/src/server/logging/LogFormat.js @@ -6,6 +6,7 @@ let ansicolors = require('ansicolors'); let stringify = require('json-stringify-safe'); let querystring = require('querystring'); let inspect = require('util').inspect; +let applyFilterToKey = require('./applyFilterToKey'); function serializeError(err) { return { @@ -24,16 +25,27 @@ let levelColor = function (code) { return ansicolors.red(code); }; + module.exports = class TransformObjStream extends Stream.Transform { - constructor() { + constructor(config) { super({ readableObjectMode: false, writableObjectMode: true }); + this.config = config; + } + + filter(data) { + if (this.config.filter) { + _.each(this.config.filter, (action, key) => { + applyFilterToKey(data, key, action); + }); + } + return data; } _transform(event, enc, next) { - var data = this.readEvent(event); + var data = this.filter(this.readEvent(event)); this.push(this.format(data) + '\n'); next(); } diff --git a/src/server/logging/LogReporter.js b/src/server/logging/LogReporter.js index 246e8164db60e..ac098732a711a 100644 --- a/src/server/logging/LogReporter.js +++ b/src/server/logging/LogReporter.js @@ -8,7 +8,7 @@ let LogFormatString = require('./LogFormatString'); module.exports = class KbnLogger { constructor(events, config) { this.squeeze = new Squeeze(events); - this.format = config.json ? new LogFormatJson() : new LogFormatString(); + this.format = config.json ? new LogFormatJson(config) : new LogFormatString(config); if (config.dest === 'stdout') { this.dest = process.stdout; diff --git a/src/server/logging/__tests__/applyFilterToKey.js b/src/server/logging/__tests__/applyFilterToKey.js new file mode 100644 index 0000000000000..ef319a216297b --- /dev/null +++ b/src/server/logging/__tests__/applyFilterToKey.js @@ -0,0 +1,49 @@ +var applyFilterToKey = require('../applyFilterToKey'); +var expect = require('expect.js'); + +function fixture() { + return { + req: { + headers: { + authorization: 'Basic dskd939k2i' + } + } + }; +} + +describe('applyFilterToKey(obj, key, action)', function () { + + it('should remove a key from an object recursivly', function () { + var data = fixture(); + applyFilterToKey(data, 'authorization', 'remove'); + expect(data).to.eql({ + req: { headers: {} } + }); + }); + + it('should censor a key in an object recursivly', function () { + var data = fixture(); + applyFilterToKey(data, 'authorization', 'censor'); + expect(data).to.eql({ + req: { + headers: { + authorization: 'XXXXXXXXXXXXXXXX' + } + } + }); + }); + + it('should censor key with a RegEx in an object recursivly', function () { + var data = fixture(); + var regex = /([^\s]+)$/; + applyFilterToKey(data, 'authorization', regex); + expect(data).to.eql({ + req: { + headers: { + authorization: 'Basic XXXXXXXXXX' + } + } + }); + }); + +}); diff --git a/src/server/logging/applyFilterToKey.js b/src/server/logging/applyFilterToKey.js new file mode 100644 index 0000000000000..6046ee867c684 --- /dev/null +++ b/src/server/logging/applyFilterToKey.js @@ -0,0 +1,23 @@ +function replacer(match, group) { + return (new Array(group.length + 1).join('X')); +} + +module.exports = function applyFilterToKey(obj, key, action) { + for (let k in obj) { + if (obj.hasOwnProperty(k)) { + let val = obj[k]; + if (typeof val === 'object') { + applyFilterToKey(val, key, action); + } else if (k === key) { + val = '' + val; + if (action === 'remove') delete obj[k]; + if (action === 'censor') { + obj[k] = val.replace(/./g, 'X'); + }; + if (action instanceof RegExp) { + obj[k] = val.replace(action, replacer); + } + } + } + } +}; diff --git a/src/server/logging/index.js b/src/server/logging/index.js index 8ac4bb4d7ef85..ee8c169565339 100644 --- a/src/server/logging/index.js +++ b/src/server/logging/index.js @@ -42,7 +42,10 @@ module.exports = function (kbnServer, server, config) { reporter: require('./LogReporter'), config: { json: config.get('logging.json'), - dest: config.get('logging.dest') + dest: config.get('logging.dest'), + filter: { + authorization: 'remove' + } }, events: _.transform(events, function (filtered, val, key) { // provide a string compatible way to remove events