/* eslint max-classes-per-file: ["error", 3] */ const { test } = require('tap'); const path = require('path'); const fs = require('fs'); const EOL = require('os').EOL || '\n'; const format = require('date-format'); const sandbox = require('@log4js-node/sandboxed-module'); const log4js = require('../../lib/log4js'); const osDelay = process.platform === 'win32' ? 400 : 200; function removeFile(filename) { try { fs.unlinkSync(path.join(__dirname, filename)); } catch (e) { // doesn't matter } } test('../../lib/appenders/dateFile', (batch) => { batch.test('with default settings', (t) => { const testFile = path.join(__dirname, 'date-appender-default.log'); log4js.configure({ appenders: { date: { type: 'dateFile', filename: testFile } }, categories: { default: { appenders: ['date'], level: 'DEBUG' } }, }); const logger = log4js.getLogger('default-settings'); logger.info('This should be in the file.'); t.teardown(() => { removeFile('date-appender-default.log'); }); setTimeout(() => { fs.readFile(testFile, 'utf8', (err, contents) => { t.match(contents, 'This should be in the file'); t.match( contents, /\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] default-settings - / ); t.end(); }); }, osDelay); }); batch.test('configure with dateFileAppender', (t) => { log4js.configure({ appenders: { date: { type: 'dateFile', filename: 'test/tap/date-file-test.log', pattern: '-yyyy-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'); log4js.shutdown(() => { fs.readFile( path.join(__dirname, 'date-file-test.log'), 'utf8', (err, contents) => { t.match(contents, `this should be written to the file${EOL}`); t.equal( contents.indexOf('this should not be written to the file'), -1 ); t.end(); } ); }); t.teardown(() => { removeFile('date-file-test.log'); }); }); batch.test('configure with options.alwaysIncludePattern', (t) => { const options = { appenders: { date: { category: 'tests', type: 'dateFile', filename: 'test/tap/date-file-test', pattern: 'yyyy-MM-dd.log', alwaysIncludePattern: true, layout: { type: 'messagePassThrough', }, }, }, categories: { default: { appenders: ['date'], level: 'debug' } }, }; const thisTime = format.asString( options.appenders.date.pattern, new Date() ); const testFile = `date-file-test.${thisTime}`; const existingFile = path.join(__dirname, testFile); fs.writeFileSync(existingFile, `this is existing data${EOL}`, 'utf8'); log4js.configure(options); const logger = log4js.getLogger('tests'); logger.warn('this should be written to the file with the appended date'); t.teardown(() => { removeFile(testFile); }); // wait for filesystem to catch up log4js.shutdown(() => { fs.readFile(existingFile, 'utf8', (err, contents) => { t.match( contents, 'this is existing data', 'should not overwrite the file on open (issue #132)' ); t.match( contents, 'this should be written to the file with the appended date' ); t.end(); }); }); }); batch.test('should flush logs on shutdown', (t) => { const testFile = path.join(__dirname, 'date-appender-flush.log'); log4js.configure({ appenders: { test: { type: 'dateFile', filename: testFile } }, categories: { default: { appenders: ['test'], level: 'trace' } }, }); const logger = log4js.getLogger('default-settings'); logger.info('1'); logger.info('2'); logger.info('3'); t.teardown(() => { removeFile('date-appender-flush.log'); }); log4js.shutdown(() => { fs.readFile(testFile, 'utf8', (err, fileContents) => { // 3 lines of output, plus the trailing newline. t.equal(fileContents.split(EOL).length, 4); t.match( fileContents, /\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] default-settings - / ); t.end(); }); }); }); batch.test('should map maxLogSize to maxSize', (t) => { const fakeStreamroller = {}; class DateRollingFileStream { constructor(filename, pattern, options) { fakeStreamroller.filename = filename; fakeStreamroller.pattern = pattern; fakeStreamroller.options = options; } on() {} // eslint-disable-line class-methods-use-this } fakeStreamroller.DateRollingFileStream = DateRollingFileStream; const dateFileAppenderModule = sandbox.require( '../../lib/appenders/dateFile', { requires: { streamroller: fakeStreamroller }, } ); dateFileAppenderModule.configure( { filename: 'cheese.log', pattern: 'yyyy', maxLogSize: 100, }, { basicLayout: () => {} } ); t.equal(fakeStreamroller.options.maxSize, 100); t.end(); }); batch.test('handling of writer.writable', (t) => { const output = []; let writable = true; const DateRollingFileStream = class { write(loggingEvent) { output.push(loggingEvent); this.written = true; return true; } // eslint-disable-next-line class-methods-use-this on() {} // eslint-disable-next-line class-methods-use-this get writable() { return writable; } }; const dateFileAppender = sandbox.require('../../lib/appenders/dateFile', { requires: { streamroller: { DateRollingFileStream, }, }, }); const appender = dateFileAppender.configure( { filename: 'test1.log', maxLogSize: 100 }, { basicLayout(loggingEvent) { return loggingEvent.data; }, } ); t.test('should log when writer.writable=true', (assert) => { writable = true; appender({ data: 'something to log' }); assert.ok(output.length, 1); assert.match(output[output.length - 1], 'something to log'); assert.end(); }); t.test('should not log when writer.writable=false', (assert) => { writable = false; appender({ data: 'this should not be logged' }); assert.ok(output.length, 1); assert.notMatch(output[output.length - 1], 'this should not be logged'); assert.end(); }); t.end(); }); batch.test('when underlying stream errors', (t) => { let consoleArgs; let errorHandler; const DateRollingFileStream = class { end() { this.ended = true; } on(evt, cb) { if (evt === 'error') { this.errored = true; errorHandler = cb; } } write() { this.written = true; return true; } }; const dateFileAppender = sandbox.require('../../lib/appenders/dateFile', { globals: { console: { error(...args) { consoleArgs = args; }, }, }, requires: { streamroller: { DateRollingFileStream, }, }, }); dateFileAppender.configure( { filename: 'test1.log', maxLogSize: 100 }, { basicLayout() {} } ); errorHandler({ error: 'aargh' }); t.test('should log the error to console.error', (assert) => { assert.ok(consoleArgs); assert.equal( consoleArgs[0], 'log4js.dateFileAppender - Writing to file %s, error happened ' ); assert.equal(consoleArgs[1], 'test1.log'); assert.equal(consoleArgs[2].error, 'aargh'); assert.end(); }); t.end(); }); batch.end(); });