From d51c9d74857aca3c2f172609297266968bc7f809 Mon Sep 17 00:00:00 2001 From: Elizabeth Alexander Hunt Date: Mon, 12 May 2025 09:40:12 -0700 Subject: The big refactor TM --- u/trace/logger.ts | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 u/trace/logger.ts (limited to 'u/trace/logger.ts') diff --git a/u/trace/logger.ts b/u/trace/logger.ts new file mode 100644 index 0000000..a5739c8 --- /dev/null +++ b/u/trace/logger.ts @@ -0,0 +1,108 @@ +import { + isDebug, + type ITrace, + type ITraceWith, + type SideEffect, + type Supplier, +} from "@emprespresso/pengueno"; + +export interface ILogger { + log: (...args: unknown[]) => void; + debug: (...args: unknown[]) => void; + warn: (...args: unknown[]) => void; + error: (...args: unknown[]) => void; +} +export enum LogLevel { + UNKNOWN = "UNKNOWN", + INFO = "INFO", + WARN = "WARN", + DEBUG = "DEBUG", + ERROR = "ERROR", +} +const logLevelOrder: Array = [ + LogLevel.DEBUG, + LogLevel.INFO, + LogLevel.WARN, + LogLevel.ERROR, +]; +export const isLogLevel = (l: string): l is LogLevel => + logLevelOrder.some((level) => level === l); + +const defaultAllowedLevels = () => + [ + LogLevel.UNKNOWN, + ...(isDebug() ? [LogLevel.DEBUG] : []), + LogLevel.INFO, + LogLevel.WARN, + LogLevel.ERROR, + ] as Array; + +export const logWithLevel = ( + logger: ILogger, + level: LogLevel, +): SideEffect => { + switch (level) { + case LogLevel.UNKNOWN: + case LogLevel.INFO: + return logger.log; + case LogLevel.DEBUG: + return logger.debug; + case LogLevel.WARN: + return logger.warn; + case LogLevel.ERROR: + return logger.error; + } +}; + +export type LogTraceSupplier = ITraceWith>; + +const defaultTrace = () => `[${new Date().toISOString()}]`; +export const LoggerImpl = console; +export class LogTrace implements ITrace { + constructor( + private readonly logger: ILogger = LoggerImpl, + private readonly traces: Array = [defaultTrace], + private readonly allowedLevels: Supplier> = + defaultAllowedLevels, + private readonly defaultLevel: LogLevel = LogLevel.INFO, + ) { + } + + public addTrace(trace: LogTraceSupplier): ITrace { + return new LogTrace( + this.logger, + this.traces.concat(trace), + this.allowedLevels, + this.defaultLevel, + ); + } + + public trace(trace: LogTraceSupplier) { + const { line, level: _level } = this.foldTraces(this.traces.concat(trace)); + if (!this.allowedLevels().includes(_level)) return; + + const level = _level === LogLevel.UNKNOWN ? this.defaultLevel : _level; + logWithLevel(this.logger, level)(`[${level}]${line}`); + } + + private foldTraces(traces: Array) { + const { line, level } = traces.reduce( + (acc: { line: string; level: number }, t) => { + const val = typeof t === "function" ? t() : t; + if (isLogLevel(val)) { + return { + ...acc, + level: Math.max(logLevelOrder.indexOf(val), acc.level), + }; + } + const prefix = [ + acc.line, + val, + ].join(" "); + return { ...acc, prefix }; + }, + { line: "", level: -1 }, + ); + return { line, level: logLevelOrder[level] ?? LogLevel.UNKNOWN }; + } +} -- cgit v1.2.3-70-g09d2