From a89a41520c62b0af2f05eeb91e21b05a4979d4bf Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Tue, 7 Jan 2025 09:30:21 -0600 Subject: [PATCH] ConsoleLogAppender writes a human-readable summary when logging structured data. Taking advantage of the new LogMessageFormatter return type, the ConsoleLogAppender logs the formatted message as-is if it is a string, but when processing structured data inserts a string summary consisting of the message level, scope, and message summary or method. The full object is still logged to the console as well for inspection. --- src/console-log-appender.ts | 44 +++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/console-log-appender.ts b/src/console-log-appender.ts index 8c67eea..8215f7e 100644 --- a/src/console-log-appender.ts +++ b/src/console-log-appender.ts @@ -3,12 +3,23 @@ import { LogLevel, LogMessage, LogMessageFormatter, -} from './log-message'; -import { LogAppender } from './log-appender'; +} from "./log-message"; +import { LogAppender } from "./log-appender"; +/** + * A log appender that writes log messages to the console. The behavior of the + * log appender can be configured with a threshold level and a message + * formatter. + * + * When the message formatter returns a string value, that value is logged to + * the console as-is. When the message formatter returns an object, a summary + * string is logged to the console, followed by the object itself. This allows + * logs to be easily read in the console, while still providing the structured + * data for inspection in the browser's developer tools. + */ export class ConsoleLogAppender implements LogAppender { public threshold = LogLevel.ALL; - public formatter: LogMessageFormatter = flattenMessage + public formatter: LogMessageFormatter = flattenMessage; constructor(threshold?: LogLevel, formatter?: LogMessageFormatter) { if (threshold) { @@ -27,17 +38,13 @@ export class ConsoleLogAppender implements LogAppender { let logMethod = console.log; switch (msg.level) { case LogLevel.ALL: - logMethod = console.log; - break; case LogLevel.TRACE: + case LogLevel.LOG: logMethod = console.log; break; case LogLevel.DEBUG: logMethod = console.debug; break; - case LogLevel.LOG: - logMethod = console.log; - break; case LogLevel.INFO: logMethod = console.info; break; @@ -50,12 +57,25 @@ export class ConsoleLogAppender implements LogAppender { break; } - const strMsg = this.formatter(msg); + const fmtMsg = this.formatter(msg); - if (msg.error || msg.stacktrace) { - logMethod(strMsg, msg.error ?? msg.stacktrace); + if (typeof fmtMsg === "string") { + if (msg.error || msg.stacktrace) { + logMethod(fmtMsg, msg.error ?? msg.stacktrace); + } else { + logMethod(fmtMsg); + } } else { - logMethod(strMsg); + const { message, _error, _stacktrace, ...rest } = fmtMsg; + const summary = `${LogLevel[msg.level]} -- ${msg.scope}: ${ + message ?? fmtMsg.method + }\n`; + + if (msg.error || msg.stacktrace) { + logMethod(summary, msg.error ?? msg.stacktrace, rest); + } else { + logMethod(summary, rest); + } } } }