summaryrefslogtreecommitdiff
path: root/u/trace/logger.ts
diff options
context:
space:
mode:
Diffstat (limited to 'u/trace/logger.ts')
-rw-r--r--u/trace/logger.ts169
1 files changed, 96 insertions, 73 deletions
diff --git a/u/trace/logger.ts b/u/trace/logger.ts
index 8e62b02..29cabd4 100644
--- a/u/trace/logger.ts
+++ b/u/trace/logger.ts
@@ -2,89 +2,27 @@ 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;
- sys: (...args: unknown[]) => void;
-}
-export enum LogLevel {
- UNKNOWN = "UNKNOWN",
- INFO = "INFO",
- WARN = "WARN",
- DEBUG = "DEBUG",
- ERROR = "ERROR",
- SYS = "SYS",
-}
-const logLevelOrder: Array<LogLevel> = [
- LogLevel.DEBUG,
- LogLevel.INFO,
- LogLevel.WARN,
- LogLevel.ERROR,
-];
-export const isLogLevel = (l: string): l is LogLevel =>
- logLevelOrder.some((level) => <string>level === l);
-
-const defaultAllowedLevels = () =>
- [
- LogLevel.UNKNOWN,
- ...(isDebug() ? [LogLevel.DEBUG] : []),
- LogLevel.INFO,
- LogLevel.WARN,
- LogLevel.ERROR,
- LogLevel.SYS,
- ] as Array<LogLevel>;
-
-export const logWithLevel = (
- logger: ILogger,
- level: LogLevel,
-): SideEffect<unknown> => {
- 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;
- case LogLevel.SYS:
- return logger.sys;
- }
-};
-
-export type LogTraceSupplier = ITraceWith<Supplier<string>>;
-
-const defaultTrace = () => `[${new Date().toISOString()}]`;
-export const LoggerImpl = {
- log: console.log,
- debug: console.debug,
- warn: console.warn,
- error: console.error,
- sys: console.log,
-};
+export type LogTraceSupplier = ITraceWith<Supplier<string> | Error>;
+const defaultTrace = () => `TimeStamp = ${new Date().toISOString()}`;
export class LogTrace implements ITrace<LogTraceSupplier> {
constructor(
- private readonly logger: ILogger = LoggerImpl,
+ private readonly logger: ILogger = new LoggerImpl(),
private readonly traces: Array<LogTraceSupplier> = [defaultTrace],
+ private readonly defaultLevel: LogLevel = LogLevel.INFO,
private readonly allowedLevels: Supplier<
Array<LogLevel>
> = defaultAllowedLevels,
- private readonly defaultLevel: LogLevel = LogLevel.INFO,
) {}
public addTrace(trace: LogTraceSupplier): ITrace<LogTraceSupplier> {
return new LogTrace(
this.logger,
this.traces.concat(trace),
- this.allowedLevels,
this.defaultLevel,
+ this.allowedLevels,
);
}
@@ -95,11 +33,7 @@ export class LogTrace implements ITrace<LogTraceSupplier> {
if (!this.allowedLevels().includes(_level)) return;
const level = _level === LogLevel.UNKNOWN ? this.defaultLevel : _level;
- const line = { level, message: traces.at(-1), traces: traces.slice(0, -1) };
- logWithLevel(
- this.logger,
- level,
- )(line);
+ this.logger.log(level, ...traces);
}
private foldTraces(_traces: Array<LogTraceSupplier>) {
@@ -111,10 +45,99 @@ export class LogTrace implements ITrace<LogTraceSupplier> {
.reduce((acc, level) => Math.max(logLevelOrder.indexOf(level), acc), -1);
const level = logLevelOrder[_level] ?? LogLevel.UNKNOWN;
- const traces = _logTraces.filter((trace) => !isLogLevel(trace));
+ const traces = _logTraces.filter((trace) => !isLogLevel(trace)).map((trace) => {
+ if (typeof trace === 'object') {
+ return `TracedException.Name = ${trace.name}, TracedException.Message = ${trace.message}, TracedException.Stack = ${trace.stack}`
+ }
+ return trace;
+ });
return {
level,
traces,
};
}
}
+
+export enum LogLevel {
+ UNKNOWN = "UNKNOWN",
+ INFO = "INFO",
+ WARN = "WARN",
+ DEBUG = "DEBUG",
+ ERROR = "ERROR",
+ SYS = "SYS",
+}
+const logLevelOrder: Array<LogLevel> = [
+ LogLevel.DEBUG,
+ LogLevel.INFO,
+ LogLevel.WARN,
+ LogLevel.ERROR,
+ LogLevel.SYS,
+];
+export const isLogLevel = (l: unknown): l is LogLevel =>
+ typeof l === "string" && logLevelOrder.some((level) => level === l);
+
+
+const defaultAllowedLevels = () =>
+ [
+ LogLevel.UNKNOWN,
+ ...(isDebug() ? [LogLevel.DEBUG] : []),
+ LogLevel.INFO,
+ LogLevel.WARN,
+ LogLevel.ERROR,
+ LogLevel.SYS,
+ ] as Array<LogLevel>;
+
+export interface ILogger {
+ readonly log: (level: LogLevel, ...args: string[]) => void;
+}
+class LoggerImpl implements ILogger {
+ private readonly textEncoder = new TextEncoder();
+
+ public log(level: LogLevel, ...msg: string[]) {
+ const message = JSON.stringify({
+ level,
+ msg,
+ }, null, 2);
+ const styled = `${this.getStyle(level)}${message}${ANSI.RESET}\n`;
+ this.getStream(level).writeSync(this.textEncoder.encode(styled));
+ }
+
+ private getStream(level: LogLevel) {
+ if (level === LogLevel.ERROR) {
+ return Deno.stderr;
+ }
+ return Deno.stdout;
+ }
+
+ private getStyle(level: LogLevel) {
+ switch (level) {
+ case LogLevel.UNKNOWN:
+ case LogLevel.INFO:
+ return `${ANSI.MAGENTA}`;
+ case LogLevel.DEBUG:
+ return `${ANSI.CYAN}`;
+ case LogLevel.WARN:
+ return `${ANSI.BRIGHT_YELLOW}`;
+ case LogLevel.ERROR:
+ return `${ANSI.BRIGHT_RED}`;
+ case LogLevel.SYS:
+ return `${ANSI.DIM}${ANSI.BLUE}`;
+ }
+ }
+}
+
+export const ANSI = {
+ RESET: "\x1b[0m",
+ BOLD: "\x1b[1m",
+ DIM: "\x1b[2m",
+ RED: "\x1b[31m",
+ GREEN: "\x1b[32m",
+ YELLOW: "\x1b[33m",
+ BLUE: "\x1b[34m",
+ MAGENTA: "\x1b[35m",
+ CYAN: "\x1b[36m",
+ WHITE: "\x1b[37m",
+ BRIGHT_RED: "\x1b[91m",
+ BRIGHT_YELLOW: "\x1b[93m",
+ GRAY: "\x1b[90m",
+};