diff --git a/lib/appenders/categoryFilter.js b/lib/appenders/categoryFilter.js index c4ab9d7..263970b 100644 --- a/lib/appenders/categoryFilter.js +++ b/lib/appenders/categoryFilter.js @@ -1,7 +1,5 @@ 'use strict'; -const log4js = require('../log4js'); - function categoryFilter(excludes, appender) { if (typeof excludes === 'string') excludes = [excludes]; return (logEvent) => { @@ -11,11 +9,9 @@ function categoryFilter(excludes, appender) { }; } -function configure(config, options) { - log4js.loadAppender(config.appender.type); - const appender = log4js.appenderMakers[config.appender.type](config.appender, options); +function configure(config, layouts, findAppender) { + const appender = findAppender(config.appender); return categoryFilter(config.exclude, appender); } -module.exports.appender = categoryFilter; module.exports.configure = configure; diff --git a/lib/appenders/console.js b/lib/appenders/console.js index 6b2e691..25211f6 100644 --- a/lib/appenders/console.js +++ b/lib/appenders/console.js @@ -1,23 +1,19 @@ 'use strict'; -const layouts = require('../layouts'); - const consoleLog = console.log.bind(console); function consoleAppender(layout, timezoneOffset) { - layout = layout || layouts.colouredLayout; return (loggingEvent) => { consoleLog(layout(loggingEvent, timezoneOffset)); }; } -function configure(config) { - let layout; +function configure(config, layouts) { + let layout = layouts.colouredLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } return consoleAppender(layout, config.timezoneOffset); } -module.exports.appender = consoleAppender; module.exports.configure = configure; diff --git a/lib/appenders/dateFile.js b/lib/appenders/dateFile.js index 3b31bdc..0357d0e 100644 --- a/lib/appenders/dateFile.js +++ b/lib/appenders/dateFile.js @@ -1,18 +1,14 @@ 'use strict'; const streams = require('streamroller'); -const layouts = require('../layouts'); -const path = require('path'); const os = require('os'); const eol = os.EOL || '\n'; -const openFiles = []; +const appenders = []; // close open files on process exit. process.on('exit', () => { - openFiles.forEach((file) => { - file.end(); - }); + appenders.forEach((a) => { a.shutdown(); }); }); /** @@ -30,21 +26,33 @@ function appender( options, timezoneOffset ) { - layout = layout || layouts.basicLayout; const logFile = new streams.DateRollingFileStream( filename, pattern, options ); - openFiles.push(logFile); - return (logEvent) => { + const app = function (logEvent) { logFile.write(layout(logEvent, timezoneOffset) + eol, 'utf8'); }; + + app.shutdown = function (cb) { + if (!logFile.write(eol, 'utf-8')) { + logFile.once('drain', () => { + logFile.end(cb); + }); + } else { + logFile.end(cb); + } + }; + + appenders.push(app); + + return app; } -function configure(config, options) { - let layout; +function configure(config, layouts) { + let layout = layouts.basicLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); @@ -54,10 +62,6 @@ function configure(config, options) { config.alwaysIncludePattern = false; } - if (options && options.cwd && !config.absolute) { - config.filename = path.join(options.cwd, config.filename); - } - return appender( config.filename, config.pattern, @@ -67,31 +71,4 @@ function configure(config, options) { ); } -function shutdown(cb) { - let completed = 0; - let error; - const complete = (err) => { - error = error || err; - completed++; // eslint-disable-line no-plusplus - if (completed >= openFiles.length) { - cb(error); - } - }; - if (!openFiles.length) { - return cb(); - } - - return openFiles.forEach((file) => { - if (!file.write(eol, 'utf-8')) { - file.once('drain', () => { - file.end(complete); - }); - } else { - file.end(complete); - } - }); -} - -module.exports.appender = appender; module.exports.configure = configure; -module.exports.shutdown = shutdown; diff --git a/lib/appenders/file.js b/lib/appenders/file.js index 9284e14..3264495 100644 --- a/lib/appenders/file.js +++ b/lib/appenders/file.js @@ -1,20 +1,17 @@ 'use strict'; const debug = require('debug')('log4js:file'); -const layouts = require('../layouts'); const path = require('path'); const streams = require('streamroller'); const os = require('os'); const eol = os.EOL || '\n'; -const openFiles = []; +const appenders = []; // close open files on process exit. process.on('exit', () => { debug('Exit handler called.'); - openFiles.forEach((file) => { - file.end(); - }); + appenders.forEach((a) => { a.shutdown(); }); }); // On SIGHUP, close and reopen all files. This allows this appender to work with @@ -22,11 +19,25 @@ process.on('exit', () => { // `logSize`. process.on('SIGHUP', () => { debug('SIGHUP handler called.'); - openFiles.forEach((writer) => { - writer.closeTheStream(writer.openTheStream.bind(writer)); + appenders.forEach((a) => { + a.reopen(); }); }); +function openTheStream(file, fileSize, numFiles, options) { + const stream = new streams.RollingFileStream( + file, + fileSize, + numFiles, + options + ); + stream.on('error', (err) => { + console.error('log4js.fileAppender - Writing to file %s, error happened ', file, err); + }); + return stream; +} + + /** * File Appender writing the logs to a text file. Supports rolling of logs by size. * @@ -42,7 +53,6 @@ process.on('SIGHUP', () => { */ function fileAppender(file, layout, logSize, numBackups, options, timezoneOffset) { file = path.normalize(file); - layout = layout || layouts.basicLayout; numBackups = numBackups === undefined ? 5 : numBackups; // there has to be at least one backup if logSize has been specified numBackups = numBackups === 0 ? 1 : numBackups; @@ -54,40 +64,38 @@ function fileAppender(file, layout, logSize, numBackups, options, timezoneOffset options, ', ', timezoneOffset, ')' ); + const writer = openTheStream(file, logSize, numBackups, options); - // push file to the stack of open handlers - openFiles.push(writer); - - return function (loggingEvent) { + const app = function (loggingEvent) { writer.write(layout(loggingEvent, timezoneOffset) + eol, 'utf8'); }; + + app.reopen = function () { + writer.closeTheStream(writer.openTheStream.bind(writer)); + }; + + app.shutdown = function (complete) { + if (!writer.write(eol, 'utf-8')) { + writer.once('drain', () => { + writer.end(complete); + }); + } else { + writer.end(complete); + } + }; + + // push file to the stack of open handlers + appenders.push(app); + return app; } -function openTheStream(file, fileSize, numFiles, options) { - const stream = new streams.RollingFileStream( - file, - fileSize, - numFiles, - options - ); - stream.on('error', (err) => { - console.error('log4js.fileAppender - Writing to file %s, error happened ', file, err); - }); - return stream; -} - - -function configure(config, options) { - let layout; +function configure(config, layouts) { + let layout = layouts.basicLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } - if (options && options.cwd && !config.absolute) { - config.filename = path.join(options.cwd, config.filename); - } - return fileAppender( config.filename, layout, @@ -98,31 +106,4 @@ function configure(config, options) { ); } -function shutdown(cb) { - let completed = 0; - let error; - const complete = (err) => { - error = error || err; - completed++; // eslint-disable-line no-plusplus - if (completed >= openFiles.length) { - cb(error); - } - }; - if (!openFiles.length) { - return cb(); - } - - return openFiles.forEach((file) => { - if (!file.write(eol, 'utf-8')) { - file.once('drain', () => { - file.end(complete); - }); - } else { - file.end(complete); - } - }); -} - -module.exports.appender = fileAppender; module.exports.configure = configure; -module.exports.shutdown = shutdown; diff --git a/lib/appenders/fileSync.js b/lib/appenders/fileSync.js index dab551c..36254a9 100755 --- a/lib/appenders/fileSync.js +++ b/lib/appenders/fileSync.js @@ -1,7 +1,6 @@ 'use strict'; const debug = require('debug')('log4js:fileSync'); -const layouts = require('../layouts'); const path = require('path'); const fs = require('fs'); const os = require('os'); @@ -135,7 +134,6 @@ class RollingFileSync { function fileAppender(file, layout, logSize, numBackups, timezoneOffset) { debug('fileSync appender created'); file = path.normalize(file); - layout = layout || layouts.basicLayout; numBackups = numBackups === undefined ? 5 : numBackups; // there has to be at least one backup if logSize has been specified numBackups = numBackups === 0 ? 1 : numBackups; @@ -174,16 +172,12 @@ function fileAppender(file, layout, logSize, numBackups, timezoneOffset) { }; } -function configure(config, options) { - let layout; +function configure(config, layouts) { + let layout = layouts.basicLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } - if (options && options.cwd && !config.absolute) { - config.filename = path.join(options.cwd, config.filename); - } - return fileAppender( config.filename, layout, @@ -193,5 +187,4 @@ function configure(config, options) { ); } -module.exports.appender = fileAppender; module.exports.configure = configure; diff --git a/lib/appenders/gelf.js b/lib/appenders/gelf.js index eb809ed..2d922b0 100644 --- a/lib/appenders/gelf.js +++ b/lib/appenders/gelf.js @@ -1,7 +1,6 @@ 'use strict'; const zlib = require('zlib'); -const layouts = require('../layouts'); const levels = require('../levels'); const dgram = require('dgram'); const util = require('util'); @@ -27,8 +26,6 @@ levelMapping[levels.WARN] = LOG_WARNING; levelMapping[levels.ERROR] = LOG_ERROR; levelMapping[levels.FATAL] = LOG_CRIT; -let client; - /** * GELF appender that supports sending UDP packets to a GELF compatible server such as Graylog * @@ -54,7 +51,6 @@ function gelfAppender(layout, host, port, hostname, facility) { host = host || 'localhost'; port = port || 12201; hostname = hostname || OS.hostname(); - layout = layout || layouts.messagePassThroughLayout; const defaultCustomFields = customFields || {}; @@ -62,7 +58,7 @@ function gelfAppender(layout, host, port, hostname, facility) { defaultCustomFields._facility = facility; } - client = dgram.createSocket('udp4'); + const client = dgram.createSocket('udp4'); process.on('exit', () => { if (client) client.close(); @@ -123,7 +119,7 @@ function gelfAppender(layout, host, port, hostname, facility) { }); } - return (loggingEvent) => { + const app = (loggingEvent) => { const message = preparePacket(loggingEvent); zlib.gzip(new Buffer(JSON.stringify(message)), (err, packet) => { if (err) { @@ -137,23 +133,21 @@ function gelfAppender(layout, host, port, hostname, facility) { } }); }; + app.shutdown = function (cb) { + if (client) { + client.close(cb); + } + }; + + return app; } -function configure(config) { - let layout; +function configure(config, layouts) { + let layout = layouts.messagePassThroughLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } return gelfAppender(layout, config); } -function shutdown(cb) { - if (client) { - client.close(cb); - client = null; - } -} - -module.exports.appender = gelfAppender; module.exports.configure = configure; -module.exports.shutdown = shutdown; diff --git a/lib/appenders/hipchat.js b/lib/appenders/hipchat.js index 8c3a3be..a071310 100644 --- a/lib/appenders/hipchat.js +++ b/lib/appenders/hipchat.js @@ -1,17 +1,12 @@ 'use strict'; const hipchat = require('hipchat-notifier'); -const layouts = require('../layouts'); - -module.exports.name = 'hipchat'; -module.exports.appender = hipchatAppender; -module.exports.configure = hipchatConfigure; /** @invoke as log4js.configure({ - 'appenders': [ + 'appenders': { 'hipchat': { 'type' : 'hipchat', 'hipchat_token': '< User token with Notification Privileges >', @@ -21,7 +16,8 @@ module.exports.configure = hipchatConfigure; 'hipchat_notify': '[ notify boolean to bug people ]', 'hipchat_host' : 'api.hipchat.com' } - ] + }, + categories: { default: { appenders: ['hipchat'], level: 'debug' }} }); var logger = log4js.getLogger('hipchat'); @@ -29,17 +25,16 @@ module.exports.configure = hipchatConfigure; @invoke */ -/* eslint no-unused-vars:0 */ -function hipchatNotifierResponseCallback(err, response, body) { + +function hipchatNotifierResponseCallback(err) { if (err) { throw err; } } -function hipchatAppender(config) { +function hipchatAppender(config, layout) { const notifier = hipchat.make(config.hipchat_room, config.hipchat_token); - // @lint W074 This function's cyclomatic complexity is too high. (10) return (loggingEvent) => { let notifierFn; @@ -68,7 +63,7 @@ function hipchatAppender(config) { } // @TODO, re-work in timezoneOffset ? - const layoutMessage = config.layout(loggingEvent); + const layoutMessage = layout(loggingEvent); // dispatch hipchat api request, do not return anything // [overide hipchatNotifierResponseCallback] @@ -77,12 +72,14 @@ function hipchatAppender(config) { }; } -function hipchatConfigure(config) { - let layout; +function hipchatConfigure(config, layouts) { + let layout = layouts.messagePassThroughLayout; - if (!config.layout) { - config.layout = layouts.messagePassThroughLayout; + if (config.layout) { + layout = layouts.layout(config.layout.type, config.layout); } return hipchatAppender(config, layout); } + +module.exports.configure = hipchatConfigure; diff --git a/lib/appenders/logFacesAppender.js b/lib/appenders/logFacesAppender.js index ba7bda6..1564b3f 100644 --- a/lib/appenders/logFacesAppender.js +++ b/lib/appenders/logFacesAppender.js @@ -125,6 +125,5 @@ function wrapErrorsWithInspect(items) { }); } -module.exports.appender = logFacesAppender; module.exports.configure = configure; module.exports.setContext = setContext; diff --git a/lib/appenders/loggly.js b/lib/appenders/loggly.js index 77afd06..84c41d1 100644 --- a/lib/appenders/loggly.js +++ b/lib/appenders/loggly.js @@ -2,27 +2,16 @@ 'use strict'; -const layouts = require('../layouts'); +const debug = require('debug')('log4js:loggly'); const loggly = require('loggly'); const os = require('os'); -const passThrough = layouts.messagePassThroughLayout; - -let openRequests = 0; -let shutdownCB; - function isAnyObject(value) { return value !== null && (typeof value === 'object' || typeof value === 'function'); } function numKeys(obj) { - let res = 0; - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - res++; // eslint-disable-line no-plusplus - } - } - return res; + return Object.keys(obj).length; } /** @@ -64,9 +53,12 @@ function processTags(msgListArgs) { */ function logglyAppender(config, layout) { const client = loggly.createClient(config); - if (!layout) layout = passThrough; + let openRequests = 0; + let shutdownCB; - return (loggingEvent) => { + debug('creating appender.'); + + function app(loggingEvent) { const result = processTags(loggingEvent.data); const deTaggedData = result.deTaggedData; const additionalTags = result.additionalTags; @@ -77,45 +69,52 @@ function logglyAppender(config, layout) { const msg = layout(loggingEvent); openRequests += 1; + debug('sending log event to loggly'); + client.log( + { + msg: msg, + level: loggingEvent.level.levelStr, + category: loggingEvent.categoryName, + hostname: os.hostname().toString(), + }, + additionalTags, + (error) => { + if (error) { + console.error('log4js.logglyAppender - error occurred: ', error); + } - client.log({ - msg: msg, - level: loggingEvent.level.levelStr, - category: loggingEvent.categoryName, - hostname: os.hostname().toString(), - }, additionalTags, (error) => { - if (error) { - console.error('log4js.logglyAppender - error occurred: ', error); + debug('log event received by loggly.'); + + openRequests -= 1; + + if (shutdownCB && openRequests === 0) { + shutdownCB(); + + shutdownCB = undefined; + } } + ); + } - openRequests -= 1; - - if (shutdownCB && openRequests === 0) { - shutdownCB(); - - shutdownCB = undefined; - } - }); + app.shutdown = function (cb) { + debug('shutdown called'); + if (openRequests === 0) { + cb(); + } else { + shutdownCB = cb; + } }; + + return app; } -function configure(config) { - let layout; +function configure(config, layouts) { + let layout = layouts.messagePassThroughLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } + debug('configuring new appender'); return logglyAppender(config, layout); } -function shutdown(cb) { - if (openRequests === 0) { - cb(); - } else { - shutdownCB = cb; - } -} - -module.exports.name = 'loggly'; -module.exports.appender = logglyAppender; module.exports.configure = configure; -module.exports.shutdown = shutdown; diff --git a/lib/configuration.js b/lib/configuration.js index 915c154..caebd7d 100644 --- a/lib/configuration.js +++ b/lib/configuration.js @@ -3,6 +3,7 @@ const util = require('util'); const levels = require('./levels'); const layouts = require('./layouts'); +const debug = require('debug')('log4js:configuration'); function not(thing) { return !thing; @@ -48,6 +49,12 @@ class Configuration { not(appenderModule), `appender "${name}" is not valid (type "${config.type}" could not be found)` ); + if (appenderModule.appender) { + debug(`DEPRECATION: Appender ${config.type} exports an appender function.`); + } + if (appenderModule.shutdown) { + debug(`DEPRECATION: Appender ${config.type} exports a shutdown function.`); + } return appenderModule.configure(config, layouts, this.configuredAppenders.get.bind(this.configuredAppenders)); } @@ -66,6 +73,7 @@ class Configuration { `appender "${name}" is not valid (must be an object with property "type")` ); + debug(`Creating appender ${name}`); this.configuredAppenders.set(name, this.createAppender(name, appenderConfig[name])); }); } @@ -114,6 +122,7 @@ class Configuration { ` valid levels are ${levels.levels.join(', ')})` ); + debug(`Creating category ${name}`); this.configuredCategories.set(name, { appenders: appenders, level: levels.toLevel(category.level) }); }); diff --git a/lib/log4js.js b/lib/log4js.js index 55a4318..23119d2 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -22,6 +22,7 @@ * @static * Website: http://log4js.berlios.de */ +const debug = require('debug')('log4js:main'); const fs = require('fs'); const Configuration = require('./configuration'); const levels = require('./levels'); @@ -74,11 +75,12 @@ function sendLogEventToAppender(logEvent) { */ function getLogger(category) { const cat = category || 'default'; - return new Logger(cat, levelForCategory(cat), sendLogEventToAppender); + return new Logger(sendLogEventToAppender, cat, levelForCategory(cat)); } function loadConfigurationFile(filename) { if (filename) { + debug(`Loading configuration from ${filename}`); return JSON.parse(fs.readFileSync(filename, 'utf8')); } return filename; @@ -90,6 +92,7 @@ function configure(configurationFileOrObject) { if (typeof configObject === 'string') { configObject = loadConfigurationFile(configurationFileOrObject); } + debug(`Configuration is ${configObject}`); config = new Configuration(configObject); enabled = true; } @@ -103,6 +106,7 @@ function configure(configurationFileOrObject) { * as the first argument. */ function shutdown(cb) { + debug('Shutdown called. Disabling all log writing.'); // First, disable all writing to appenders. This prevents appenders from // not being able to be drained because of run-away log writes. enabled = false; @@ -113,15 +117,19 @@ function shutdown(cb) { let completed = 0; let error; + debug(`Found ${shutdownFunctions} appenders with shutdown functions.`); function complete(err) { error = error || err; completed += 1; + debug(`Appender shutdowns complete: ${completed} / ${shutdownFunctions}`); if (completed >= shutdownFunctions) { + debug('All shutdown functions completed.'); cb(error); } } if (shutdownFunctions === 0) { + debug('No appenders with shutdown functions found.'); return cb(); } diff --git a/lib/logger.js b/lib/logger.js index 4955b26..cc5cc30 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -2,10 +2,9 @@ 'use strict'; +const debug = require('debug')('log4js:logger'); const levels = require('./levels'); -// let logWritesEnabled = true; - /** * @name LoggingEvent * @namespace Log4js @@ -40,10 +39,14 @@ class LoggingEvent { * @author Stephan Strittmatter */ class Logger { - constructor(name, level, dispatch) { + constructor(dispatch, name, level) { + if (typeof dispatch !== 'function') { + throw new Error('No dispatch function provided.'); + } this.category = name; this.level = levels.toLevel(level, levels.TRACE); this.dispatch = dispatch; + debug(`Logger created (${name}, ${level})`); } setLevel(level) { @@ -65,6 +68,7 @@ class Logger { } _log(level, data) { + debug(`sending log data (${level}, ${data}) to appenders`); const loggingEvent = new LoggingEvent(this.category, level, data); this.dispatch(loggingEvent); } @@ -85,7 +89,7 @@ function addLevelMethods(target) { /* eslint prefer-rest-params:0 */ // todo: once node v4 support dropped, use rest parameter instead const args = Array.from(arguments); - if (/* logWritesEnabled &&*/ this.isLevelEnabled(level)) { + if (this.isLevelEnabled(level)) { this._log(level, args); } }; @@ -93,24 +97,5 @@ function addLevelMethods(target) { levels.levels.forEach(addLevelMethods); -/** - * Disable all log writes. - * @returns {void} - */ -// function disableAllLogWrites() { -// logWritesEnabled = false; -// } - -/** - * Enable log writes. - * @returns {void} - */ -// function enableAllLogWrites() { -// logWritesEnabled = true; -// } - module.exports.LoggingEvent = LoggingEvent; module.exports.Logger = Logger; -// module.exports.disableAllLogWrites = disableAllLogWrites; -// module.exports.enableAllLogWrites = enableAllLogWrites; -// module.exports.addLevelMethods = addLevelMethods; diff --git a/test/tap/categoryFilter-test.js b/test/tap/categoryFilter-test.js index 4cd1043..cabd7f2 100644 --- a/test/tap/categoryFilter-test.js +++ b/test/tap/categoryFilter-test.js @@ -1,78 +1,62 @@ 'use strict'; const test = require('tap').test; -const fs = require('fs'); -const EOL = require('os').EOL || '\n'; const log4js = require('../../lib/log4js'); - -function remove(filename) { - try { - fs.unlinkSync(filename); - } catch (e) { - // doesn't really matter if it failed - } -} - -function cleanup(done) { - remove(`${__dirname}/categoryFilter-web.log`); - remove(`${__dirname}/categoryFilter-noweb.log`); - done(); -} +const recording = require('../../lib/appenders/recording'); test('log4js categoryFilter', (batch) => { - batch.beforeEach(cleanup); + batch.beforeEach((done) => { recording.reset(); done(); }); batch.test('appender should exclude categories', (t) => { - const logEvents = []; - const appender = require( - '../../lib/appenders/categoryFilter' - ).appender( - ['app'], - (evt) => { - logEvents.push(evt); - } - ); - log4js.clearAppenders(); - log4js.addAppender(appender, ['app', 'web']); + log4js.configure({ + appenders: { + recorder: { type: 'recording' }, + filtered: { + type: 'categoryFilter', + exclude: 'web', + appender: 'recorder' + } + }, + categories: { default: { appenders: ['filtered'], level: 'DEBUG' } } + }); const webLogger = log4js.getLogger('web'); const appLogger = log4js.getLogger('app'); - webLogger.debug('This should get logged'); - appLogger.debug('This should not'); + webLogger.debug('This should not get logged'); + appLogger.debug('This should get logged'); webLogger.debug('Hello again'); - log4js.getLogger('db').debug('This shouldn\'t be included by the appender anyway'); + log4js.getLogger('db').debug('This should be included by the appender anyway'); + const logEvents = recording.replay(); t.equal(logEvents.length, 2); t.equal(logEvents[0].data[0], 'This should get logged'); - t.equal(logEvents[1].data[0], 'Hello again'); + t.equal(logEvents[1].data[0], 'This should be included by the appender anyway'); t.end(); }); - batch.test('should work with configuration file', (t) => { - log4js.configure('test/tap/with-categoryFilter.json'); - const logger = log4js.getLogger('app'); - const weblogger = log4js.getLogger('web'); + batch.test('should not really need a category filter any more', (t) => { + log4js.configure({ + appenders: { recorder: { type: 'recording' } }, + categories: { + default: { appenders: ['recorder'], level: 'DEBUG' }, + web: { appenders: ['recorder'], level: 'OFF' } + } + }); + const appLogger = log4js.getLogger('app'); + const webLogger = log4js.getLogger('web'); - logger.info('Loading app'); - logger.info('Initialising indexes'); - weblogger.info('00:00:00 GET / 200'); - weblogger.warn('00:00:00 GET / 500'); + webLogger.debug('This should not get logged'); + appLogger.debug('This should get logged'); + webLogger.debug('Hello again'); + log4js.getLogger('db').debug('This should be included by the appender anyway'); - setTimeout(() => { - fs.readFile(`${__dirname}/categoryFilter-noweb.log`, 'utf8', (err, contents) => { - const noWebMessages = contents.trim().split(EOL); - t.same(noWebMessages, ['Loading app', 'Initialising indexes']); - - fs.readFile(`${__dirname}/categoryFilter-web.log`, 'utf8', (e, c) => { - const messages = c.trim().split(EOL); - t.same(messages, ['00:00:00 GET / 200', '00:00:00 GET / 500']); - t.end(); - }); - }); - }, 500); + const logEvents = recording.replay(); + t.equal(logEvents.length, 2); + t.equal(logEvents[0].data[0], 'This should get logged'); + t.equal(logEvents[1].data[0], 'This should be included by the appender anyway'); + t.end(); }); - batch.afterEach(cleanup); batch.end(); }); diff --git a/test/tap/configureNoLevels-test.js b/test/tap/configureNoLevels-test.js deleted file mode 100644 index 0c5988b..0000000 --- a/test/tap/configureNoLevels-test.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -// This test shows unexpected behaviour for log4js.configure() in log4js-node@0.4.3 and earlier: -// 1) log4js.configure(), log4js.configure(null), -// log4js.configure({}), log4js.configure() -// all set all loggers levels to trace, even if they were previously set to something else. -// 2) log4js.configure({levels:{}}), log4js.configure({levels: {foo: -// bar}}) leaves previously set logger levels intact. -// -const test = require('tap').test; - -// setup the configurations we want to test -const configs = [ - undefined, - null, - {}, - { foo: 'bar' }, - { levels: null }, - { levels: {} }, - { levels: { foo: 'bar' } }, - { levels: { A: 'INFO' } } -]; - -test('log4js dodgy config', (batch) => { - const log4js = require('../../lib/log4js'); - const logger = log4js.getLogger('test-logger'); - const error = log4js.levels.ERROR; - logger.setLevel('ERROR'); - - configs.forEach((config) => { - batch.test(`config of ${config} should not change logger level`, (t) => { - log4js.configure(config); - t.equal(logger.level, error); - t.end(); - }); - }); - batch.end(); -}); diff --git a/test/tap/consoleAppender-test.js b/test/tap/consoleAppender-test.js index 6fe32cd..499f2d3 100644 --- a/test/tap/consoleAppender-test.js +++ b/test/tap/consoleAppender-test.js @@ -1,7 +1,6 @@ 'use strict'; const test = require('tap').test; -const layouts = require('../../lib/layouts'); const sandbox = require('sandboxed-module'); test('log4js console appender', (batch) => { @@ -12,17 +11,20 @@ test('log4js console appender', (batch) => { messages.push(msg); } }; - const appenderModule = sandbox.require( - '../../lib/appenders/console', + const log4js = sandbox.require( + '../../lib/log4js', { globals: { console: fakeConsole } } ); + log4js.configure({ + appenders: { console: { type: 'console', layout: { type: 'messagePassThrough' } } }, + categories: { default: { appenders: ['console'], level: 'DEBUG' } } + }); - const appender = appenderModule.appender(layouts.messagePassThroughLayout); - appender({ data: ['blah'] }); + log4js.getLogger().info('blah'); t.equal(messages[0], 'blah'); t.end(); diff --git a/test/tap/dateFileAppender-test.js b/test/tap/dateFileAppender-test.js index 768eb17..d19d44c 100644 --- a/test/tap/dateFileAppender-test.js +++ b/test/tap/dateFileAppender-test.js @@ -10,20 +10,25 @@ const EOL = require('os').EOL || '\n'; function removeFile(filename) { try { fs.unlinkSync(path.join(__dirname, filename)); - } catch (e) {} + } catch (e) { + // doesn't matter + } } test('../../lib/appenders/dateFile', (batch) => { batch.test('adding multiple dateFileAppenders', (t) => { const listenersCount = process.listeners('exit').length; - const dateFileAppender = require('../../lib/appenders/dateFile'); - let count = 5; - let logfile; - while (count--) { - logfile = path.join(__dirname, `datefa-default-test${count}.log`); - log4js.addAppender(dateFileAppender.appender(logfile)); - } + log4js.configure({ + appenders: { + date0: { type: 'dateFile', filename: 'datefa-default-test0.log' }, + date1: { type: 'dateFile', filename: 'datefa-default-test1.log' }, + date2: { type: 'dateFile', filename: 'datefa-default-test2.log' }, + date3: { type: 'dateFile', filename: 'datefa-default-test3.log' }, + date4: { type: 'dateFile', filename: 'datefa-default-test4.log' } + }, + categories: { default: { appenders: ['date0', 'date1', 'date2', 'date3', 'date4'], level: 'debug' } } + }); t.teardown(() => { removeFile('datefa-default-test0.log'); @@ -59,6 +64,10 @@ test('../../lib/appenders/dateFile', (batch) => { this.end = function () { openedFiles.shift(); }; + + this.write = function () { + return true; + }; } } } @@ -66,7 +75,7 @@ test('../../lib/appenders/dateFile', (batch) => { ); for (let i = 0; i < 5; i += 1) { - dateFileAppender.appender(`test${i}`); + dateFileAppender.configure({ filename: `test${i}` }, { basicLayout: function () {} }); } t.equal(openedFiles.length, 5); exitListener(); @@ -76,10 +85,12 @@ test('../../lib/appenders/dateFile', (batch) => { batch.test('with default settings', (t) => { const testFile = path.join(__dirname, 'date-appender-default.log'); - const appender = require('../../lib/appenders/dateFile').appender(testFile); + log4js.configure({ + appenders: { date: { type: 'dateFile', filename: testFile } }, + categories: { default: { appenders: ['date'], level: 'DEBUG' } } + }); + const logger = log4js.getLogger('default-settings'); - log4js.clearAppenders(); - log4js.addAppender(appender, 'default-settings'); logger.info('This should be in the file.'); t.teardown(() => { removeFile('date-appender-default.log'); }); @@ -97,9 +108,17 @@ test('../../lib/appenders/dateFile', (batch) => { }); batch.test('configure with dateFileAppender', (t) => { - // this config file defines one file appender (to ./date-file-test.log) - // and sets the log level for "tests" to WARN - log4js.configure('test/tap/with-dateFile.json'); + log4js.configure({ + appenders: { + date: { + type: 'dateFile', + filename: 'test/tap/date-file-test.log', + pattern: '-from-MM-dd', + layout: { type: 'messagePassThrough' } + } + }, + categories: { default: { appenders: ['date'], level: 'WARN' } } + }); const logger = log4js.getLogger('tests'); logger.info('this should not be written to the file'); logger.warn('this should be written to the file'); @@ -117,8 +136,8 @@ test('../../lib/appenders/dateFile', (batch) => { const format = require('date-format'); const options = { - appenders: [ - { + appenders: { + date: { category: 'tests', type: 'dateFile', filename: 'test/tap/date-file-test', @@ -128,16 +147,16 @@ test('../../lib/appenders/dateFile', (batch) => { type: 'messagePassThrough' } } - ] + }, + categories: { default: { appenders: ['date'], level: 'debug' } } }; - const thisTime = format.asString(options.appenders[0].pattern, new Date()); + const thisTime = format.asString(options.appenders.date.pattern, new Date()); fs.writeFileSync( path.join(__dirname, `date-file-test${thisTime}`), `this is existing data${EOL}`, 'utf8' ); - log4js.clearAppenders(); log4js.configure(options); const logger = log4js.getLogger('tests'); logger.warn('this should be written to the file with the appended date'); @@ -154,40 +173,5 @@ test('../../lib/appenders/dateFile', (batch) => { }, 100); }); - batch.test('configure with cwd option', (t) => { - let fileOpened; - - const appender = sandbox.require( - '../../lib/appenders/dateFile', - { - requires: { - streamroller: { - DateRollingFileStream: function (file) { - fileOpened = file; - return { - on: function () { - }, - end: function () { - } - }; - } - } - } - } - ); - - appender.configure( - { - filename: 'whatever.log', - maxLogSize: 10 - }, - { cwd: '/absolute/path/to' } - ); - - const expected = path.sep + path.join('absolute', 'path', 'to', 'whatever.log'); - t.equal(fileOpened, expected, 'should prepend options.cwd to config.filename'); - t.end(); - }); - batch.end(); }); diff --git a/test/tap/file-sighup-test.js b/test/tap/file-sighup-test.js index 5ed6afa..f863851 100644 --- a/test/tap/file-sighup-test.js +++ b/test/tap/file-sighup-test.js @@ -29,11 +29,15 @@ test('file appender SIGHUP', (t) => { this.end = function () { }; + + this.write = function () { + return true; + }; } } } } - ).appender('sighup-test-file'); + ).configure({ type: 'file', filename: 'sighup-test-file' }, { basicLayout: function () {} }); process.kill(process.pid, 'SIGHUP'); t.plan(2); diff --git a/test/tap/fileAppender-test.js b/test/tap/fileAppender-test.js index 95220ec..966f7e8 100644 --- a/test/tap/fileAppender-test.js +++ b/test/tap/fileAppender-test.js @@ -8,9 +8,7 @@ const log4js = require('../../lib/log4js'); const zlib = require('zlib'); const EOL = require('os').EOL || '\n'; -log4js.clearAppenders(); - -function remove(filename) { +function removeFile(filename) { try { fs.unlinkSync(filename); } catch (e) { @@ -21,16 +19,24 @@ function remove(filename) { test('log4js fileAppender', (batch) => { batch.test('adding multiple fileAppenders', (t) => { const initialCount = process.listeners('exit').length; - let count = 5; - let logfile; + log4js.configure({ + appenders: { + file0: { type: 'file', filename: 'fa-default-test0.log' }, + file1: { type: 'file', filename: 'fa-default-test1.log' }, + file2: { type: 'file', filename: 'fa-default-test2.log' }, + file3: { type: 'file', filename: 'fa-default-test3.log' }, + file4: { type: 'file', filename: 'fa-default-test4.log' }, + }, + categories: { default: { appenders: ['file0', 'file1', 'file2', 'file3', 'file4'], level: 'debug' } } + }); - while (count--) { - logfile = path.join(__dirname, `fa-default-test${count}.log`); - log4js.addAppender( - require('../../lib/appenders/file').appender(logfile), - 'default-settings' - ); - } + t.tearDown(() => { + removeFile('fa-default-test0.log'); + removeFile('fa-default-test1.log'); + removeFile('fa-default-test2.log'); + removeFile('fa-default-test3.log'); + removeFile('fa-default-test4.log'); + }); t.equal(initialCount + 1, process.listeners('exit').length, 'should not add more than one exit listener'); t.end(); @@ -62,6 +68,10 @@ test('log4js fileAppender', (batch) => { openedFiles.shift(); }; + this.write = function () { + return true; + }; + this.on = function () { }; } @@ -71,9 +81,9 @@ test('log4js fileAppender', (batch) => { ); for (let i = 0; i < 5; i += 1) { - fileAppender.appender(`test${i}`, null, 100); + fileAppender.configure({ filename: `test${i}` }, { basicLayout: function () {} }); } - t.ok(openedFiles); + t.equal(openedFiles.length, 5); exitListener(); t.equal(openedFiles.length, 0, 'should close all open files'); t.end(); @@ -82,13 +92,14 @@ test('log4js fileAppender', (batch) => { batch.test('with default fileAppender settings', (t) => { const testFile = path.join(__dirname, 'fa-default-test.log'); const logger = log4js.getLogger('default-settings'); - remove(testFile); + removeFile(testFile); - log4js.clearAppenders(); - log4js.addAppender( - require('../../lib/appenders/file').appender(testFile), - 'default-settings' - ); + t.tearDown(() => { removeFile(testFile); }); + + log4js.configure({ + appenders: { file: { type: 'file', filename: testFile } }, + categories: { default: { appenders: ['file'], level: 'debug' } } + }); logger.info('This should be in the file.'); @@ -104,86 +115,25 @@ test('log4js fileAppender', (batch) => { }, 100); }); - batch.test('fileAppender subcategories', (t) => { - log4js.clearAppenders(); - - function addAppender(cat) { - const testFile = path.join( - __dirname, - `fa-subcategories-test-${cat.join('-').replace(/\./g, '_')}.log` - ); - remove(testFile); - log4js.addAppender(require('../../lib/appenders/file').appender(testFile), cat); - return testFile; - } - - /* eslint-disable camelcase */ - const file_sub1 = addAppender(['sub1']); - const file_sub1_sub12$sub1_sub13 = addAppender(['sub1.sub12', 'sub1.sub13']); - const file_sub1_sub12 = addAppender(['sub1.sub12']); - const logger_sub1_sub12_sub123 = log4js.getLogger('sub1.sub12.sub123'); - const logger_sub1_sub13_sub133 = log4js.getLogger('sub1.sub13.sub133'); - const logger_sub1_sub14 = log4js.getLogger('sub1.sub14'); - const logger_sub2 = log4js.getLogger('sub2'); - - logger_sub1_sub12_sub123.info('sub1_sub12_sub123'); - logger_sub1_sub13_sub133.info('sub1_sub13_sub133'); - logger_sub1_sub14.info('sub1_sub14'); - logger_sub2.info('sub2'); - - setTimeout(() => { - t.test('file contents', (assert) => { - const fileContents = { - file_sub1: fs.readFileSync(file_sub1).toString(), - file_sub1_sub12$sub1_sub13: fs.readFileSync(file_sub1_sub12$sub1_sub13).toString(), - file_sub1_sub12: fs.readFileSync(file_sub1_sub12).toString() - }; - // everything but category 'sub2' - assert.match( - fileContents.file_sub1, - /^(\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] (sub1.sub12.sub123 - sub1_sub12_sub123|sub1.sub13.sub133 - sub1_sub13_sub133|sub1.sub14 - sub1_sub14)[\s\S]){3}$/ // eslint-disable-line - ); - assert.ok( - fileContents.file_sub1.match(/sub123/) && - fileContents.file_sub1.match(/sub133/) && - fileContents.file_sub1.match(/sub14/) - ); - assert.ok(!fileContents.file_sub1.match(/sub2/)); - - // only catgories starting with 'sub1.sub12' and 'sub1.sub13' - assert.match( - fileContents.file_sub1_sub12$sub1_sub13, - /^(\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] (sub1.sub12.sub123 - sub1_sub12_sub123|sub1.sub13.sub133 - sub1_sub13_sub133)[\s\S]){2}$/ // eslint-disable-line - ); - assert.ok( - fileContents.file_sub1_sub12$sub1_sub13.match(/sub123/) && - fileContents.file_sub1_sub12$sub1_sub13.match(/sub133/) - ); - assert.ok(!fileContents.file_sub1_sub12$sub1_sub13.match(/sub14|sub2/)); - - // only catgories starting with 'sub1.sub12' - assert.match( - fileContents.file_sub1_sub12, - /^(\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] (sub1.sub12.sub123 - sub1_sub12_sub123)[\s\S]){1}$/ // eslint-disable-line - ); - assert.ok(!fileContents.file_sub1_sub12.match(/sub14|sub2|sub13/)); - assert.end(); - }); - t.end(); - }, 3000); - }); - batch.test('with a max file size and no backups', (t) => { const testFile = path.join(__dirname, 'fa-maxFileSize-test.log'); const logger = log4js.getLogger('max-file-size'); - remove(testFile); - remove(`${testFile}.1`); + + t.tearDown(() => { + removeFile(testFile); + removeFile(`${testFile}.1`); + }); + removeFile(testFile); + removeFile(`${testFile}.1`); + // log file of 100 bytes maximum, no backups - log4js.clearAppenders(); - log4js.addAppender( - require('../../lib/appenders/file').appender(testFile, log4js.layouts.basicLayout, 100, 0), - 'max-file-size' - ); + log4js.configure({ + appenders: { + file: { type: 'file', filename: testFile, maxLogSize: 100, backups: 0 } + }, + categories: { default: { appenders: ['file'], level: 'debug' } } + }); + logger.info('This is the first log message.'); logger.info('This is an intermediate log message.'); logger.info('This is the second log message.'); @@ -206,16 +156,24 @@ test('log4js fileAppender', (batch) => { batch.test('with a max file size and 2 backups', (t) => { const testFile = path.join(__dirname, 'fa-maxFileSize-with-backups-test.log'); const logger = log4js.getLogger('max-file-size-backups'); - remove(testFile); - remove(`${testFile}.1`); - remove(`${testFile}.2`); + removeFile(testFile); + removeFile(`${testFile}.1`); + removeFile(`${testFile}.2`); + + t.tearDown(() => { + removeFile(testFile); + removeFile(`${testFile}.1`); + removeFile(`${testFile}.2`); + }); // log file of 50 bytes maximum, 2 backups - log4js.clearAppenders(); - log4js.addAppender( - require('../../lib/appenders/file').appender(testFile, log4js.layouts.basicLayout, 50, 2), - 'max-file-size-backups' - ); + log4js.configure({ + appenders: { + file: { type: 'file', filename: testFile, maxLogSize: 50, backups: 2 } + }, + categories: { default: { appenders: ['file'], level: 'debug' } } + }); + logger.info('This is the first log message.'); logger.info('This is the second log message.'); logger.info('This is the third log message.'); @@ -258,18 +216,23 @@ test('log4js fileAppender', (batch) => { batch.test('with a max file size and 2 compressed backups', (t) => { const testFile = path.join(__dirname, 'fa-maxFileSize-with-backups-compressed-test.log'); const logger = log4js.getLogger('max-file-size-backups'); - remove(testFile); - remove(`${testFile}.1.gz`); - remove(`${testFile}.2.gz`); + removeFile(testFile); + removeFile(`${testFile}.1.gz`); + removeFile(`${testFile}.2.gz`); + + t.tearDown(() => { + removeFile(testFile); + removeFile(`${testFile}.1.gz`); + removeFile(`${testFile}.2.gz`); + }); // log file of 50 bytes maximum, 2 backups - log4js.clearAppenders(); - log4js.addAppender( - require('../../lib/appenders/file').appender( - testFile, log4js.layouts.basicLayout, 50, 2, { compress: true } - ), - 'max-file-size-backups' - ); + log4js.configure({ + appenders: { + file: { type: 'file', filename: testFile, maxLogSize: 50, backups: 2, compress: true } + }, + categories: { default: { appenders: ['file'], level: 'debug' } } + }); logger.info('This is the first log message.'); logger.info('This is the second log message.'); logger.info('This is the third log message.'); @@ -309,24 +272,6 @@ test('log4js fileAppender', (batch) => { }, 1000); }); - batch.test('configure with fileAppender', (t) => { - // this config file defines one file appender (to ./tmp-tests.log) - // and sets the log level for "tests" to WARN - log4js.configure('./test/tap/log4js.json'); - const logger = log4js.getLogger('tests'); - logger.info('this should not be written to the file'); - logger.warn('this should be written to the file'); - - // wait for the file system to catch up - setTimeout(() => { - fs.readFile('tmp-tests.log', 'utf8', (err, contents) => { - t.include(contents, `this should be written to the file${EOL}`); - t.equal(contents.indexOf('this should not be written to the file'), -1); - t.end(); - }); - }, 100); - }); - batch.test('when underlying stream errors', (t) => { let consoleArgs; let errorHandler; @@ -351,13 +296,16 @@ test('log4js fileAppender', (batch) => { errorHandler = cb; } }; + this.write = function () { + return true; + }; } } } } ); - fileAppender.appender('test1.log', null, 100); + fileAppender.configure({ filename: 'test1.log', maxLogSize: 100 }, { basicLayout: function () {} }); errorHandler({ error: 'aargh' }); t.test('should log the error to console.error', (assert) => { diff --git a/test/tap/fileSyncAppender-test.js b/test/tap/fileSyncAppender-test.js index 4874862..fc5629a 100644 --- a/test/tap/fileSyncAppender-test.js +++ b/test/tap/fileSyncAppender-test.js @@ -6,8 +6,6 @@ const path = require('path'); const log4js = require('../../lib/log4js'); const EOL = require('os').EOL || '\n'; -log4js.clearAppenders(); - function remove(filename) { try { fs.unlinkSync(filename); @@ -22,11 +20,14 @@ test('log4js fileSyncAppender', (batch) => { const logger = log4js.getLogger('default-settings'); remove(testFile); - log4js.clearAppenders(); - log4js.addAppender( - require('../../lib/appenders/fileSync').appender(testFile), - 'default-settings' - ); + t.tearDown(() => { + remove(testFile); + }); + + log4js.configure({ + appenders: { sync: { type: 'fileSync', filename: testFile } }, + categories: { default: { appenders: ['sync'], level: 'debug' } } + }); logger.info('This should be in the file.'); @@ -43,21 +44,20 @@ test('log4js fileSyncAppender', (batch) => { batch.test('with a max file size and no backups', (t) => { const testFile = path.join(__dirname, '/fa-maxFileSize-sync-test.log'); const logger = log4js.getLogger('max-file-size'); + remove(testFile); remove(`${testFile}.1`); + + t.tearDown(() => { + remove(testFile); + remove(`${testFile}.1`); + }); + // log file of 100 bytes maximum, no backups - log4js.clearAppenders(); - log4js.addAppender( - require( - '../../lib/appenders/fileSync' - ).appender( - testFile, - log4js.layouts.basicLayout, - 100, - 0 - ), - 'max-file-size' - ); + log4js.configure({ + appenders: { sync: { type: 'fileSync', filename: testFile, maxLogSize: 100, backups: 0 } }, + categories: { default: { appenders: ['sync'], level: 'debug' } } + }); logger.info('This is the first log message.'); logger.info('This is an intermediate log message.'); logger.info('This is the second log message.'); @@ -89,17 +89,17 @@ test('log4js fileSyncAppender', (batch) => { remove(`${testFile}.1`); remove(`${testFile}.2`); + t.tearDown(() => { + remove(testFile); + remove(`${testFile}.1`); + remove(`${testFile}.2`); + }); + // log file of 50 bytes maximum, 2 backups - log4js.clearAppenders(); - log4js.addAppender( - require('../../lib/appenders/fileSync').appender( - testFile, - log4js.layouts.basicLayout, - 50, - 2 - ), - 'max-file-size-backups' - ); + log4js.configure({ + appenders: { sync: { type: 'fileSync', filename: testFile, maxLogSize: 50, backups: 2 } }, + categories: { default: { appenders: ['sync'], level: 'debug' } } + }); logger.info('This is the first log message.'); logger.info('This is the second log message.'); logger.info('This is the third log message.'); @@ -136,16 +136,16 @@ test('log4js fileSyncAppender', (batch) => { // this config defines one file appender (to ./tmp-sync-tests.log) // and sets the log level for "tests" to WARN log4js.configure({ - appenders: [ - { - category: 'tests', - type: 'file', - filename: 'tmp-sync-tests.log', - layout: { type: 'messagePassThrough' } - } - ], - - levels: { tests: 'WARN' } + appenders: { sync: { + type: 'fileSync', + filename: 'tmp-sync-tests.log', + layout: { type: 'messagePassThrough' } + } + }, + categories: { + default: { appenders: ['sync'], level: 'debug' }, + tests: { appenders: ['sync'], level: 'warn' } + } }); const logger = log4js.getLogger('tests'); logger.info('this should not be written to the file'); diff --git a/test/tap/gelfAppender-test.js b/test/tap/gelfAppender-test.js index fc822be..12402e5 100644 --- a/test/tap/gelfAppender-test.js +++ b/test/tap/gelfAppender-test.js @@ -2,7 +2,6 @@ const test = require('tap').test; const sandbox = require('sandboxed-module'); -const log4js = require('../../lib/log4js'); const realLayouts = require('../../lib/layouts'); const setupLogging = function (options, category, compressedLength) { @@ -11,8 +10,9 @@ const setupLogging = function (options, category, compressedLength) { socket: { packetLength: 0, closed: false, - close: function () { + close: function (cb) { this.closed = true; + if (cb) cb(); }, send: function (pkt, offset, pktLength, port, host) { fakeDgram.sent = true; @@ -62,12 +62,12 @@ const setupLogging = function (options, category, compressedLength) { messagePassThroughLayout: realLayouts.messagePassThroughLayout }; - const appender = sandbox.require('../../lib/appenders/gelf', { - singleOnly: true, + const log4js = sandbox.require('../../lib/log4js', { + // singleOnly: true, requires: { dgram: fakeDgram, zlib: fakeZlib, - '../layouts': fakeLayouts + './layouts': fakeLayouts }, globals: { process: { @@ -75,21 +75,29 @@ const setupLogging = function (options, category, compressedLength) { if (evt === 'exit') { exitHandler = handler; } - } + }, + env: {} }, console: fakeConsole } }); - log4js.clearAppenders(); - log4js.addAppender(appender.configure(options || {}), category || 'gelf-test'); + options = options || {}; + options.type = 'gelf'; + + log4js.configure({ + appenders: { gelf: options }, + categories: { default: { appenders: ['gelf'], level: 'debug' } } + }); + return { dgram: fakeDgram, compress: fakeZlib, exitHandler: exitHandler, console: fakeConsole, layouts: fakeLayouts, - logger: log4js.getLogger(category || 'gelf-test') + logger: log4js.getLogger(category || 'gelf-test'), + log4js: log4js }; }; @@ -163,6 +171,14 @@ test('log4js gelfAppender', (batch) => { t.end(); }); + batch.test('on shutdown should close open sockets', (t) => { + const setup = setupLogging(); + setup.log4js.shutdown(() => { + t.ok(setup.dgram.socket.closed); + t.end(); + }); + }); + batch.test('on zlib error should output to console.error', (t) => { const setup = setupLogging(); setup.compress.shouldError = true; diff --git a/test/tap/global-log-level-test.js b/test/tap/global-log-level-test.js deleted file mode 100644 index 14beb61..0000000 --- a/test/tap/global-log-level-test.js +++ /dev/null @@ -1,126 +0,0 @@ -'use strict'; - -const test = require('tap').test; - -test('log4js global loglevel', (batch) => { - batch.test('global loglevel', (t) => { - const log4js = require('../../lib/log4js'); - - t.test('set global loglevel on creation', (assert) => { - const log1 = log4js.getLogger('log1'); - let level = 'OFF'; - if (log1.level.toString() === level) { - level = 'TRACE'; - } - assert.notEqual(log1.level.toString(), level); - - log4js.setGlobalLogLevel(level); - assert.equal(log1.level.toString(), level); - - const log2 = log4js.getLogger('log2'); - assert.equal(log2.level.toString(), level); - assert.end(); - }); - - t.test('global change loglevel', (assert) => { - const log1 = log4js.getLogger('log1'); - const log2 = log4js.getLogger('log2'); - let level = 'OFF'; - if (log1.level.toString() === level) { - level = 'TRACE'; - } - assert.notEqual(log1.level.toString(), level); - - log4js.setGlobalLogLevel(level); - assert.equal(log1.level.toString(), level); - assert.equal(log2.level.toString(), level); - assert.end(); - }); - - t.test('override loglevel', (assert) => { - const log1 = log4js.getLogger('log1'); - const log2 = log4js.getLogger('log2'); - let level = 'OFF'; - if (log1.level.toString() === level) { - level = 'TRACE'; - } - assert.notEqual(log1.level.toString(), level); - - const oldLevel = log1.level.toString(); - assert.equal(log2.level.toString(), oldLevel); - - log2.setLevel(level); - assert.equal(log1.level.toString(), oldLevel); - assert.equal(log2.level.toString(), level); - assert.notEqual(oldLevel, level); - - log2.removeLevel(); - assert.equal(log1.level.toString(), oldLevel); - assert.equal(log2.level.toString(), oldLevel); - assert.end(); - }); - - t.test('preload loglevel', (assert) => { - const log1 = log4js.getLogger('log1'); - let level = 'OFF'; - if (log1.level.toString() === level) { - level = 'TRACE'; - } - assert.notEqual(log1.level.toString(), level); - - const oldLevel = log1.level.toString(); - log4js.getLogger('log2').setLevel(level); - - assert.equal(log1.level.toString(), oldLevel); - - // get again same logger but as different variable - const log2 = log4js.getLogger('log2'); - assert.equal(log2.level.toString(), level); - assert.notEqual(oldLevel, level); - - log2.removeLevel(); - assert.equal(log1.level.toString(), oldLevel); - assert.equal(log2.level.toString(), oldLevel); - assert.end(); - }); - - t.test('set level on all categories', (assert) => { - // Get 2 loggers - const log1 = log4js.getLogger('log1'); - const log2 = log4js.getLogger('log2'); - - // First a test with 2 categories with different levels - const config = { - levels: { - log1: 'ERROR', - log2: 'WARN' - } - }; - log4js.configure(config); - - // Check if the levels are set correctly - assert.equal('ERROR', log1.level.toString()); - assert.equal('WARN', log2.level.toString()); - - log1.removeLevel(); - log2.removeLevel(); - - // Almost identical test, but now we set - // level on all categories - const config2 = { - levels: { - '[all]': 'DEBUG' - } - }; - log4js.configure(config2); - - // Check if the loggers got the DEBUG level - assert.equal('DEBUG', log1.level.toString()); - assert.equal('DEBUG', log2.level.toString()); - assert.end(); - }); - t.end(); - }); - - batch.end(); -}); diff --git a/test/tap/hipchatAppender-test.js b/test/tap/hipchatAppender-test.js index 032bde7..2d58687 100644 --- a/test/tap/hipchatAppender-test.js +++ b/test/tap/hipchatAppender-test.js @@ -1,7 +1,6 @@ 'use strict'; const test = require('tap').test; -const log4js = require('../../lib/log4js'); const sandbox = require('sandboxed-module'); function setupLogging(category, options) { @@ -50,13 +49,19 @@ function setupLogging(category, options) { } }; - const hipchatModule = sandbox.require('../../lib/appenders/hipchat', { + const log4js = sandbox.require('../../lib/log4js', { requires: { 'hipchat-notifier': fakeHipchatNotifier } }); - log4js.clearAppenders(); - log4js.addAppender(hipchatModule.configure(options), category); + + options = options || {}; + options.type = 'hipchat'; + + log4js.configure({ + appenders: { hipchat: options }, + categories: { default: { appenders: ['hipchat'], level: 'debug' } } + }); return { logger: log4js.getLogger(category), @@ -112,7 +117,7 @@ test('HipChat appender', (batch) => { batch.test('when basicLayout is provided', (t) => { const topic = setupLogging('myLogger', { type: 'hipchat', - layout: log4js.layouts.basicLayout + layout: { type: 'basic' } }); topic.logger.debug('Log event #3'); diff --git a/test/tap/log-abspath-test.js b/test/tap/log-abspath-test.js deleted file mode 100644 index aa274ac..0000000 --- a/test/tap/log-abspath-test.js +++ /dev/null @@ -1,88 +0,0 @@ -'use strict'; - -const test = require('tap').test; -const path = require('path'); -const sandbox = require('sandboxed-module'); - -test('log4js-abspath', (batch) => { - batch.test('options', (t) => { - let appenderOptions; - - const log4js = sandbox.require( - '../../lib/log4js', - { - singleOnly: true, - requires: { - './appenders/fake': { - name: 'fake', - appender: function () { - }, - configure: function (configuration, options) { - appenderOptions = options; - return function () { - }; - } - } - } - } - ); - - const config = { - appenders: [ - { - type: 'fake', - filename: 'cheesy-wotsits.log' - } - ] - }; - - log4js.configure(config, { - cwd: '/absolute/path/to' - }); - t.test('should be passed to appenders during configuration', (assert) => { - assert.equal(appenderOptions.cwd, '/absolute/path/to'); - assert.end(); - }); - t.end(); - }); - - batch.test('file appender', (t) => { - let fileOpened; - - const fileAppender = sandbox.require( - '../../lib/appenders/file', - { - requires: { - streamroller: { - RollingFileStream: function (file) { - fileOpened = file; - return { - on: function () { - }, - end: function () { - } - }; - } - } - } - } - ); - - fileAppender.configure( - { - filename: 'whatever.log', - maxLogSize: 10 - }, - { cwd: '/absolute/path/to' } - ); - - t.test('should prepend options.cwd to config.filename', (assert) => { - const expected = path.sep + path.join('absolute', 'path', 'to', 'whatever.log'); - assert.equal(fileOpened, expected); - assert.end(); - }); - t.end(); - }); - - batch.end(); -}); diff --git a/test/tap/logger-test.js b/test/tap/logger-test.js index 6edf229..7873c07 100644 --- a/test/tap/logger-test.js +++ b/test/tap/logger-test.js @@ -5,31 +5,46 @@ const levels = require('../../lib/levels'); const loggerModule = require('../../lib/logger'); const Logger = loggerModule.Logger; +const testDispatcher = { + events: [], + dispatch: function (evt) { + this.events.push(evt); + } +}; +const dispatch = testDispatcher.dispatch.bind(testDispatcher); test('../../lib/logger', (batch) => { batch.test('constructor with no parameters', (t) => { - const logger = new Logger(); + t.throws( + () => new Logger(), + new Error('No dispatch function provided.') + ); + t.end(); + }); + + batch.test('constructor with only dispatch', (t) => { + const logger = new Logger(dispatch); t.equal(logger.category, Logger.DEFAULT_CATEGORY, 'should use default category'); t.equal(logger.level, levels.TRACE, 'should use TRACE log level'); t.end(); }); batch.test('constructor with category', (t) => { - const logger = new Logger('cheese'); + const logger = new Logger(dispatch, 'cheese'); t.equal(logger.category, 'cheese', 'should use category'); t.equal(logger.level, levels.TRACE, 'should use TRACE log level'); t.end(); }); batch.test('constructor with category and level', (t) => { - const logger = new Logger('cheese', 'debug'); + const logger = new Logger(dispatch, 'cheese', 'debug'); t.equal(logger.category, 'cheese', 'should use category'); t.equal(logger.level, levels.DEBUG, 'should use level'); t.end(); }); batch.test('isLevelEnabled', (t) => { - const logger = new Logger('cheese', 'info'); + const logger = new Logger(dispatch, 'cheese', 'info'); const functions = [ 'isTraceEnabled', 'isDebugEnabled', 'isInfoEnabled', 'isWarnEnabled', 'isErrorEnabled', 'isFatalEnabled' @@ -52,28 +67,17 @@ test('../../lib/logger', (batch) => { t.end(); }); - batch.test('should emit log events', (t) => { - const events = []; - const logger = new Logger(); - logger.addListener('log', (logEvent) => { - events.push(logEvent); - }); + batch.test('should send log events to dispatch function', (t) => { + const logger = new Logger(dispatch); logger.debug('Event 1'); - loggerModule.disableAllLogWrites(); logger.debug('Event 2'); - loggerModule.enableAllLogWrites(); logger.debug('Event 3'); + const events = testDispatcher.events; - t.test('when log writes are enabled', (assert) => { - assert.equal(events[0].data[0], 'Event 1'); - assert.end(); - }); - - t.test('but not when log writes are disabled', (assert) => { - assert.equal(events.length, 2); - assert.equal(events[1].data[0], 'Event 3'); - assert.end(); - }); + t.equal(events.length, 3); + t.equal(events[0].data[0], 'Event 1'); + t.equal(events[1].data[0], 'Event 2'); + t.equal(events[2].data[0], 'Event 3'); t.end(); }); diff --git a/test/tap/logglyAppender-test.js b/test/tap/logglyAppender-test.js index 8fb25ad..400a4b8 100644 --- a/test/tap/logglyAppender-test.js +++ b/test/tap/logglyAppender-test.js @@ -1,8 +1,8 @@ 'use strict'; const test = require('tap').test; -const log4js = require('../../lib/log4js'); const sandbox = require('sandboxed-module'); +const layouts = require('../../lib/layouts'); function setupLogging(category, options) { const msgs = []; @@ -26,10 +26,10 @@ function setupLogging(category, options) { layout: function (type, config) { this.type = type; this.config = config; - return log4js.layouts.messagePassThroughLayout; + return layouts.messagePassThroughLayout; }, - basicLayout: log4js.layouts.basicLayout, - messagePassThroughLayout: log4js.layouts.messagePassThroughLayout + basicLayout: layouts.basicLayout, + messagePassThroughLayout: layouts.messagePassThroughLayout }; const fakeConsole = { @@ -39,22 +39,26 @@ function setupLogging(category, options) { } }; - const logglyModule = sandbox.require('../../lib/appenders/loggly', { + const log4js = sandbox.require('../../lib/log4js', { requires: { loggly: fakeLoggly, - '../layouts': fakeLayouts + './layouts': fakeLayouts }, globals: { console: fakeConsole } }); - log4js.addAppender( - logglyModule.configure(options), - logglyModule.shutdown, - category); + options = options || {}; + options.type = 'loggly'; + + log4js.configure({ + appenders: { loggly: options }, + categories: { default: { appenders: ['loggly'], level: 'trace' } } + }); return { + log4js: log4js, logger: log4js.getLogger(category), loggly: fakeLoggly, layouts: fakeLayouts, @@ -63,8 +67,6 @@ function setupLogging(category, options) { }; } -log4js.clearAppenders(); - function setupTaggedLogging() { return setupLogging('loggly', { token: 'your-really-long-input-token', @@ -105,9 +107,9 @@ test('log4js logglyAppender', (batch) => { tags: ['tag1', 'tag2'] }); - log4js.shutdown(() => { t.end(); }); + setup.log4js.shutdown(() => { t.end(); }); - // shutdown will until after the last message has been sent to loggly + // shutdown will wait until after the last message has been sent to loggly setup.results[0].cb(); }); diff --git a/test/tap/with-categoryFilter.json b/test/tap/with-categoryFilter.json deleted file mode 100644 index f1efa4a..0000000 --- a/test/tap/with-categoryFilter.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "appenders": [ - { - "type": "categoryFilter", - "exclude": "web", - "appender": { - "type": "file", - "filename": "test/tap/categoryFilter-noweb.log", - "layout": { - "type": "messagePassThrough" - } - } - }, - { - "category": "web", - "type": "file", - "filename": "test/tap/categoryFilter-web.log", - "layout": { - "type": "messagePassThrough" - } - } - ] -} diff --git a/test/tap/with-dateFile.json b/test/tap/with-dateFile.json deleted file mode 100644 index 4691278..0000000 --- a/test/tap/with-dateFile.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "appenders": [ - { - "category": "tests", - "type": "dateFile", - "filename": "test/tap/date-file-test.log", - "pattern": "-from-MM-dd", - "layout": { - "type": "messagePassThrough" - } - } - ], - - "levels": { - "tests": "WARN" - } -}