diff --git a/lib/categories.js b/lib/categories.js index 5a99ebd..06ab4ca 100644 --- a/lib/categories.js +++ b/lib/categories.js @@ -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 diff --git a/lib/configuration.js b/lib/configuration.js index b6b62a5..b91d13c 100644 --- a/lib/configuration.js +++ b/lib/configuration.js @@ -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, diff --git a/lib/log4js.js b/lib/log4js.js index 7b357d9..5883c47 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -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); diff --git a/test/tap/configuration-inheritance-test.js b/test/tap/configuration-inheritance-test.js index aaf80c2..2afefd3 100644 --- a/test/tap/configuration-inheritance-test.js +++ b/test/tap/configuration-inheritance-test.js @@ -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(); }); diff --git a/test/tap/dummy-appender.js b/test/tap/dummy-appender.js new file mode 100644 index 0000000..f59ceba --- /dev/null +++ b/test/tap/dummy-appender.js @@ -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;