From b256fc8b367023c9a20f658f6c8d2ab374b74064 Mon Sep 17 00:00:00 2001 From: David Mehren Date: Sun, 27 Sep 2020 21:41:02 +0200 Subject: [PATCH] Add logger module and custom logger implementation ConsoleLoggerService is based on the default Nest LoggerService, but adds the ability to give context about the function that is logging something. It also removes the `[Nest]` string and the PID at the beginning of each log line. NestConsoleLoggerService is a wrapper around ConsoleLoggerService and makes it possible to use our implementation as a default Nest LoggerService Signed-off-by: David Mehren --- src/logger/console-logger.service.ts | 119 ++++++++++++++++++++++ src/logger/logger.module.ts | 9 ++ src/logger/nest-console-logger.service.ts | 33 ++++++ 3 files changed, 161 insertions(+) create mode 100644 src/logger/console-logger.service.ts create mode 100644 src/logger/logger.module.ts create mode 100644 src/logger/nest-console-logger.service.ts diff --git a/src/logger/console-logger.service.ts b/src/logger/console-logger.service.ts new file mode 100644 index 000000000..bc594f3c3 --- /dev/null +++ b/src/logger/console-logger.service.ts @@ -0,0 +1,119 @@ +import { Injectable, Optional, Scope } from '@nestjs/common'; +import { isObject } from '@nestjs/common/utils/shared.utils'; +import * as clc from 'cli-color'; + +@Injectable({ scope: Scope.TRANSIENT }) +export class ConsoleLoggerService { + private classContext; + private lastTimestamp: number; + + constructor(@Optional() context?: string) { + this.classContext = context; + } + + setContext(context: string) { + this.classContext = context; + } + + error(message: any, trace = '', functionContext?: string) { + this.printMessage( + message, + clc.red, + this.makeContextString(functionContext), + false, + ); + this.printStackTrace(trace); + } + + log(message: any, functionContext?: string) { + this.printMessage( + message, + clc.green, + this.makeContextString(functionContext), + false, + ); + } + + warn(message: any, functionContext?: string) { + this.printMessage( + message, + clc.yellow, + this.makeContextString(functionContext), + false, + ); + } + + debug(message: any, functionContext?: string) { + this.printMessage( + message, + clc.magentaBright, + this.makeContextString(functionContext), + false, + ); + } + + verbose(message: any, functionContext?: string) { + this.printMessage( + message, + clc.cyanBright, + this.makeContextString(functionContext), + false, + ); + } + + private makeContextString(functionContext) { + let context = this.classContext; + if (functionContext) { + context += '.' + functionContext + '()'; + } + return context; + } + + private printMessage( + message: any, + color: (message: string) => string, + context = '', + isTimeDiffEnabled?: boolean, + ) { + const output = isObject(message) + ? `${color('Object:')}\n${JSON.stringify(message, null, 2)}\n` + : color(message); + + const localeStringOptions = { + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + day: '2-digit', + month: '2-digit', + }; + //TODO make timestamp optional + const timestamp = new Date(Date.now()).toLocaleString( + undefined, + localeStringOptions, + ); + + const contextMessage = context ? clc.blue(`[${context}] `) : ''; + const timestampDiff = this.updateAndGetTimestampDiff(isTimeDiffEnabled); + + process.stdout.write( + `${timestamp} ${contextMessage}${output}${timestampDiff}\n`, + ); + } + + private updateAndGetTimestampDiff(isTimeDiffEnabled?: boolean): string { + const includeTimestamp = this.lastTimestamp && isTimeDiffEnabled; + const result = includeTimestamp + ? clc.yellow(` +${Date.now() - this.lastTimestamp}ms`) + : ''; + this.lastTimestamp = Date.now(); + return result; + } + + private printStackTrace(trace: string) { + if (!trace) { + return; + } + process.stdout.write(`${trace}\n`); + } +} diff --git a/src/logger/logger.module.ts b/src/logger/logger.module.ts new file mode 100644 index 000000000..fee91d3c4 --- /dev/null +++ b/src/logger/logger.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { ConsoleLoggerService } from './console-logger.service'; +import { NestConsoleLoggerService } from './nest-console-logger.service'; + +@Module({ + providers: [ConsoleLoggerService, NestConsoleLoggerService], + exports: [ConsoleLoggerService, NestConsoleLoggerService], +}) +export class LoggerModule {} diff --git a/src/logger/nest-console-logger.service.ts b/src/logger/nest-console-logger.service.ts new file mode 100644 index 000000000..918710d0c --- /dev/null +++ b/src/logger/nest-console-logger.service.ts @@ -0,0 +1,33 @@ +import { Injectable, LoggerService } from '@nestjs/common'; +import { ConsoleLoggerService } from './console-logger.service'; + +Injectable(); + +export class NestConsoleLoggerService implements LoggerService { + private consoleLoggerService = new ConsoleLoggerService(); + + debug(message: any, context?: string): any { + this.consoleLoggerService.setContext(context); + this.consoleLoggerService.debug(message); + } + + error(message: any, trace?: string, context?: string): any { + this.consoleLoggerService.setContext(context); + this.consoleLoggerService.error(message); + } + + log(message: any, context?: string): any { + this.consoleLoggerService.setContext(context); + this.consoleLoggerService.log(message); + } + + verbose(message: any, context?: string): any { + this.consoleLoggerService.setContext(context); + this.consoleLoggerService.verbose(message); + } + + warn(message: any, context?: string): any { + this.consoleLoggerService.setContext(context); + this.consoleLoggerService.warn(message); + } +}