UNPKG

@villedemontreal/logger

Version:
564 lines 28.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.timeout = timeout; const general_utils_1 = require("@villedemontreal/general-utils"); const chai_1 = require("chai"); const fs = require("fs-extra"); const _ = require("lodash"); const configs_1 = require("./config/configs"); const constants_1 = require("./config/constants"); const lazyLogger_1 = require("./lazyLogger"); const logger_1 = require("./logger"); const TESTING_CID = 'test-cid'; /** * The "--no-timeouts" arg doesn't work to disable * the Mocha timeouts (while debugging) if a timeout * is specified in the code itself. Using this to set the * timeouts does. */ function timeout(mocha, milliSec) { mocha.timeout(process.argv.includes('--no-timeouts') ? 0 : milliSec); } // ========================================== // Logger tests // ========================================== describe('Logger tests', () => { describe('General tests', () => { let loggerConfig; let logger; const stdoutWriteBackup = process.stdout.write; let output; before(async () => { // ========================================== // Tweaks the configs for this tests file. // ========================================== loggerConfig = new configs_1.LoggerConfigs(() => TESTING_CID); loggerConfig.setLogHumanReadableinConsole(false); loggerConfig.setLogSource(true); loggerConfig.setLogLevel(logger_1.LogLevel.INFO); // ========================================== // Creates the logger // ========================================== (0, logger_1.initLogger)(loggerConfig, 'default', true); logger = new logger_1.Logger('test'); }); let expectTwoCalls = false; let keepSecondCallOnly = false; let firstCallDone = false; function restartCustomWriter() { output = ''; expectTwoCalls = false; keepSecondCallOnly = false; firstCallDone = false; // A stadard "function" is required here, because // of the use of "arguments". // tslint:disable-next-line:only-arrow-functions process.stdout.write = function (...args) { if (!expectTwoCalls) { output += args[0]; process.stdout.write = stdoutWriteBackup; return; } if (!firstCallDone) { if (!keepSecondCallOnly) { output += args[0]; } firstCallDone = true; } else { output += args[0]; process.stdout.write = stdoutWriteBackup; } }; chai_1.assert.isTrue(general_utils_1.utils.isBlank(output)); } beforeEach(async () => { restartCustomWriter(); }); it('string message', async () => { logger.error('allo'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.name, 'test'); chai_1.assert.strictEqual(jsonObj.msg, 'allo'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('string message and extra text message', async () => { logger.error('allo', 'salut'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.msg, 'allo - salut'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('custom object message', async () => { logger.error({ key1: { key3: 'val3', key4: 'val4', }, key2: 'val2', msg: 'blabla', }); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.key2, 'val2'); chai_1.assert.strictEqual(jsonObj.msg, 'blabla'); chai_1.assert.deepEqual(jsonObj.key1, { key3: 'val3', key4: 'val4', }); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('custom object message and extra text message', async () => { logger.error({ key1: { key3: 'val3', key4: 'val4', }, key2: 'val2', msg: 'blabla', }, 'my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.key2, 'val2'); chai_1.assert.strictEqual(jsonObj.msg, 'blabla - my text message'); chai_1.assert.deepEqual(jsonObj.key1, { key3: 'val3', key4: 'val4', }); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('regular Error object and extra text message', async () => { logger.error(new Error('my error message'), 'my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'my error message - my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(jsonObj.stack)); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(jsonObj.name)); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('null Error object and extra text message', async () => { logger.error(null, 'my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(jsonObj.name)); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('undefined Error object and extra text message', async () => { logger.error(undefined, 'my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'my text message'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(jsonObj.name)); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); }); it('array message', async () => { // ========================================== // Two calls to "process.stdout.write" will // be made because an error for the invalid // array message will be logged! // ========================================== expectTwoCalls = true; keepSecondCallOnly = true; logger.error([ 'toto', { key1: 'val1', key2: 'val2', }, ]); const jsonObj = JSON.parse(output); chai_1.assert.deepEqual(jsonObj._arrayMsg, [ 'toto', { key1: 'val1', key2: 'val2', }, ]); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); }); it('array message and extra text message', async () => { // ========================================== // Two calls to "process.stdout.write" will // be made because an error for the invalid // array message will be logged! // ========================================== expectTwoCalls = true; keepSecondCallOnly = true; logger.error([ 'toto', { key1: 'val1', key2: 'val2', }, ], 'my text message'); const jsonObj = JSON.parse(output); chai_1.assert.deepEqual(jsonObj._arrayMsg, [ 'toto', { key1: 'val1', key2: 'val2', }, ]); chai_1.assert.strictEqual(jsonObj.msg, 'my text message'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); }); it('log level - debug', async () => { logger.debug('allo'); chai_1.assert.strictEqual(output, ''); }); it('log level - info', async () => { logger.info('allo'); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.INFO)); }); it('log level - warning', async () => { logger.warning('allo'); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.WARNING)); }); it('log level - error', async () => { logger.error('allo'); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.ERROR)); }); it('log level - custom valid', async () => { logger.log(logger_1.LogLevel.INFO, 'allo'); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.INFO)); }); it('log level - custom invalid', async () => { // ========================================== // Two calls to "process.stdout.write" will // be made because an error for the invalid // level will be logged! // ========================================== expectTwoCalls = true; keepSecondCallOnly = true; logger.log('nope', 'allo'); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.ERROR)); chai_1.assert.strictEqual(jsonObj.msg, 'allo'); }); it('newline after each log - string', async () => { expectTwoCalls = true; logger.error('111'); logger.error('222'); const pos = output.indexOf('\n'); chai_1.assert.isTrue(pos > -1); chai_1.assert.strictEqual(output.charAt(pos + 1), '{'); }); it('newline after each log - complexe objects', async () => { expectTwoCalls = true; logger.error({ key1: 'val1', key2: 'val2', }); logger.error({ key1: 'val1', key2: 'val2', }); const pos = output.indexOf('\n'); chai_1.assert.isTrue(pos > -1); chai_1.assert.strictEqual(output.charAt(pos + 1), '{'); }); it('date message', async () => { const someDate = new Date(); logger.error(someDate); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.msg, someDate.toString()); chai_1.assert.isTrue(_.isDate(someDate)); }); // ========================================== // Error controller log messages // ========================================== describe('Error controller log messages', () => { it('app and version properties', async () => { const packagePath = `${constants_1.constants.libRoot}/../../package.json`; const packageJson = require(packagePath); const appName = packageJson.name; const appVersion = packageJson.version; logger.error('allo'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.APP_NAME], appName); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.APP_VERSION], appVersion); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.CORRELATION_ID], TESTING_CID); }); }); // ========================================== // LazyLogger tests // ========================================== describe('LazyLogger tests', () => { let lazyLogger; beforeEach(async () => { lazyLogger = new lazyLogger_1.LazyLogger('titi', (name) => { const logger2 = new logger_1.Logger('titi'); return logger2; }); }); it('debug', async () => { lazyLogger.debug('allo'); chai_1.assert.isTrue(general_utils_1.utils.isBlank(output)); }); it('info', async () => { lazyLogger.info('allo'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.INFO)); chai_1.assert.strictEqual(jsonObj.name, 'titi'); chai_1.assert.strictEqual(jsonObj.msg, 'allo'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.CORRELATION_ID], TESTING_CID); }); it('warning', async () => { lazyLogger.warning('allo'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.WARNING)); chai_1.assert.strictEqual(jsonObj.name, 'titi'); chai_1.assert.strictEqual(jsonObj.msg, 'allo'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.CORRELATION_ID], TESTING_CID); }); it('error', async () => { lazyLogger.error('allo'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.ERROR)); chai_1.assert.strictEqual(jsonObj.name, 'titi'); chai_1.assert.strictEqual(jsonObj.msg, 'allo'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.CORRELATION_ID], TESTING_CID); }); it('log', async () => { lazyLogger.log(logger_1.LogLevel.INFO, 'allo'); chai_1.assert.isTrue(!general_utils_1.utils.isBlank(output)); const jsonObj = JSON.parse(output); chai_1.assert.isTrue(_.isObject(jsonObj)); chai_1.assert.strictEqual(jsonObj.level, (0, logger_1.convertLogLevelToPinoNumberLevel)(logger_1.LogLevel.INFO)); chai_1.assert.strictEqual(jsonObj.name, 'titi'); chai_1.assert.strictEqual(jsonObj.msg, 'allo'); chai_1.assert.isNotNull(jsonObj.src); chai_1.assert.isNotNull(jsonObj.src.file); chai_1.assert.isNotNull(jsonObj.src.line); chai_1.assert.strictEqual(jsonObj.logType, constants_1.constants.logging.logType.MONTREAL); chai_1.assert.strictEqual(jsonObj.logTypeVersion, '2'); chai_1.assert.strictEqual(jsonObj[constants_1.constants.logging.properties.CORRELATION_ID], TESTING_CID); }); it('logger creator is required', async () => { try { const lazyLogger2 = new lazyLogger_1.LazyLogger('titi', null); chai_1.assert.fail(); chai_1.assert.isNotOk(lazyLogger2); } catch (err) { /* ok */ } try { const lazyLogger3 = new lazyLogger_1.LazyLogger('titi', undefined); chai_1.assert.fail(); chai_1.assert.isNotOk(lazyLogger3); } catch (err) { /* ok */ } }); }); // ========================================== // Global log level // ========================================== describe('Global log level', () => { let childLogger; before(() => { childLogger = (0, logger_1.createLogger)('testing child logger'); }); afterEach(() => { // Reset the default logging (0, logger_1.setGlobalLogLevel)(loggerConfig.getLogLevel()); }); it('log debug message when global log level set to DEBUG', () => { (0, logger_1.setGlobalLogLevel)(logger_1.LogLevel.DEBUG); logger.debug('this is the debug message'); let jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the debug message'); restartCustomWriter(); childLogger.debug('this is the child logger debug message'); jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the child logger debug message'); restartCustomWriter(); logger.info('this is the info message'); jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the info message'); restartCustomWriter(); childLogger.info('this is the child logger info message'); jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the child logger info message'); }); it('filter debug message when global log level set to WARNING', () => { chai_1.assert.isTrue(general_utils_1.utils.isBlank(output)); (0, logger_1.setGlobalLogLevel)(logger_1.LogLevel.WARNING); logger.debug('this is my filtered the debug message'); chai_1.assert.isTrue(general_utils_1.utils.isBlank(output), 'Did not filter debug message as expected.'); childLogger.debug('this is my filtered the debug message'); chai_1.assert.isTrue(general_utils_1.utils.isBlank(output), 'Did not filter debug message as expected.'); logger.info('this is my filtered the info message'); chai_1.assert.isTrue(general_utils_1.utils.isBlank(output), 'Did not filter info message as expected.'); childLogger.info('this is my filtered the info message'); chai_1.assert.isTrue(general_utils_1.utils.isBlank(output), 'Did not filter info message as expected.'); logger.warning('this is the warning message'); let jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the warning message'); restartCustomWriter(); childLogger.warning('this is the child logger warning message'); jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the child logger warning message'); }); it('apply current log level to new created logger - INFO', () => { chai_1.assert.isTrue(general_utils_1.utils.isBlank(output)); (0, logger_1.setGlobalLogLevel)(logger_1.LogLevel.WARNING); const newLogger = (0, logger_1.createLogger)('testing logger'); newLogger.info('this is the info message for newly created logger'); chai_1.assert.isTrue(general_utils_1.utils.isBlank(output), 'Did not filter info message as expected.'); newLogger.warning('this is the warning message'); const jsonObj = JSON.parse(output); chai_1.assert.strictEqual(jsonObj.msg, 'this is the warning message'); }); }); }); describe('Log to file', function () { timeout(this, 30000); let loggerConfig; let logger; let testingLogDir; let testingLogFile; before(async () => { testingLogDir = `${constants_1.constants.libRoot}/output/testingLogs`; if (general_utils_1.utils.isDir(testingLogDir)) { await general_utils_1.utils.clearDir(testingLogDir); } else { fs.mkdirsSync(testingLogDir); } testingLogFile = `${testingLogDir}/application.log`; }); after(async () => { await general_utils_1.utils.deleteDir(testingLogDir); }); beforeEach(async () => { if (fs.existsSync(testingLogFile)) { fs.unlinkSync(testingLogFile); } chai_1.assert.isFalse(fs.existsSync(testingLogFile)); }); /** * Logging with Pino is asynchronous. * We need to make sure the log is written to file by waiting. * @see https://github.com/pinojs/pino/blob/master/docs/asynchronous.md */ async function logAndWait(msg) { logger.error(msg); chai_1.assert.isFunction(logger[`pino`][`flush`], `The "flush method should exist on a Pino logger"`); logger[`pino`][`flush`](); const max = 5000; let elapsed = 0; const sleep = 200; while (!fs.existsSync(testingLogFile) && elapsed < max) { await general_utils_1.utils.sleep(sleep); elapsed += sleep; } } it('No log file - default', async () => { loggerConfig = new configs_1.LoggerConfigs(() => TESTING_CID); loggerConfig.setLogHumanReadableinConsole(false); loggerConfig.setLogSource(true); loggerConfig.setLogLevel(logger_1.LogLevel.DEBUG); loggerConfig.setLogDirectory(testingLogDir); (0, logger_1.initLogger)(loggerConfig, 'default', true); logger = new logger_1.Logger('test'); await logAndWait('allo'); chai_1.assert.isFalse(fs.existsSync(testingLogFile)); }); it('No log file - explicit', async () => { loggerConfig = new configs_1.LoggerConfigs(() => TESTING_CID); loggerConfig.setLogHumanReadableinConsole(false); loggerConfig.setLogSource(true); loggerConfig.setLogLevel(logger_1.LogLevel.DEBUG); loggerConfig.setLogDirectory(testingLogDir); loggerConfig.setSlowerLogToFileToo(false); (0, logger_1.initLogger)(loggerConfig, 'default', true); logger = new logger_1.Logger('test'); await logAndWait('allo'); chai_1.assert.isFalse(fs.existsSync(testingLogFile)); }); it('Log file', async () => { loggerConfig = new configs_1.LoggerConfigs(() => TESTING_CID); loggerConfig.setLogHumanReadableinConsole(false); loggerConfig.setLogSource(true); loggerConfig.setLogLevel(logger_1.LogLevel.DEBUG); loggerConfig.setLogDirectory(testingLogDir); loggerConfig.setSlowerLogToFileToo(true); (0, logger_1.initLogger)(loggerConfig, 'default', true); logger = new logger_1.Logger('test'); await logAndWait('allo'); chai_1.assert.isTrue(fs.existsSync(testingLogFile)); const content = fs.readFileSync(testingLogFile, 'utf-8'); chai_1.assert.isOk(content); chai_1.assert.isTrue(content.indexOf(`"msg":"allo"`) > -1); }); }); }); //# sourceMappingURL=logger.test.js.map