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.
This commit is contained in:
Jonathan Bernard 2025-01-07 09:30:21 -06:00
parent 6b4173d636
commit a89a41520c

View File

@ -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 (typeof fmtMsg === "string") {
if (msg.error || msg.stacktrace) {
logMethod(fmtMsg, msg.error ?? msg.stacktrace);
} else {
logMethod(fmtMsg);
}
} else {
const { message, _error, _stacktrace, ...rest } = fmtMsg;
const summary = `${LogLevel[msg.level]} -- ${msg.scope}: ${
message ?? fmtMsg.method
}\n`;
if (msg.error || msg.stacktrace) {
logMethod(strMsg, msg.error ?? msg.stacktrace);
logMethod(summary, msg.error ?? msg.stacktrace, rest);
} else {
logMethod(strMsg);
logMethod(summary, rest);
}
}
}
}