From 19993c6f5ba490fb4dd077b06b2de3e15b9b5147 Mon Sep 17 00:00:00 2001 From: Kir_Antipov Date: Wed, 14 Dec 2022 15:32:18 +0000 Subject: [PATCH] Added a logger that writes logs to the console --- src/utils/logging/console-logger.ts | 66 +++++++++++ .../unit/utils/logging/console-logger.spec.ts | 112 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/utils/logging/console-logger.ts create mode 100644 tests/unit/utils/logging/console-logger.spec.ts diff --git a/src/utils/logging/console-logger.ts b/src/utils/logging/console-logger.ts new file mode 100644 index 0000000..9c51539 --- /dev/null +++ b/src/utils/logging/console-logger.ts @@ -0,0 +1,66 @@ +import { Logger } from "./logger"; +import { error, warn, info, debug } from "node:console"; + +/** + * Represents a console-like object. + */ +type Console = Omit; + +/** + * Default console instance. + */ +const CONSOLE_INSTANCE: Console = { error, warn, info, debug }; + +/** + * A logger that writes log messages to the console. + */ +export class ConsoleLogger implements Logger { + /** + * A console instance to log messages to. + */ + private readonly _console: Console; + + /** + * Constructs a new {@link ConsoleLogger} instance. + * + * @param console - Optional custom console object to use for logging. + */ + constructor(console?: Console) { + this._console = console || CONSOLE_INSTANCE; + } + + /** + * @inheritdoc + */ + fatal(message: string | Error): void { + this._console.error(message); + } + + /** + * @inheritdoc + */ + error(message: string | Error): void { + this._console.error(message); + } + + /** + * @inheritdoc + */ + warn(message: string | Error): void { + this._console.warn(message); + } + + /** + * @inheritdoc + */ + info(message: string | Error): void { + this._console.info(message); + } + + /** + * @inheritdoc + */ + debug(message: string | Error): void { + this._console.debug(message); + } +} diff --git a/tests/unit/utils/logging/console-logger.spec.ts b/tests/unit/utils/logging/console-logger.spec.ts new file mode 100644 index 0000000..cb11452 --- /dev/null +++ b/tests/unit/utils/logging/console-logger.spec.ts @@ -0,0 +1,112 @@ +import { ConsoleLogger } from "@/utils/logging/console-logger"; + +interface MockConsole { + error: jest.Mock; + warn: jest.Mock; + info: jest.Mock; + debug: jest.Mock; +} + +function createMockConsole(): MockConsole { + return { + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + debug: jest.fn(), + }; +} + +describe("ConsoleLogger", () => { + describe("constructor", () => { + test("constructs a new instance with the provided console", () => { + const console = createMockConsole(); + const logger = new ConsoleLogger(console); + + logger.fatal("Fatal"); + logger.error("Error"); + logger.warn("Warn"); + logger.info("Info"); + logger.debug("Debug"); + + expect(console.error).toHaveBeenCalledTimes(2); + expect(console.error).toHaveBeenNthCalledWith(1, "Fatal"); + expect(console.error).toHaveBeenNthCalledWith(2, "Error"); + expect(console.warn).toHaveBeenCalledTimes(1); + expect(console.warn).toHaveBeenCalledWith("Warn"); + expect(console.info).toHaveBeenCalledTimes(1); + expect(console.info).toHaveBeenCalledWith("Info"); + expect(console.debug).toHaveBeenCalledTimes(1); + expect(console.debug).toHaveBeenCalledWith("Debug"); + }); + }); + + describe("fatal", () => { + test("redirects the call to console.error", () => { + const console = createMockConsole(); + const logger = new ConsoleLogger(console); + + logger.fatal("Fatal Error"); + logger.fatal(new Error("Fatal Error")); + + expect(console.error).toHaveBeenCalledTimes(2); + expect(console.error).toHaveBeenNthCalledWith(1, "Fatal Error"); + expect(console.error).toHaveBeenNthCalledWith(2, new Error("Fatal Error")); + }); + }); + + describe("error", () => { + test("redirects the call to console.error", () => { + const console = createMockConsole(); + const logger = new ConsoleLogger(console); + + logger.fatal("Error"); + logger.fatal(new Error("Error")); + + expect(console.error).toHaveBeenCalledTimes(2); + expect(console.error).toHaveBeenNthCalledWith(1, "Error"); + expect(console.error).toHaveBeenNthCalledWith(2, new Error("Error")); + }); + }); + + describe("warn", () => { + test("redirects the call to console.warn", () => { + const console = createMockConsole(); + const logger = new ConsoleLogger(console); + + logger.warn("Warning"); + logger.warn(new Error("Warning")); + + expect(console.warn).toHaveBeenCalledTimes(2); + expect(console.warn).toHaveBeenNthCalledWith(1, "Warning"); + expect(console.warn).toHaveBeenNthCalledWith(2, new Error("Warning")); + }); + }); + + describe("info", () => { + test("redirects the call to console.info", () => { + const console = createMockConsole(); + const logger = new ConsoleLogger(console); + + logger.info("Info"); + logger.info(new Error("Info")); + + expect(console.info).toHaveBeenCalledTimes(2); + expect(console.info).toHaveBeenNthCalledWith(1, "Info"); + expect(console.info).toHaveBeenNthCalledWith(2, new Error("Info")); + }); + }); + + describe("debug", () => { + test("redirects the call to console.debug", () => { + const console = createMockConsole(); + const logger = new ConsoleLogger(console); + + logger.debug("Debug Info"); + logger.debug(new Error("Debug Info")); + + expect(console.debug).toHaveBeenCalledTimes(2); + expect(console.debug).toHaveBeenNthCalledWith(1, "Debug Info"); + expect(console.debug).toHaveBeenNthCalledWith(2, new Error("Debug Info")); + }); + }); +});