From c3c13351a9f26f2209b51b8ded5e8f2a1ad86e94 Mon Sep 17 00:00:00 2001 From: Paul Thompson Date: Mon, 6 Jul 2020 13:57:31 +1000 Subject: [PATCH] std/log - Expose Logger type and improve public interface for get & set log levels (#6617) --- std/log/logger.ts | 43 ++++++++++---- std/log/mod.ts | 3 +- std/log/mod_test.ts | 133 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 166 insertions(+), 13 deletions(-) diff --git a/std/log/logger.ts b/std/log/logger.ts index 004088d9ac..05e83dc772 100644 --- a/std/log/logger.ts +++ b/std/log/logger.ts @@ -43,22 +43,43 @@ export interface LoggerOptions { } export class Logger { - level: number; - levelName: LevelName; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handlers: any[]; - loggerName: string; + #level: LogLevels; + #handlers: BaseHandler[]; + readonly #loggerName: string; constructor( loggerName: string, levelName: LevelName, options: LoggerOptions = {} ) { - this.loggerName = loggerName; - this.level = getLevelByName(levelName); - this.levelName = levelName; + this.#loggerName = loggerName; + this.#level = getLevelByName(levelName); + this.#handlers = options.handlers || []; + } - this.handlers = options.handlers || []; + get level(): LogLevels { + return this.#level; + } + set level(level: LogLevels) { + this.#level = level; + } + + get levelName(): LevelName { + return getLevelName(this.#level); + } + set levelName(levelName: LevelName) { + this.#level = getLevelByName(levelName); + } + + get loggerName(): string { + return this.#loggerName; + } + + set handlers(hndls: BaseHandler[]) { + this.#handlers = hndls; + } + get handlers(): BaseHandler[] { + return this.#handlers; } /** If the level of the logger is greater than the level to log, then nothing @@ -68,7 +89,7 @@ export class Logger { * function, not the function itself, unless the function isn't called, in which * case undefined is returned. All types are coerced to strings for logging. */ - _log( + private _log( level: number, msg: (T extends Function ? never : T) | (() => T), ...args: unknown[] @@ -92,7 +113,7 @@ export class Logger { loggerName: this.loggerName, }); - this.handlers.forEach((handler): void => { + this.#handlers.forEach((handler): void => { handler.handle(record); }); diff --git a/std/log/mod.ts b/std/log/mod.ts index a1a863d4a9..ed94725c49 100644 --- a/std/log/mod.ts +++ b/std/log/mod.ts @@ -10,7 +10,8 @@ import { import { assert } from "../_util/assert.ts"; import { LevelName } from "./levels.ts"; -export { LogLevels } from "./levels.ts"; +export { LogLevels, LevelName } from "./levels.ts"; +export { Logger } from "./logger.ts"; export class LoggerConfig { level?: LevelName; diff --git a/std/log/mod_test.ts b/std/log/mod_test.ts index 9de5d76afa..30c6b09142 100644 --- a/std/log/mod_test.ts +++ b/std/log/mod_test.ts @@ -8,8 +8,10 @@ import { error, critical, setup, + Logger, + LogLevels, + LevelName, } from "./mod.ts"; -import { Logger } from "./logger.ts"; import { BaseHandler } from "./handlers.ts"; class TestHandler extends BaseHandler { @@ -89,3 +91,132 @@ Deno.test({ assertEquals(anotherConsoleHandler.messages[0], "[tasks] ERROR world"); }, }); + +Deno.test({ + name: "Loggers have level and levelName to get/set loglevels", + async fn() { + const testHandler = new TestHandler("DEBUG"); + await setup({ + handlers: { + test: testHandler, + }, + + loggers: { + // configure default logger available via short-hand methods above + default: { + level: "DEBUG", + handlers: ["test"], + }, + }, + }); + const logger: Logger = getLogger(); + assertEquals(logger.levelName, "DEBUG"); + assertEquals(logger.level, LogLevels.DEBUG); + + logger.debug("debug"); + logger.error("error"); + logger.critical("critical"); + assertEquals(testHandler.messages.length, 3); + assertEquals(testHandler.messages[0], "DEBUG debug"); + assertEquals(testHandler.messages[1], "ERROR error"); + assertEquals(testHandler.messages[2], "CRITICAL critical"); + + testHandler.messages = []; + logger.level = LogLevels.WARNING; + assertEquals(logger.levelName, "WARNING"); + assertEquals(logger.level, LogLevels.WARNING); + + logger.debug("debug2"); + logger.error("error2"); + logger.critical("critical2"); + assertEquals(testHandler.messages.length, 2); + assertEquals(testHandler.messages[0], "ERROR error2"); + assertEquals(testHandler.messages[1], "CRITICAL critical2"); + + testHandler.messages = []; + const setLevelName: LevelName = "CRITICAL"; + logger.levelName = setLevelName; + assertEquals(logger.levelName, "CRITICAL"); + assertEquals(logger.level, LogLevels.CRITICAL); + + logger.debug("debug3"); + logger.error("error3"); + logger.critical("critical3"); + assertEquals(testHandler.messages.length, 1); + assertEquals(testHandler.messages[0], "CRITICAL critical3"); + }, +}); + +Deno.test({ + name: "Loggers have loggerName to get logger name", + async fn() { + const testHandler = new TestHandler("DEBUG"); + await setup({ + handlers: { + test: testHandler, + }, + + loggers: { + namedA: { + level: "DEBUG", + handlers: ["test"], + }, + namedB: { + level: "DEBUG", + handlers: ["test"], + }, + }, + }); + + assertEquals(getLogger("namedA").loggerName, "namedA"); + assertEquals(getLogger("namedB").loggerName, "namedB"); + assertEquals(getLogger().loggerName, "default"); + assertEquals(getLogger("nonsetupname").loggerName, "nonsetupname"); + }, +}); + +Deno.test({ + name: "Logger has mutable handlers", + async fn() { + const testHandlerA = new TestHandler("DEBUG"); + const testHandlerB = new TestHandler("DEBUG"); + await setup({ + handlers: { + testA: testHandlerA, + testB: testHandlerB, + }, + + loggers: { + default: { + level: "DEBUG", + handlers: ["testA"], + }, + }, + }); + const logger: Logger = getLogger(); + logger.info("msg1"); + assertEquals(testHandlerA.messages.length, 1); + assertEquals(testHandlerA.messages[0], "INFO msg1"); + assertEquals(testHandlerB.messages.length, 0); + + logger.handlers = [testHandlerA, testHandlerB]; + + logger.info("msg2"); + assertEquals(testHandlerA.messages.length, 2); + assertEquals(testHandlerA.messages[1], "INFO msg2"); + assertEquals(testHandlerB.messages.length, 1); + assertEquals(testHandlerB.messages[0], "INFO msg2"); + + logger.handlers = [testHandlerB]; + + logger.info("msg3"); + assertEquals(testHandlerA.messages.length, 2); + assertEquals(testHandlerB.messages.length, 2); + assertEquals(testHandlerB.messages[1], "INFO msg3"); + + logger.handlers = []; + logger.info("msg4"); + assertEquals(testHandlerA.messages.length, 2); + assertEquals(testHandlerB.messages.length, 2); + }, +});