feat(categoryInheritance): using preProcessingListener

for preparing config before validation and interpretation
This commit is contained in:
Paul Harapiak 2019-05-04 12:10:16 -04:00
parent 045a1feef0
commit 6bff3bb7f4
5 changed files with 141 additions and 101 deletions

View File

@ -59,7 +59,7 @@ function inheritFromParent(config, category, categoryName) {
* Inheritance is skipped where a category has inherit=false.
* @param {any} config
*/
function addInheritedConfig(config) {
function addCategoryInheritance(config) {
if (!config.categories) return;
const categoryNames = Object.keys(config.categories);
categoryNames.forEach((name) => {
@ -69,6 +69,7 @@ function addInheritedConfig(config) {
});
}
configuration.addPreProcessingListener(config => addCategoryInheritance(config));
configuration.addListener((config) => {
configuration.throwExceptionIf(
@ -182,7 +183,6 @@ const setLevelForCategory = (category, level) => {
};
module.exports = {
addInheritedConfig,
appendersForCategory,
getLevelForCategory,
setLevelForCategory

View File

@ -3,6 +3,7 @@
const util = require('util');
const debug = require('debug')('log4js:configuration');
const preProcessingListeners = [];
const listeners = [];
const not = thing => !thing;
@ -15,7 +16,12 @@ const anInteger = thing => thing && typeof thing === 'number' && Number.isIntege
const addListener = (fn) => {
listeners.push(fn);
debug(`Added listener, listeners now ${listeners.length}`);
debug(`Added listener, now ${listeners.length} listeners`);
};
const addPreProcessingListener = (fn) => {
preProcessingListeners.push(fn);
debug(`Added pre-processing listener, now ${preProcessingListeners.length} listeners`);
};
const throwExceptionIf = (config, checks, message) => {
@ -32,6 +38,10 @@ const configure = (candidate) => {
debug('New configuration to be validated: ', candidate);
throwExceptionIf(candidate, not(anObject(candidate)), 'must be an object.');
debug(`Calling pre-processing listeners (${preProcessingListeners.length})`);
preProcessingListeners.forEach(listener => listener(candidate));
debug('Configuration pre-processing finished.');
debug(`Calling configuration listeners (${listeners.length})`);
listeners.forEach(listener => listener(candidate));
debug('Configuration finished.');
@ -40,6 +50,7 @@ const configure = (candidate) => {
module.exports = {
configure,
addListener,
addPreProcessingListener,
throwExceptionIf,
anObject,
anInteger,

View File

@ -59,8 +59,6 @@ function configure(configurationFileOrObject) {
}
debug(`Configuration is ${configObject}`);
categories.addInheritedConfig(configObject); // copy config from parent to child categories
configuration.configure(deepClone(configObject));
clustering.onMessage(sendLogEventToAppender);

View File

@ -1,18 +1,15 @@
'use strict';
const test = require('tap').test;
// const util = require('util');
// const debug = require('debug')('log4js:test.configuration-inheritance');
const log4js = require('../../lib/log4js');
// const configuration = require('../../lib/configuration');
const categories = require('../../lib/categories');
test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('should inherit appenders from direct parent', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -23,21 +20,23 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 2, 'inherited 2 appenders');
t.ok(child.appenders.includes('stdout1'), 'inherited stdout1');
t.ok(child.appenders.includes('stdout2'), 'inherited stdout2');
t.isEqual(child.level, 'DEBUG', 'child level overrides parent');
const childCategoryName = 'catA.catB';
const childAppenders = categories.appendersForCategory(childCategoryName);
const childLevel = categories.getLevelForCategory(childCategoryName);
t.ok(childAppenders);
t.isEqual(childAppenders.length, 2, 'inherited 2 appenders');
t.ok(childAppenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
t.ok(childAppenders.some(a => a.label === 'stdout2'), 'inherited stdout2');
t.isEqual(childLevel.levelStr, 'DEBUG', 'child level overrides parent');
t.end();
});
batch.test('multiple children should inherit config from shared parent', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -49,20 +48,23 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child1 = config.categories['catA.catB.cat1'];
t.ok(child1);
t.ok(child1.appenders);
t.isEqual(child1.appenders.length, 1, 'inherited 1 appender');
t.ok(child1.appenders.includes('stdout1'), 'inherited stdout1');
t.isEqual(child1.level, 'DEBUG', 'child level overrides parent');
const child1CategoryName = 'catA.catB.cat1';
const child1Appenders = categories.appendersForCategory(child1CategoryName);
const child1Level = categories.getLevelForCategory(child1CategoryName);
const child2 = config.categories['catA.catB.cat2'];
t.ok(child2);
t.ok(child2.appenders);
t.isEqual(child2.appenders.length, 2, 'inherited 1 appenders, plus its original');
t.ok(child2.appenders.includes('stdout1'), 'inherited stdout1');
t.ok(child2.appenders.includes('stdout2'), 'kept stdout2');
t.isEqual(child2.level, 'INFO', 'inherited parent level');
t.isEqual(child1Appenders.length, 1, 'inherited 1 appender');
t.ok(child1Appenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
t.isEqual(child1Level.levelStr, 'DEBUG', 'child level overrides parent');
const child2CategoryName = 'catA.catB.cat2';
const child2Appenders = categories.appendersForCategory(child2CategoryName);
const child2Level = categories.getLevelForCategory(child2CategoryName);
t.ok(child2Appenders);
t.isEqual(child2Appenders.length, 2, 'inherited 1 appenders, plus its original');
t.ok(child2Appenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
t.ok(child2Appenders.some(a => a.label === 'stdout2'), 'kept stdout2');
t.isEqual(child2Level.levelStr, 'INFO', 'inherited parent level');
t.end();
});
@ -70,8 +72,8 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('should inherit appenders from multiple parents', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -83,20 +85,21 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB.catC'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 2, 'inherited 2 appenders');
t.ok(child.appenders.includes('stdout1'), 'inherited stdout1');
t.ok(child.appenders.includes('stdout1'), 'inherited stdout1');
const childCategoryName = 'catA.catB.catC';
const childAppenders = categories.appendersForCategory(childCategoryName);
const firstParent = config.categories['catA.catB'];
t.ok(firstParent);
t.ok(firstParent.appenders);
t.isEqual(firstParent.appenders.length, 2, 'ended up with 2 appenders');
t.ok(firstParent.appenders.includes('stdout1'), 'inherited stdout1');
t.ok(firstParent.appenders.includes('stdout2'), 'kept stdout2');
t.ok(childAppenders);
t.isEqual(childAppenders.length, 2, 'inherited 2 appenders');
t.ok(childAppenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
t.ok(childAppenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
const firstParentName = 'catA.catB';
const firstParentAppenders = categories.appendersForCategory(firstParentName);
t.ok(firstParentAppenders);
t.isEqual(firstParentAppenders.length, 2, 'ended up with 2 appenders');
t.ok(firstParentAppenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
t.ok(firstParentAppenders.some(a => a.label === 'stdout2'), 'kept stdout2');
t.end();
});
@ -104,8 +107,8 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('should inherit appenders from deep parent with missing direct parent', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -117,17 +120,19 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB.catC'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 1, 'inherited 1 appenders');
t.ok(child.appenders.includes('stdout1'), 'inherited stdout1');
const childCategoryName = 'catA.catB.catC';
const childAppenders = categories.appendersForCategory(childCategoryName);
const firstParent = config.categories['catA.catB'];
t.ok(firstParent);
t.ok(firstParent.appenders, 'catA.catB got created implicitily');
t.isEqual(firstParent.appenders.length, 1, 'created with 1 inherited appender');
t.ok(firstParent.appenders.includes('stdout1'), 'inherited stdout1');
t.ok(childAppenders);
t.isEqual(childAppenders.length, 1, 'inherited 1 appenders');
t.ok(childAppenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
const firstParentCategoryName = 'catA.catB';
const firstParentAppenders = categories.appendersForCategory(firstParentCategoryName);
t.ok(firstParentAppenders, 'catA.catB got created implicitily');
t.isEqual(firstParentAppenders.length, 1, 'created with 1 inherited appender');
t.ok(firstParentAppenders.some(a => a.label === 'stdout1'), 'inherited stdout1');
t.end();
});
@ -135,8 +140,8 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('should deal gracefully with missing parent', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -147,11 +152,12 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB.catC'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 1);
t.ok(child.appenders.includes('stdout2'));
const childCategoryName = 'catA.catB.catC';
const childAppenders = categories.appendersForCategory(childCategoryName);
t.ok(childAppenders);
t.isEqual(childAppenders.length, 1);
t.ok(childAppenders.some(a => a.label === 'stdout2'));
t.end();
});
@ -160,8 +166,8 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('should not get duplicate appenders if parent has the same one', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -172,20 +178,21 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 2, 'inherited 1 appender');
t.ok(child.appenders.includes('stdout1'), 'still have stdout1');
t.ok(child.appenders.includes('stdout2'), 'inherited stdout2');
const childCategoryName = 'catA.catB';
const childAppenders = categories.appendersForCategory(childCategoryName);
t.ok(childAppenders);
t.isEqual(childAppenders.length, 2, 'inherited 1 appender');
t.ok(childAppenders.some(a => a.label === 'stdout1'), 'still have stdout1');
t.ok(childAppenders.some(a => a.label === 'stdout2'), 'inherited stdout2');
t.end();
});
batch.test('inherit:falses should disable inheritance', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -196,11 +203,12 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 1, 'inherited no appender');
t.ok(child.appenders.includes('stdout2'), 'kept stdout2');
const childCategoryName = 'catA.catB';
const childAppenders = categories.appendersForCategory(childCategoryName);
t.ok(childAppenders);
t.isEqual(childAppenders.length, 1, 'inherited no appender');
t.ok(childAppenders.some(a => a.label === 'stdout2'), 'kept stdout2');
t.end();
});
@ -209,8 +217,8 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('inheritance should stop if direct parent has inherit off', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -222,17 +230,19 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB.catC'];
t.ok(child);
t.ok(child.appenders);
t.isEqual(child.appenders.length, 1, 'inherited 1 appender');
t.ok(child.appenders.includes('stdout2'), 'inherited stdout2');
const childCategoryName = 'catA.catB.catC';
const childAppenders = categories.appendersForCategory(childCategoryName);
const firstParent = config.categories['catA.catB'];
t.ok(firstParent);
t.ok(firstParent.appenders);
t.isEqual(firstParent.appenders.length, 1, 'did not inherit new appenders');
t.ok(firstParent.appenders.includes('stdout2'), 'kept stdout2');
t.ok(childAppenders);
t.isEqual(childAppenders.length, 1, 'inherited 1 appender');
t.ok(childAppenders.some(a => a.label === 'stdout2'), 'inherited stdout2');
const firstParentCategoryName = 'catA.catB';
const firstParentAppenders = categories.appendersForCategory(firstParentCategoryName);
t.ok(firstParentAppenders);
t.isEqual(firstParentAppenders.length, 1, 'did not inherit new appenders');
t.ok(firstParentAppenders.some(a => a.label === 'stdout2'), 'kept stdout2');
t.end();
});
@ -240,8 +250,8 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
batch.test('should inherit level when it is missing', (t) => {
const config = {
appenders: {
stdout1: { type: 'stdout' },
stdout2: { type: 'stdout' }
stdout1: { type: 'dummy-appender', label: 'stdout1' },
stdout2: { type: 'dummy-appender', label: 'stdout2' }
},
categories: {
default: { appenders: ['stdout1'], level: 'ERROR' },
@ -253,13 +263,15 @@ test('log4js category inherit all appenders from direct parent', (batch) => {
log4js.configure(config);
const child = config.categories['catA.catB.catC'];
t.ok(child);
t.isEqual(child.level, 'INFO', 'inherited level');
const childCategoryName = 'catA.catB.catC';
const childLevel = categories.getLevelForCategory(childCategoryName);
const firstParent = config.categories['catA.catB'];
t.ok(firstParent);
t.isEqual(firstParent.level, 'INFO', 'generate parent inherited level from base');
t.isEqual(childLevel.levelStr, 'INFO', 'inherited level');
const firstParentCategoryName = 'catA.catB';
const firstParentLevel = categories.getLevelForCategory(firstParentCategoryName);
t.isEqual(firstParentLevel.levelStr, 'INFO', 'generate parent inherited level from base');
t.end();
});

View File

@ -0,0 +1,19 @@
// Dummy appender for test purposes; set config.label to identify instances in a test
function createDummyAppender() { // This is the function that generates an appender function
// This is the appender function itself
return (/* loggingEvent */) => {
// do nothing
// console.log(loggingEvent.data);
};
}
function configure(config) {
// create a new appender instance
const appender = createDummyAppender();
appender.label = config.label;
return appender;
}
// export the only function needed
exports.configure = configure;