Allow LogMessageFormatter to return FlattenedLogMessages.

Originally the idea was that a log formatter should turn the LogMessage
into a string that can be appended via a LogAppender. However, all of
the default LogAppenders can handle objects. In particular, the
ConsoleLogAppender writes to the browser console which offers an
interactive UI experience when logging raw objects.

For LogAppenders that can only manage text, it seems an acceptable
design decision to require users to provide a LogMessageFormatter that
returns a string, or accept some sane default like JSON.stringify if
their formatter returns objects.
This commit is contained in:
Jonathan Bernard 2025-01-07 08:48:37 -06:00
parent 13941840ce
commit 756ebf3c78
2 changed files with 6 additions and 5 deletions

View File

@ -1,14 +1,14 @@
import {
flattenMessage,
LogLevel,
LogMessage,
LogMessageFormatter,
structuredLogMessageFormatter
} from './log-message';
import { LogAppender } from './log-appender';
export class ConsoleLogAppender implements LogAppender {
public threshold = LogLevel.ALL;
public formatter = structuredLogMessageFormatter;
public formatter: LogMessageFormatter = flattenMessage
constructor(threshold?: LogLevel, formatter?: LogMessageFormatter) {
if (threshold) {

View File

@ -50,12 +50,12 @@ export type FlattenedLogMessage = Record<string, unknown>;
*
* Should result after flattening in a structured log message like:
* ```json
* {"scope":"example","level":4,"foo":"bar","baz":"qux","timestamp":"2020-01-01T00:00:00.000Z"}
* {"scope":"example","level":"INFO","foo":"bar","baz":"qux","timestamp":"2020-01-01T00:00:00.000Z"}
* ```
*/
export function flattenMessage(msg: LogMessage): FlattenedLogMessage {
if (typeof msg.message === 'string') {
return { ...msg };
return { ...msg, level: LogLevel[msg.level] };
} else {
const { message, ...rest } = msg;
return {
@ -67,10 +67,11 @@ export function flattenMessage(msg: LogMessage): FlattenedLogMessage {
'timestamp',
]),
...rest,
level: LogLevel[msg.level],
};
}
}
export type LogMessageFormatter = (msg: LogMessage) => string;
export type LogMessageFormatter = (msg: LogMessage) => string | FlattenedLogMessage;
export function structuredLogMessageFormatter(msg: LogMessage): string {
return JSON.stringify(flattenMessage(msg));