From 1c4d34f41598f490e7bc7247c2a00fefd527e9fb Mon Sep 17 00:00:00 2001 From: jpoirier <jpoirier@grandlyon.com> Date: Sat, 22 Jul 2023 09:26:03 +0200 Subject: [PATCH] feat: enhance winston logs exploitability - One file by day rather by hour, up to 20mb - Disable zippedArchive - Display stack traces - Add files prefix --- back/environments/sample.env | 1 + back/src/config/config.service.ts | 5 ++++ back/src/logger/logger.service.ts | 28 +++++++++++++--------- back/src/main.ts | 2 +- deployment/00-backend-files.config-map.yml | 1 + 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/back/environments/sample.env b/back/environments/sample.env index 23a7f3a..2005863 100644 --- a/back/environments/sample.env +++ b/back/environments/sample.env @@ -12,6 +12,7 @@ RATE_LIMIT_MAX=5000 # ********************************************************************************************* APP_LOG_DIR=logs +APP_LOG_FILES_PREFIX=backend-files # error < warn < log < debug < verbose APP_LOG_MAX_LEVEL=debug \ No newline at end of file diff --git a/back/src/config/config.service.ts b/back/src/config/config.service.ts index f990d45..564bb90 100644 --- a/back/src/config/config.service.ts +++ b/back/src/config/config.service.ts @@ -24,6 +24,7 @@ export class ConfigService { const envVarsSchema: Joi.ObjectSchema = Joi.object({ API_KEY: Joi.string().required(), APP_LOG_DIR: Joi.string().required(), + APP_LOG_FILES_PREFIX: Joi.string().required(), APP_LOG_MAX_LEVEL: Joi.string().required(), BODY_PARSER_LIMIT: Joi.string().default('50mb'), DOCUMENTS_DIR: Joi.string().required(), @@ -56,6 +57,10 @@ export class ConfigService { return String(this.envConfig.APP_LOG_DIR); } + public get appLogFilesPrefix(): string { + return String(this.envConfig.APP_LOG_FILES_PREFIX); + } + public get appLogMaxLevel(): string { return String(this.envConfig.APP_LOG_MAX_LEVEL); } diff --git a/back/src/logger/logger.service.ts b/back/src/logger/logger.service.ts index dd39ecf..2ea7964 100644 --- a/back/src/logger/logger.service.ts +++ b/back/src/logger/logger.service.ts @@ -1,4 +1,4 @@ -import { ConsoleLogger, Injectable, LogLevel, NotImplementedException, Scope } from '@nestjs/common'; +import { ConsoleLogger, Injectable, LogLevel, Scope } from '@nestjs/common'; import * as winston from 'winston'; import * as DailyRotateFile from 'winston-daily-rotate-file'; @@ -8,7 +8,7 @@ export class LoggerService extends ConsoleLogger { appLogMaxLevelDefault: LogLevel = 'log'; levelsNotLoggedInConsole: LogLevel[]; // Don't want to display debug/verbose in console - constructor(context: string, appLogDir: string, appLogMaxLevel: LogLevel) { + constructor(context: string, appLogDir: string, appLogFilesPrefix: string, appLogMaxLevel: LogLevel) { super(context); if (this.nestLevels.indexOf(appLogMaxLevel) < 0) { @@ -22,7 +22,7 @@ export class LoggerService extends ConsoleLogger { this.levelsNotLoggedInConsole = this.nestLevels.slice(this.nestLevels.indexOf(this.appLogMaxLevel) + 1); - this.createWinstonLoggers(appLogDir); + this.createWinstonLoggers(appLogDir, appLogFilesPrefix); } // ********************************************************************************************* @@ -32,10 +32,9 @@ export class LoggerService extends ConsoleLogger { winstonLoggers: winston.Logger[] = []; - private createWinstonLoggers(appLogDir: string): void { - const DailyOptions: any = { - datePattern: 'YYYY-MM-DD-HH', - zippedArchive: true, + private createWinstonLoggers(appLogDir: string, appLogFilesPrefix: string): void { + const dailyOptions: DailyRotateFile.DailyRotateFileTransportOptions = { + zippedArchive: false, maxSize: '20m', maxFiles: '14d', }; @@ -44,9 +43,11 @@ export class LoggerService extends ConsoleLogger { // * Formatters const readableFormat: winston.Logform.Format = winston.format.combine( + winston.format.errors({ stack: true }), // Cf. https://stackoverflow.com/a/58475687 winston.format.timestamp({ format: 'DD/MM/YYYY HH:mm:ss' }), winston.format.printf( - ({ level, message, timestamp, ...meta }) => `${timestamp} ${level.toUpperCase()} [${meta[Symbol.for('splat')]}] ${message}`, + ({ level, message, timestamp, stack, ...meta }) => + `${timestamp} ${level.toUpperCase()} [${meta[Symbol.for('splat')]}] ${level == 'error' ? stack : message}`, ), ); @@ -55,8 +56,8 @@ export class LoggerService extends ConsoleLogger { ( [ - { level: 'error', filePrefix: 'error-readable-' }, - { level: this.appLogMaxLevel, filePrefix: 'all-readable-' }, + { level: 'error', filePrefix: appLogFilesPrefix + '-error-readable-' }, + { level: this.appLogMaxLevel, filePrefix: appLogFilesPrefix + '-all-readable-' }, ] as { level: LogLevel; filePrefix: string }[] ).forEach((logger) => { try { @@ -64,7 +65,12 @@ export class LoggerService extends ConsoleLogger { winston.createLogger({ level: logger.level, format: readableFormat, - transports: [new DailyRotateFile({ filename: appLogDir + `/${logger.filePrefix}%DATE%.log`, ...DailyOptions })], + transports: [ + new DailyRotateFile({ + filename: appLogDir + `/${logger.filePrefix}%DATE%.log`, + ...dailyOptions, + } as DailyRotateFile.DailyRotateFileTransportOptions), + ], }), ); } catch (error) { diff --git a/back/src/main.ts b/back/src/main.ts index 4d94f1a..3e375ed 100644 --- a/back/src/main.ts +++ b/back/src/main.ts @@ -24,7 +24,7 @@ async function bootstrap() { app.use(express.urlencoded({ limit: config.bodyParserLimit, extended: true })); // Logger - app.useLogger(new LoggerService('AppModule', config.appLogDir, <LogLevel>config.appLogMaxLevel)); + app.useLogger(new LoggerService('AppModule', config.appLogDir, config.appLogFilesPrefix, <LogLevel>config.appLogMaxLevel)); // Skip SSL certificate verification https.globalAgent.options.rejectUnauthorized = false; diff --git a/deployment/00-backend-files.config-map.yml b/deployment/00-backend-files.config-map.yml index c26be55..5cc0335 100644 --- a/deployment/00-backend-files.config-map.yml +++ b/deployment/00-backend-files.config-map.yml @@ -5,6 +5,7 @@ metadata: namespace: ns-spi-NAMESPACE_ENV-syn data: APP_LOG_DIR: "{{APP_LOG_DIR}}" + APP_LOG_FILES_PREFIX: "backend-files" APP_LOG_MAX_LEVEL: "{{APP_LOG_MAX_LEVEL}}" DOCUMENTS_DIR: "{{DOCUMENTS_DIR}}" NODE_ENV: "{{NODE_ENV}}" -- GitLab