refactor: fixed a few more appenders

This commit is contained in:
Gareth Jones 2017-02-07 08:53:51 +11:00
parent 5283782ba0
commit 1d50b82a96
27 changed files with 443 additions and 852 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -125,6 +125,5 @@ function wrapErrorsWithInspect(items) {
});
}
module.exports.appender = logFacesAppender;
module.exports.configure = configure;
module.exports.setContext = setContext;

View File

@ -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;

View File

@ -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) });
});

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
});

View File

@ -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(<some object with no levels prop>)
// 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();
});

View File

@ -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();

View File

@ -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();
});

View File

@ -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);

View File

@ -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) => {

View File

@ -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');

View File

@ -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;

View File

@ -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();
});

View File

@ -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');

View File

@ -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();
});

View File

@ -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();
});

View File

@ -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();
});

View File

@ -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"
}
}
]
}

View File

@ -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"
}
}