const configuration = require('./configuration'); const levels = require('./levels'); const appenders = require('./appenders'); const debug = require('debug')('log4js:categories'); const categories = new Map(); configuration.addListener((config) => { configuration.throwExceptionIf( config, configuration.not(configuration.anObject(config.categories)), 'must have a property "categories" of type object.' ); const categoryNames = Object.keys(config.categories); configuration.throwExceptionIf( config, configuration.not(categoryNames.length), 'must define at least one category.' ); categoryNames.forEach((name) => { const category = config.categories[name]; configuration.throwExceptionIf( config, [ configuration.not(category.appenders), configuration.not(category.level) ], `category "${name}" is not valid (must be an object with properties "appenders" and "level")` ); configuration.throwExceptionIf( config, configuration.not(Array.isArray(category.appenders)), `category "${name}" is not valid (appenders must be an array of appender names)` ); configuration.throwExceptionIf( config, configuration.not(category.appenders.length), `category "${name}" is not valid (appenders must contain at least one appender name)` ); category.appenders.forEach((appender) => { configuration.throwExceptionIf( config, configuration.not(appenders.get(appender)), `category "${name}" is not valid (appender "${appender}" is not defined)` ); }); configuration.throwExceptionIf( config, configuration.not(levels.getLevel(category.level)), `category "${name}" is not valid (level "${category.level}" not recognised;` + ` valid levels are ${levels.levels.join(', ')})` ); }); configuration.throwExceptionIf( config, configuration.not(config.categories.default), 'must define a "default" category.' ); }); const setup = (config) => { categories.clear(); const categoryNames = Object.keys(config.categories); categoryNames.forEach((name) => { const category = config.categories[name]; const categoryAppenders = []; category.appenders.forEach((appender) => { categoryAppenders.push(appenders.get(appender)); debug(`Creating category ${name}`); categories.set( name, { appenders: categoryAppenders, level: levels.getLevel(category.level) } ); }); }); }; setup({ categories: { default: { appenders: ['out'], level: 'OFF' } } }); configuration.addListener(setup); const configForCategory = (category) => { debug(`configForCategory: searching for config for ${category}`); if (categories.has(category)) { debug(`configForCategory: ${category} exists in config, returning it`); return categories.get(category); } if (category.indexOf('.') > 0) { debug(`configForCategory: ${category} has hierarchy, searching for parents`); return configForCategory(category.substring(0, category.lastIndexOf('.'))); } debug('configForCategory: returning config for default category'); return configForCategory('default'); }; const appendersForCategory = category => configForCategory(category).appenders; const getLevelForCategory = category => configForCategory(category).level; const setLevelForCategory = (category, level) => { let categoryConfig = categories.get(category); debug(`setLevelForCategory: found ${categoryConfig} for ${category}`); if (!categoryConfig) { const sourceCategoryConfig = configForCategory(category); debug('setLevelForCategory: no config found for category, ' + `found ${sourceCategoryConfig} for parents of ${category}`); categoryConfig = { appenders: sourceCategoryConfig.appenders }; } categoryConfig.level = level; categories.set(category, categoryConfig); }; module.exports = { appendersForCategory, getLevelForCategory, setLevelForCategory };