UNPKG

perfect-logger

Version:

A customizable logger that can be used with NodeJS application for terminal logging purposes

223 lines (195 loc) 8.9 kB
const fs = require('fs'); const child_process = require('child_process'); const os = require('os'); const process = require('process'); const definitions = require('./definitions'); let startTime = null; let logNumber = 0; let logFileNames = []; let moduleName = null; let customBannerHeaders = []; let timezone = definitions.DEFAULT_TIMEZONE; let logLevel = definitions.LOG_LEVEL_DISABLED; let developmentMode = false; let logSwitchSize = -1; let logDirectory = '.'; let callbackLogSwitch = null; //********************************************************************************************************************* function getLockDataFromFile(module = null) { let fileLockData = {}; try { fileLockData = JSON.parse(fs.readFileSync(definitions.LOCKFILE_NAME, 'utf-8')); } catch (e) {} if (module === null) return fileLockData; return Object.assign({ startTime: 'UNKNOWN_START_TIME', pid: 'UNKNOWN_PID' }, fileLockData[moduleName]); } //********************************************************************************************************************* function updateLockDataFile() { let lockData = getLockDataFromFile(); lockData.lastUpdatedBy = moduleName; lockData[moduleName] = { startTime: Date.now(), pid: process.pid }; fs.writeFileSync(definitions.LOCKFILE_NAME, JSON.stringify(lockData, null, 4)); } //********************************************************************************************************************* function isPreviousLogFileExists() { try { fs.accessSync(`${logDirectory}/${moduleName}.log`, fs.constants.R_OK | fs.constants.W_OK); return true; } catch (e) { return false; } } //********************************************************************************************************************* function getApplicationInfo() { let appData = {}; try { appData = JSON.parse(fs.readFileSync('package.json', 'utf-8')); } catch (e) {} return Object.assign({ name: 'Unknown', version: 'Unknown' }, appData) } //********************************************************************************************************************* function renamePreviousLogFile() { let lockData = getLockDataFromFile(moduleName); fs.renameSync(`${logDirectory}/${moduleName}.log`, `${logDirectory}/${moduleName}.${lockData.pid}.${lockData.startTime}.log`); logFileNames.push(`${moduleName}.${lockData.pid}.${lockData.startTime}.log`); } //********************************************************************************************************************* function getFormattedDateString(date) { return date.toLocaleString('en-US', {timeZone: timezone}) } //********************************************************************************************************************* function writeDataToLog(data) { fs.appendFileSync(`${logDirectory}/${moduleName}.log`, data + '\n'); } //********************************************************************************************************************* function splitToChunks(str, size){ if (str == null) return []; str = String(str); size = ~~size; return str.length > size ? str.match(new RegExp('.{1,' + size + '}(\ ){0,}', 'g')) : [str]; } //********************************************************************************************************************* function printBanner() { const appData = getApplicationInfo(); writeDataToLog(definitions.STAR_LINE); if (customBannerHeaders.length > 0) { writeDataToLog(definitions.STAR_INDENT); for (const line of customBannerHeaders) { writeDataToLog(definitions.STAR_INDENT + line); } writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_LINE); } writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_INDENT + `Module Name : ${moduleName}`); writeDataToLog(definitions.STAR_INDENT + `Project Name : ${appData.name}`); writeDataToLog(definitions.STAR_INDENT + `Version : ${appData.version}`); writeDataToLog(definitions.STAR_INDENT + `Configured Timezone : ${timezone}`); writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_LINE); writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_INDENT + `Log Number : #${logNumber}`); writeDataToLog(definitions.STAR_INDENT + `Process Start Time : ${getFormattedDateString(startTime)}`); writeDataToLog(definitions.STAR_INDENT + `Log Start Time : ${getFormattedDateString(new Date())}`); writeDataToLog(definitions.STAR_INDENT + `Log Level : ${logLevel}`); writeDataToLog(definitions.STAR_INDENT + `Continuing From : ${ logFileNames[logFileNames.length - 1] || 'None' }`); writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_LINE); writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_INDENT + `Hostname : ${os.hostname()}`); writeDataToLog(definitions.STAR_INDENT + `OS Release : ${os.release()}`); writeDataToLog(definitions.STAR_INDENT + `Platform : ${os.platform()}`); writeDataToLog(definitions.STAR_INDENT + `NodeJS Version : ${process.versions.node}`); writeDataToLog(definitions.STAR_INDENT + `OpenSSL Version : ${process.versions.openssl}`); writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_LINE); writeDataToLog(definitions.STAR_INDENT); writeDataToLog(definitions.STAR_INDENT + 'DEPENDENT NPM PACKAGE DETAILS'); writeDataToLog(definitions.STAR_INDENT); if (developmentMode) { writeDataToLog(definitions.STAR_INDENT + 'Dependent packages are not logged in Development Mode'); writeDataToLog(definitions.STAR_INDENT); } else { try { for (const line of child_process.execSync('npm list --depth=0').toString().split('\n')) { writeDataToLog(definitions.STAR_INDENT + line); } } catch (e) { writeDataToLog(definitions.STAR_INDENT + 'ERROR: NPM COMMAND `npm list --depth=0` FAILED'); } } writeDataToLog(definitions.STAR_LINE); } //********************************************************************************************************************* function switchLogFile() { if (isPreviousLogFileExists()){ if (developmentMode && logNumber === 0) { fs.unlinkSync(`${logDirectory}/${moduleName}.log`); } else { renamePreviousLogFile(); } } updateLockDataFile(); logNumber++; printBanner(); if (logNumber > 1 && callbackLogSwitch !== null) { callbackLogSwitch(); } } //********************************************************************************************************************* exports.init = (name, options = {}) => { moduleName = name; startTime = new Date(); if (options.customBannerHeaders) { customBannerHeaders = splitToChunks(options.customBannerHeaders, definitions.STAR_LINE.length - (definitions.STAR_INDENT.length * 2)); } if (options.devMode) { developmentMode = true; } if (options.timezone) { timezone = options.timezone; } if (options.logSwitchSize !== undefined) { logSwitchSize = options.logSwitchSize; } if (options.callbackLogSwitch) { callbackLogSwitch = options.callbackLogSwitch; } if (options.logLevel !== undefined) { logLevel = options.logLevel; } if (options.logDirectory) { try { fs.accessSync(options.logDirectory, fs.constants.R_OK | fs.constants.W_OK); } catch (e) { fs.mkdirSync(options.logDirectory); } logDirectory = options.logDirectory; } switchLogFile(); }; //********************************************************************************************************************* exports.write = (data) => { if (logSwitchSize !== definitions.NO_MAX_LOG_SIZE && fs.statSync(currentLogFile).size > logSwitchSize) { writeDataToLog(`Switching log files. Maximum file size (${logSwitchSize} Bytes) reached`); switchLogFile(); } writeDataToLog(data); }; //********************************************************************************************************************* exports.switchLogFile = (reason = 'null') => { writeDataToLog(`Switching log files. User request: ${reason}`); switchLogFile(); };