From 883fa99108c711fc2076e5ff0f868c0573f862e6 Mon Sep 17 00:00:00 2001 From: spuxx1701 Date: Thu, 15 Aug 2024 22:45:40 +0200 Subject: [PATCH] feat: Implement CustomLogger class --- .eslintrc.cjs | 2 +- .../src/logging/custom.logger.test.ts | 38 +++++++++++++++++++ .../nest-utils/src/logging/custom.logger.ts | 34 +++++++++++++++++ packages/nest-utils/src/logging/index.ts | 1 + packages/nest-utils/src/main.ts | 1 + packages/nest-utils/src/testing.ts | 1 + .../nest-utils/src/testing/logging/index.ts | 1 + .../src/testing/logging/test.logger.ts | 19 ++++++++++ 8 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 packages/nest-utils/src/logging/custom.logger.test.ts create mode 100644 packages/nest-utils/src/logging/custom.logger.ts create mode 100644 packages/nest-utils/src/logging/index.ts create mode 100644 packages/nest-utils/src/testing/logging/index.ts create mode 100644 packages/nest-utils/src/testing/logging/test.logger.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 0a19abd..3c34da7 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -28,7 +28,7 @@ module.exports = { format: ['camelCase', 'PascalCase', 'UPPER_CASE'], leadingUnderscore: 'allow', }, - { selector: 'property', format: ['camelCase', 'UPPER_CASE'], leadingUnderscore: 'allow' }, + { selector: 'property', format: ['camelCase', 'PascalCase', 'UPPER_CASE'], leadingUnderscore: 'allow' }, { selector: 'property', modifiers: ['requiresQuotes'], format: null }, { selector: 'method', format: ['camelCase'], leadingUnderscore: 'allow' }, { selector: 'function', format: ['camelCase', 'PascalCase'] }, diff --git a/packages/nest-utils/src/logging/custom.logger.test.ts b/packages/nest-utils/src/logging/custom.logger.test.ts new file mode 100644 index 0000000..6f14f51 --- /dev/null +++ b/packages/nest-utils/src/logging/custom.logger.test.ts @@ -0,0 +1,38 @@ +import { TestAppLogger } from '../testing/logging'; +import { ApplicationLogLevel, CustomLogger } from './custom.logger'; + +describe('CustomLogger', () => { + it('should be ok', () => { + const logger = new CustomLogger(); + expect(logger).toBeDefined(); + expect(logger).toBeInstanceOf(CustomLogger); + }); + + describe('ApplicationLogLevel', () => { + it('should log the expected amount of messages with default logging enabled', () => { + const logger = new TestAppLogger({ + logLevel: ApplicationLogLevel.Default, + }); + logger.debug('hello world'); + logger.verbose('hello world'); + logger.log('hello world'); + logger.warn('hello world'); + logger.error('hello world'); + logger.fatal('hello world'); + expect(logger.printMessages).toHaveBeenCalledTimes(4); + }); + + it('should log the expected amount of messages with verbose logging enabled', () => { + const logger = new TestAppLogger({ + logLevel: ApplicationLogLevel.Verbose, + }); + logger.debug('hello world'); + logger.verbose('hello world'); + logger.log('hello world'); + logger.warn('hello world'); + logger.error('hello world'); + logger.fatal('hello world'); + expect(logger.printMessages).toHaveBeenCalledTimes(6); + }); + }); +}); diff --git a/packages/nest-utils/src/logging/custom.logger.ts b/packages/nest-utils/src/logging/custom.logger.ts new file mode 100644 index 0000000..40402dc --- /dev/null +++ b/packages/nest-utils/src/logging/custom.logger.ts @@ -0,0 +1,34 @@ +import { ConsoleLogger } from '@nestjs/common'; + +/** + * The application log level. + */ +export const ApplicationLogLevel = { + Default: 'default', + Verbose: 'verbose', +} as const; +export type ApplicationLogLevel = (typeof ApplicationLogLevel)[keyof typeof ApplicationLogLevel]; + +/** + * The custom application logger. This logger extends the NestJS console logger, but + * simplifies the API to set the application's log levels. + * @example + * // main.ts + * const app = await NestFactory.create(AppModule, { + * logger: new CustomLogger({ logLevel: ApplicationLogLevel.Verbose }), + * }); + */ +export class CustomLogger extends ConsoleLogger { + constructor(options?: { logLevel?: ApplicationLogLevel; context?: string }) { + super(); + const { logLevel, context } = { logLevel: 'default', ...options }; + if (logLevel === ApplicationLogLevel.Verbose) { + this.setLogLevels(['debug', 'verbose', 'log', 'warn', 'error', 'fatal']); + } else { + this.setLogLevels(['log', 'warn', 'error', 'fatal']); + } + if (context) { + this.setContext(context); + } + } +} diff --git a/packages/nest-utils/src/logging/index.ts b/packages/nest-utils/src/logging/index.ts new file mode 100644 index 0000000..445fb22 --- /dev/null +++ b/packages/nest-utils/src/logging/index.ts @@ -0,0 +1 @@ +export * from './custom.logger'; diff --git a/packages/nest-utils/src/main.ts b/packages/nest-utils/src/main.ts index de3582c..8d037a8 100644 --- a/packages/nest-utils/src/main.ts +++ b/packages/nest-utils/src/main.ts @@ -3,6 +3,7 @@ // Otherwise, they will not be included into the bundle. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ export * from './env'; +export * from './logging'; export * from './transformers'; // As long as NestJS does not support TypeScript's newer resolution algorithms like 'Node16', diff --git a/packages/nest-utils/src/testing.ts b/packages/nest-utils/src/testing.ts index 131c2af..1d734bc 100644 --- a/packages/nest-utils/src/testing.ts +++ b/packages/nest-utils/src/testing.ts @@ -4,3 +4,4 @@ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ export * from './testing/container'; export * from './testing/supertest'; +export * from './testing/logging'; diff --git a/packages/nest-utils/src/testing/logging/index.ts b/packages/nest-utils/src/testing/logging/index.ts new file mode 100644 index 0000000..862a8a2 --- /dev/null +++ b/packages/nest-utils/src/testing/logging/index.ts @@ -0,0 +1 @@ +export * from './test.logger'; diff --git a/packages/nest-utils/src/testing/logging/test.logger.ts b/packages/nest-utils/src/testing/logging/test.logger.ts new file mode 100644 index 0000000..f20db67 --- /dev/null +++ b/packages/nest-utils/src/testing/logging/test.logger.ts @@ -0,0 +1,19 @@ +import { CustomLogger } from '../../logging/custom.logger'; + +/** + * A custom logger for testing purposes. Replaces `printMessages` with a mocked function + * that can be spied on. + * @example + * const logger = new TestAppLogger(); + * logger.debug('hello world'); + * expect(logger.printMessages).toHaveBeenCalledTimes(1); + * + * // Or hand it over to TestContainer + * const container = await TestContainer.create({ + * logger, + * // ... + * }); + */ +export class TestAppLogger extends CustomLogger { + printMessages = vitest.fn(); +}