From 7ec46a9aab2376a8a5201ce57aba95116a00d291 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Wed, 11 Nov 2020 19:12:42 +0100 Subject: [PATCH] Add logs rotation. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .gitignore | 3 + docker/config.json | 4 +- package-lock.json | 29 +++++++ package.json | 1 + src/assets/config-template.json | 4 +- .../AutomaticTransactionGenerator.ts | 8 +- src/charging-station/ChargingStation.ts | 78 ++++++++++--------- src/types/ConfigurationData.ts | 4 +- src/utils/Configuration.ts | 8 +- src/utils/Logger.ts | 21 +++-- src/utils/Statistics.ts | 46 +++++------ src/utils/Utils.ts | 4 +- 12 files changed, 126 insertions(+), 84 deletions(-) diff --git a/.gitignore b/.gitignore index afb29cd9..113248a3 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,6 @@ build/config.gypi # System Files .DS_Store Thumbs.db + +# Winston +*-audit.json diff --git a/docker/config.json b/docker/config.json index 02ec2060..277f68f1 100644 --- a/docker/config.json +++ b/docker/config.json @@ -34,7 +34,7 @@ "numberOfStations": 10 } ], - "consoleLog": false, + "logConsole": false, "logFile": "/dev/stdout", - "errorFile": "/dev/stderr" + "logErrorFile": "/dev/stderr" } diff --git a/package-lock.json b/package-lock.json index 58ee363b..a7ed82c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4578,6 +4578,14 @@ "flat-cache": "^2.0.1" } }, + "file-stream-rotator": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.5.7.tgz", + "integrity": "sha512-VYb3HZ/GiAGUCrfeakO8Mp54YGswNUHvL7P09WQcXAJNSj3iQ5QraYSp3cIn1MUyw6uzfgN/EFOarCNa4JvUHQ==", + "requires": { + "moment": "^2.11.2" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -7197,6 +7205,11 @@ "xtend": "^4.0.0" } }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, "morphdom": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.6.1.tgz", @@ -7799,6 +7812,11 @@ } } }, + "object-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", + "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==" + }, "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", @@ -11086,6 +11104,17 @@ } } }, + "winston-daily-rotate-file": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.0.tgz", + "integrity": "sha512-/HqeWiU48dzGqcrABRlxYWVMdL6l3uKCtFSJyrqK+E2rLnSFNsgYpvwx15EgTitBLNzH69lQd/+z2ASryV2aqw==", + "requires": { + "file-stream-rotator": "^0.5.7", + "object-hash": "^2.0.1", + "triple-beam": "^1.3.0", + "winston-transport": "^4.2.0" + } + }, "winston-transport": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", diff --git a/package.json b/package.json index b3dde366..2aa64bed 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "tslib": "^2.0.3", "uuid": "^8.3.1", "winston": "^3.3.3", + "winston-daily-rotate-file": "^4.5.0", "worker-threads-pool": "^2.0.0", "ws": "^7.4.0" }, diff --git a/src/assets/config-template.json b/src/assets/config-template.json index d55855fe..b3085a7c 100644 --- a/src/assets/config-template.json +++ b/src/assets/config-template.json @@ -31,6 +31,6 @@ } ], "logFile": "combined.log", - "errorFile": "error.log", - "consoleLog": false + "logErrorFile": "error.log", + "logConsole": false } diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index ac7b2008..399a9942 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -29,7 +29,7 @@ export default class AutomaticTransactionGenerator { _logPrefix(connectorId: number = null): string { if (connectorId) { - return Utils.logPrefix(' ' + this._chargingStation.stationInfo.name + ' ATG on connector #' + connectorId + ':'); + return Utils.logPrefix(' ' + this._chargingStation.stationInfo.name + ' ATG on connector #' + connectorId.toString() + ':'); } return Utils.logPrefix(' ' + this._chargingStation.stationInfo.name + ' ATG:'); } @@ -54,7 +54,7 @@ export default class AutomaticTransactionGenerator { logger.info(this._logPrefix() + ' ATG OVER => STOPPING ALL TRANSACTIONS'); for (const connector in this._chargingStation.connectors) { if (this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionStarted) { - logger.info(this._logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionId); + logger.info(this._logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionId.toString()); await this._chargingStation.sendStopTransaction(this._chargingStation.getConnector(Utils.convertToInt(connector)).transactionId, reason); } } @@ -91,11 +91,11 @@ export default class AutomaticTransactionGenerator { // Wait until end of transaction const waitTrxEnd = Utils.getRandomInt(this._chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration, this._chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000; - logger.info(this._logPrefix(connectorId) + ' transaction ' + this._chargingStation.getConnector(connectorId).transactionId + ' will stop in ' + Utils.milliSecondsToHHMMSS(waitTrxEnd)); + logger.info(this._logPrefix(connectorId) + ' transaction ' + this._chargingStation.getConnector(connectorId).transactionId.toString() + ' will stop in ' + Utils.milliSecondsToHHMMSS(waitTrxEnd)); await Utils.sleep(waitTrxEnd); // Stop transaction if (this._chargingStation.getConnector(connectorId).transactionStarted) { - logger.info(this._logPrefix(connectorId) + ' stop transaction ' + this._chargingStation.getConnector(connectorId).transactionId); + logger.info(this._logPrefix(connectorId) + ' stop transaction ' + this._chargingStation.getConnector(connectorId).transactionId.toString()); if (this._chargingStation.getEnableStatistics()) { const stopTransaction = performance.timerify(this.stopTransaction); this._performanceObserver.observe({ entryTypes: ['function'] }); diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 843093e2..73496046 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -83,7 +83,7 @@ export default class ChargingStation { stationTemplateFromFile = JSON.parse(fs.readFileSync(fileDescriptor, 'utf8')) as ChargingStationTemplate; fs.closeSync(fileDescriptor); } catch (error) { - logger.error('Template file ' + this._stationTemplateFile + ' loading error: ' + error); + logger.error('Template file ' + this._stationTemplateFile + ' loading error: %j', error); throw error; } const stationInfo: ChargingStationInfo = stationTemplateFromFile || {} as ChargingStationInfo; @@ -201,7 +201,7 @@ export default class ChargingStation { authorizedTags = JSON.parse(fs.readFileSync(fileDescriptor, 'utf8')) as string[]; fs.closeSync(fileDescriptor); } catch (error) { - logger.error(this._logPrefix() + ' Authorization file ' + authorizationFile + ' loading error: ' + error); + logger.error(this._logPrefix() + ' Authorization file ' + authorizationFile + ' loading error: %j', error); throw error; } } else { @@ -263,7 +263,7 @@ export default class ChargingStation { if (!Utils.isEmptyArray(this._stationInfo.numberOfConnectors)) { const numberOfConnectors = this._stationInfo.numberOfConnectors as number[]; // Distribute evenly the number of connectors - maxConnectors = numberOfConnectors[(this._index - 1) % numberOfConnectors.length] ; + maxConnectors = numberOfConnectors[(this._index - 1) % numberOfConnectors.length]; } else if (!Utils.isUndefined(this._stationInfo.numberOfConnectors)) { maxConnectors = this._stationInfo.numberOfConnectors as number; } else { @@ -306,7 +306,7 @@ export default class ChargingStation { } _getSupervisionURL(): string { - const supervisionUrls = Utils.cloneObject(this._stationInfo.supervisionURL ? this._stationInfo.supervisionURL : Configuration.getSupervisionURLs()) as string|string[]; + const supervisionUrls = Utils.cloneObject(this._stationInfo.supervisionURL ? this._stationInfo.supervisionURL : Configuration.getSupervisionURLs()) as string | string[]; let indexUrl = 0; if (!Utils.isEmptyArray(supervisionUrls)) { if (Configuration.getDistributeStationToTenantEqually()) { @@ -315,7 +315,7 @@ export default class ChargingStation { // Get a random url indexUrl = Math.floor(Math.random() * supervisionUrls.length); } - return supervisionUrls[indexUrl] ; + return supervisionUrls[indexUrl]; } return supervisionUrls as string; } @@ -404,7 +404,7 @@ export default class ChargingStation { // Initialize _authorizedTags this._authorizedTags = this._loadAndGetAuthorizedTags(); } catch (error) { - logger.error(this._logPrefix() + ' Authorization file monitoring error: ' + error); + logger.error(this._logPrefix() + ' Authorization file monitoring error: %j', error); } }); } @@ -421,7 +421,7 @@ export default class ChargingStation { this._automaticTransactionGeneration.stop().catch(() => { }); } } catch (error) { - logger.error(this._logPrefix() + ' Charging station template file monitoring error: ' + error); + logger.error(this._logPrefix() + ' Charging station template file monitoring error: %j', error); } }); } @@ -487,13 +487,13 @@ export default class ChargingStation { } _reconnect(error): void { - logger.error(this._logPrefix() + ' Socket: abnormally closed', error); + logger.error(this._logPrefix() + ' Socket: abnormally closed %j', error); // Stop the ATG if needed if (this._stationInfo.AutomaticTransactionGenerator.enable && this._stationInfo.AutomaticTransactionGenerator.stopOnConnectionFailure && this._automaticTransactionGeneration && !this._automaticTransactionGeneration.timeToStop) { - this._automaticTransactionGeneration.stop().catch(() => {}); + this._automaticTransactionGeneration.stop().catch(() => { }); } // Stop heartbeat this._stopHeartbeat(); @@ -537,7 +537,7 @@ export default class ChargingStation { this._reconnect(error); break; default: - logger.error(this._logPrefix() + ' Socket error: ' + error); + logger.error(this._logPrefix() + ' Socket error: %j', error); break; } } @@ -546,7 +546,7 @@ export default class ChargingStation { switch (error) { case 1000: // Normal close case 1005: - logger.info(this._logPrefix() + ' Socket normally closed ' + error); + logger.info(this._logPrefix() + ' Socket normally closed %j', error); this._autoReconnectRetryCount = 0; break; default: // Abnormal close @@ -631,7 +631,7 @@ export default class ChargingStation { }; await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'Heartbeat'); } catch (error) { - logger.error(this._logPrefix() + ' Send Heartbeat error: ' + error); + logger.error(this._logPrefix() + ' Send Heartbeat error: %j', error); throw error; } } @@ -640,7 +640,7 @@ export default class ChargingStation { try { await this.sendMessage(Utils.generateUUID(), this._bootNotificationMessage, Constants.OCPP_JSON_CALL_MESSAGE, 'BootNotification'); } catch (error) { - logger.error(this._logPrefix() + ' Send BootNotification error: ' + error); + logger.error(this._logPrefix() + ' Send BootNotification error: %j', error); throw error; } } @@ -655,7 +655,7 @@ export default class ChargingStation { }; await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StatusNotification'); } catch (error) { - logger.error(this._logPrefix() + ' Send StatusNotification error: ' + error); + logger.error(this._logPrefix() + ' Send StatusNotification error: %j', error); throw error; } } @@ -670,7 +670,7 @@ export default class ChargingStation { }; return await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StartTransaction') as StartTransactionResponse; } catch (error) { - logger.error(this._logPrefix() + ' Send StartTransaction error: ' + error); + logger.error(this._logPrefix() + ' Send StartTransaction error: %j', error); throw error; } } @@ -687,7 +687,7 @@ export default class ChargingStation { }; return await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StopTransaction') as StartTransactionResponse; } catch (error) { - logger.error(this._logPrefix() + ' Send StopTransaction error: ' + error); + logger.error(this._logPrefix() + ' Send StopTransaction error: %j', error); throw error; } } @@ -801,7 +801,7 @@ export default class ChargingStation { ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: powerMeasurandValues[`L${phase}`] }, + ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: powerMeasurandValues[`L${phase}`] as string }, phase: phaseValue as MeterValuePhase, }); } @@ -862,7 +862,7 @@ export default class ChargingStation { ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: currentMeasurandValues[phaseValue] }, + ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: currentMeasurandValues[phaseValue] as string }, phase: phaseValue as MeterValuePhase, }); } @@ -892,7 +892,8 @@ export default class ChargingStation { ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: connector.lastEnergyActiveImportRegisterValue.toString() }, + ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : + { value: connector.lastEnergyActiveImportRegisterValue.toString() }, }); const sampledValuesIndex = sampledValues.sampledValue.length - 1; const maxConsumption = Math.round(self._stationInfo.maxPower * 3600 / (self._stationInfo.powerDivider * interval)); @@ -912,7 +913,7 @@ export default class ChargingStation { }; await self.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'MeterValues'); } catch (error) { - logger.error(self._logPrefix() + ' Send MeterValues error: ' + error); + logger.error(self._logPrefix() + ' Send MeterValues error: %j', error); throw error; } } @@ -1045,46 +1046,47 @@ export default class ChargingStation { } handleResponseStartTransaction(payload: StartTransactionResponse, requestPayload): void { - if (this.getConnector(requestPayload.connectorId).transactionStarted) { - logger.debug(this._logPrefix() + ' Try to start a transaction on an already used connector ' + requestPayload.connectorId + ': %s', this.getConnector(requestPayload.connectorId)); + const connectorId = Utils.convertToInt(requestPayload.connectorId); + if (this.getConnector(connectorId).transactionStarted) { + logger.debug(this._logPrefix() + ' Try to start a transaction on an already used connector ' + connectorId.toString() + ': %j', this.getConnector(connectorId)); return; } let transactionConnectorId: number; for (const connector in this._connectors) { - if (Utils.convertToInt(connector) === Utils.convertToInt(requestPayload.connectorId)) { + if (Utils.convertToInt(connector) === connectorId) { transactionConnectorId = Utils.convertToInt(connector); break; } } if (!transactionConnectorId) { - logger.error(this._logPrefix() + ' Try to start a transaction on a non existing connector Id ' + requestPayload.connectorId); + logger.error(this._logPrefix() + ' Try to start a transaction on a non existing connector Id ' + connectorId.toString()); return; } if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { - this.getConnector(requestPayload.connectorId).transactionStarted = true; - this.getConnector(requestPayload.connectorId).transactionId = payload.transactionId; - this.getConnector(requestPayload.connectorId).idTag = requestPayload.idTag; - this.getConnector(requestPayload.connectorId).lastEnergyActiveImportRegisterValue = 0; - this.sendStatusNotification(requestPayload.connectorId, ChargePointStatus.CHARGING); - logger.info(this._logPrefix() + ' Transaction ' + payload.transactionId + ' STARTED on ' + this._stationInfo.name + '#' + requestPayload.connectorId + ' for idTag ' + requestPayload.idTag); + this.getConnector(connectorId).transactionStarted = true; + this.getConnector(connectorId).transactionId = payload.transactionId; + this.getConnector(connectorId).idTag = requestPayload.idTag; + this.getConnector(connectorId).lastEnergyActiveImportRegisterValue = 0; + this.sendStatusNotification(connectorId, ChargePointStatus.CHARGING).catch(() => { }); + logger.info(this._logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + this._stationInfo.name + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag); if (this._stationInfo.powerSharedByConnectors) { this._stationInfo.powerDivider++; } const configuredMeterValueSampleInterval = this._getConfigurationKey('MeterValueSampleInterval'); - this._startMeterValues(requestPayload.connectorId, + this._startMeterValues(connectorId, configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000); } else { - logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId + ' REJECTED with status ' + payload.idTagInfo?.status + ', idTag ' + requestPayload.idTag); - this._resetTransactionOnConnector(requestPayload.connectorId); - this.sendStatusNotification(requestPayload.connectorId, ChargePointStatus.AVAILABLE); + logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status + ', idTag ' + requestPayload.idTag); + this._resetTransactionOnConnector(connectorId); + this.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE).catch(() => { }); } } handleResponseStopTransaction(payload: StopTransactionResponse, requestPayload): void { let transactionConnectorId: number; for (const connector in this._connectors) { - if (this.getConnector(Utils.convertToInt(connector)).transactionId === requestPayload.transactionId) { + if (this.getConnector(Utils.convertToInt(connector)).transactionId === Utils.convertToInt(requestPayload.transactionId)) { transactionConnectorId = Utils.convertToInt(connector); break; } @@ -1094,7 +1096,7 @@ export default class ChargingStation { return; } if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { - this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE); + this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE).catch(() => { }); if (this._stationInfo.powerSharedByConnectors) { this._stationInfo.powerDivider--; } @@ -1126,7 +1128,7 @@ export default class ChargingStation { response = await this['handleRequest' + commandName](commandPayload); } catch (error) { // Log - logger.error(this._logPrefix() + ' Handle request error: ' + error); + logger.error(this._logPrefix() + ' Handle request error: %j', error); // Send back response to inform backend await this.sendError(messageId, error, commandName); throw error; @@ -1295,7 +1297,7 @@ export default class ChargingStation { return Constants.OCPP_RESPONSE_ACCEPTED; } } - logger.info(this._logPrefix() + ' Try to stop remotely a non existing transaction ' + commandPayload.transactionId); + logger.info(this._logPrefix() + ' Try to stop remotely a non existing transaction ' + transactionId.toString()); return Constants.OCPP_RESPONSE_REJECTED; } } diff --git a/src/types/ConfigurationData.ts b/src/types/ConfigurationData.ts index 29a443aa..3f51cb85 100644 --- a/src/types/ConfigurationData.ts +++ b/src/types/ConfigurationData.ts @@ -15,6 +15,6 @@ export default interface ConfigurationData { logFormat?: string; logLevel?: string; logFile?: string; - errorFile?: string; - consoleLog?: boolean; + logErrorFile?: string; + logConsole?: boolean; } diff --git a/src/utils/Configuration.ts b/src/utils/Configuration.ts index d15f9053..ab48cf31 100644 --- a/src/utils/Configuration.ts +++ b/src/utils/Configuration.ts @@ -42,8 +42,8 @@ export default class Configuration { return Configuration.getConfig().workerPoolSize; } - static getConsoleLog(): boolean { - return Utils.objectHasOwnProperty(Configuration.getConfig(), 'consoleLog') ? Configuration.getConfig().consoleLog : false; + static getLogConsole(): boolean { + return Utils.objectHasOwnProperty(Configuration.getConfig(), 'logConsole') ? Configuration.getConfig().logConsole : false; } static getLogFormat(): string { @@ -58,8 +58,8 @@ export default class Configuration { return Utils.objectHasOwnProperty(Configuration.getConfig(), 'logFile') ? Configuration.getConfig().logFile : 'combined.log'; } - static getErrorFile(): string { - return Utils.objectHasOwnProperty(Configuration.getConfig(), 'errorFile') ? Configuration.getConfig().errorFile : 'error.log'; + static getLogErrorFile(): string { + return Utils.objectHasOwnProperty(Configuration.getConfig(), 'logErrorFile') ? Configuration.getConfig().logErrorFile : 'error.log'; } static getSupervisionURLs(): string[] { diff --git a/src/utils/Logger.ts b/src/utils/Logger.ts index 736e9b89..e45550c9 100644 --- a/src/utils/Logger.ts +++ b/src/utils/Logger.ts @@ -1,16 +1,21 @@ +import 'winston-daily-rotate-file'; + import Configuration from './Configuration'; -import Winston from 'winston'; +import Utils from './Utils'; +import winston from 'winston'; + +const maxLogFiles = 7; -const logger = Winston.createLogger({ +const logger = winston.createLogger({ level: Configuration.getLogLevel(), - format: Winston.format.combine(Winston.format.splat(), Winston.format[Configuration.getLogFormat()]()), + format: winston.format.combine(winston.format.splat(), winston.format[Configuration.getLogFormat()]()), transports: [ // // - Write to all logs with level `info` and below to `combined.log` // - Write all logs error (and below) to `error.log`. // - new Winston.transports.File({ filename: Configuration.getErrorFile(), level: 'error' }), - new Winston.transports.File({ filename: Configuration.getLogFile() }), + new winston.transports.DailyRotateFile({ filename: Utils.insertAt(Configuration.getLogErrorFile(), '-%DATE%', Configuration.getLogErrorFile().indexOf('.log')), level: 'error', maxFiles: maxLogFiles }), + new winston.transports.DailyRotateFile({ filename: Utils.insertAt(Configuration.getLogFile(), '-%DATE%', Configuration.getLogFile().indexOf('.log')), maxFiles: maxLogFiles }), ], }); @@ -18,9 +23,9 @@ const logger = Winston.createLogger({ // If enabled, log to the `console` with the format: // `${info.level}: ${info.message} JSON.stringify({ ...rest }) ` // -if (Configuration.getConsoleLog()) { - logger.add(new Winston.transports.Console({ - format: Winston.format.combine(Winston.format.splat(), Winston.format[Configuration.getLogFormat()]()), +if (Configuration.getLogConsole()) { + logger.add(new winston.transports.Console({ + format: winston.format.combine(winston.format.splat(), winston.format[Configuration.getLogFormat()]()), })); } diff --git a/src/utils/Statistics.ts b/src/utils/Statistics.ts index f2bfee4f..0f0674d1 100644 --- a/src/utils/Statistics.ts +++ b/src/utils/Statistics.ts @@ -67,28 +67,6 @@ export default class Statistics { } } - addPerformanceTimer(command: string, duration: number): void { - // Map to proper command name - const MAPCOMMAND = { - sendMeterValues: 'MeterValues', - startTransaction: 'StartTransaction', - stopTransaction: 'StopTransaction', - }; - if (MAPCOMMAND[command]) { - command = MAPCOMMAND[command] as string; - } - // Initialize command statistics - if (!this._commandsStatistics[command]) { - this._commandsStatistics[command] = {} as CommandStatisticsData; - } - // Update current statistics timers - this._commandsStatistics[command].countTime = this._commandsStatistics[command].countTime ? this._commandsStatistics[command].countTime + 1 : 1; - this._commandsStatistics[command].minTime = this._commandsStatistics[command].minTime ? (this._commandsStatistics[command].minTime > duration ? duration : this._commandsStatistics[command].minTime) : duration; - this._commandsStatistics[command].maxTime = this._commandsStatistics[command].maxTime ? (this._commandsStatistics[command].maxTime < duration ? duration : this._commandsStatistics[command].maxTime) : duration; - this._commandsStatistics[command].totalTime = this._commandsStatistics[command].totalTime ? this._commandsStatistics[command].totalTime + duration : duration; - this._commandsStatistics[command].avgTime = this._commandsStatistics[command].totalTime / this._commandsStatistics[command].countTime; - } - logPerformance(entry: PerformanceEntry, className: string): void { this.addPerformanceTimer(entry.name, entry.duration); logger.info(`${this._logPrefix()} class->${className}, method->${entry.name}, duration->${entry.duration}`); @@ -103,7 +81,7 @@ export default class Statistics { setInterval(() => { this._display(); }, Configuration.getStatisticsDisplayInterval() * 1000); - logger.info(this._logPrefix() + ' displayed every ' + Configuration.getStatisticsDisplayInterval().toString() + 's'); + logger.info(this._logPrefix() + ' displayed every ' + Utils.secondsToHHMMSS(Configuration.getStatisticsDisplayInterval())); } } @@ -111,6 +89,28 @@ export default class Statistics { this._displayInterval(); } + private addPerformanceTimer(command: string, duration: number): void { + // Map to proper command name + const MAPCOMMAND = { + sendMeterValues: 'MeterValues', + startTransaction: 'StartTransaction', + stopTransaction: 'StopTransaction', + }; + if (MAPCOMMAND[command]) { + command = MAPCOMMAND[command] as string; + } + // Initialize command statistics + if (!this._commandsStatistics[command]) { + this._commandsStatistics[command] = {} as CommandStatisticsData; + } + // Update current statistics timers + this._commandsStatistics[command].countTime = this._commandsStatistics[command].countTime ? this._commandsStatistics[command].countTime + 1 : 1; + this._commandsStatistics[command].minTime = this._commandsStatistics[command].minTime ? (this._commandsStatistics[command].minTime > duration ? duration : this._commandsStatistics[command].minTime) : duration; + this._commandsStatistics[command].maxTime = this._commandsStatistics[command].maxTime ? (this._commandsStatistics[command].maxTime < duration ? duration : this._commandsStatistics[command].maxTime) : duration; + this._commandsStatistics[command].totalTime = this._commandsStatistics[command].totalTime ? this._commandsStatistics[command].totalTime + duration : duration; + this._commandsStatistics[command].avgTime = this._commandsStatistics[command].totalTime / this._commandsStatistics[command].countTime; + } + private _logPrefix(): string { return Utils.logPrefix(` ${this._objName} Statistics:`); } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 52a2b0ee..167e299d 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -149,7 +149,7 @@ export default class Utils { return typeof value === 'string'; } - static isUndefined(value) { + static isUndefined(value): boolean { return typeof value === 'undefined'; } @@ -171,4 +171,6 @@ export default class Utils { static isEmptyObject(obj): boolean { return !Object.keys(obj).length; } + + static insertAt = (str: string, subStr: string, pos: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`; } -- 2.34.1