diff options
author | Elizabeth Hunt <lizhunt@amazon.com> | 2025-05-14 18:02:34 -0700 |
---|---|---|
committer | Elizabeth Hunt <lizhunt@amazon.com> | 2025-05-14 18:03:15 -0700 |
commit | 3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4 (patch) | |
tree | bb44512bccceee43c57372a4ae325b5b70a6e192 /u/trace | |
parent | f316b4a015b5b2e2988b250b3c34bbb7f9994709 (diff) | |
download | ci-3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4.tar.gz ci-3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4.zip |
moar
Diffstat (limited to 'u/trace')
-rw-r--r-- | u/trace/itrace.ts | 68 | ||||
-rw-r--r-- | u/trace/logger.ts | 67 | ||||
-rw-r--r-- | u/trace/trace.ts | 40 |
3 files changed, 112 insertions, 63 deletions
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts index b483067..b9b750d 100644 --- a/u/trace/itrace.ts +++ b/u/trace/itrace.ts @@ -1,71 +1,95 @@ -import { Mapper, SideEffect } from "../fn/mod.ts"; +import type { Mapper, SideEffect } from "@emprespresso/pengueno"; -export interface ITrace<TracingW> { - addTrace: Mapper<TracingW, ITrace<TracingW>>; - trace: SideEffect<TracingW>; +// the "thing" every Trace writer must "trace()" +type BaseTraceWith = string; +export type ITraceWith<T> = BaseTraceWith | T; +export interface ITrace<TraceWith> { + addTrace: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>; + trace: SideEffect<ITraceWith<TraceWith>>; } -export type ITraceableTuple<T, Trace> = [T, Trace]; -export type ITraceableMapper<T, Trace, U, W = ITraceable<T, Trace>> = ( +export type ITraceableTuple<T, TraceWith> = [T, BaseTraceWith | TraceWith]; +export type ITraceableMapper< + T, + U, + TraceWith, + W = ITraceable<T, TraceWith>, +> = ( w: W, ) => U; -export interface ITraceable<T, Trace> { +export interface ITraceable<T, Trace = BaseTraceWith> { readonly item: T; readonly trace: ITrace<Trace>; move<U>(u: U): ITraceable<U, Trace>; map: <U>( - mapper: ITraceableMapper<T, Trace, U>, + mapper: ITraceableMapper<T, U, Trace>, ) => ITraceable<U, Trace>; bimap: <U>( - mapper: ITraceableMapper<T, Trace, ITraceableTuple<U, Trace>>, + mapper: ITraceableMapper<T, ITraceableTuple<U, Trace>, Trace>, ) => ITraceable<U, Trace>; - peek: (peek: ITraceableMapper<T, Trace, void>) => ITraceable<T, Trace>; + peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>; flatMap: <U>( - mapper: ITraceableMapper<T, Trace, ITraceable<U, Trace>>, + mapper: ITraceableMapper<T, ITraceable<U, Trace>, Trace>, ) => ITraceable<U, Trace>; flatMapAsync<U>( - mapper: ITraceableMapper<T, Trace, Promise<ITraceable<U, Trace>>>, + mapper: ITraceableMapper<T, Promise<ITraceable<U, Trace>>, Trace>, ): ITraceable<Promise<U>, Trace>; } -export class TraceableImpl<T, L> implements ITraceable<T, L> { +export class TraceableImpl<T, TraceWith> implements ITraceable<T, TraceWith> { protected constructor( readonly item: T, - readonly trace: ITrace<L>, + readonly trace: ITrace<TraceWith>, ) {} - public map<U>(mapper: ITraceableMapper<T, L, U>) { + public map<U>( + mapper: ITraceableMapper<T, U, TraceWith>, + ) { const result = mapper(this); return new TraceableImpl(result, this.trace); } public flatMap<U>( - mapper: ITraceableMapper<T, L, ITraceable<U, L>>, - ): ITraceable<U, L> { + mapper: ITraceableMapper< + T, + ITraceable<U, TraceWith>, + TraceWith + >, + ): ITraceable<U, TraceWith> { return mapper(this); } public flatMapAsync<U>( - mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>, - ): ITraceable<Promise<U>, L> { + mapper: ITraceableMapper< + T, + Promise<ITraceable<U, TraceWith>>, + TraceWith + >, + ): ITraceable<Promise<U>, TraceWith> { return new TraceableImpl( mapper(this).then(({ item }) => item), this.trace, ); } - public peek(peek: ITraceableMapper<T, L, void>) { + public peek(peek: ITraceableMapper<T, void, TraceWith>) { peek(this); return this; } - public move<Tt>(t: Tt): ITraceable<Tt, L> { + public move<Tt>(t: Tt): ITraceable<Tt, TraceWith> { return this.map(() => t); } - public bimap<U>(mapper: ITraceableMapper<T, L, ITraceableTuple<U, L>>) { + public bimap<U>( + mapper: ITraceableMapper< + T, + ITraceableTuple<U, TraceWith>, + TraceWith + >, + ) { const [item, trace] = mapper(this); return new TraceableImpl(item, this.trace.addTrace(trace)); } diff --git a/u/trace/logger.ts b/u/trace/logger.ts index 79da367..4f3c856 100644 --- a/u/trace/logger.ts +++ b/u/trace/logger.ts @@ -1,10 +1,9 @@ import { isDebug, - isObject, type ITrace, type SideEffect, type Supplier, -} from "@emprespresso/utils"; +} from "@emprespresso/pengueno"; export interface ILogger { log: (...args: unknown[]) => void; @@ -12,74 +11,88 @@ export interface ILogger { warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void; } -export type ILoggerLevel = "UNKNOWN" | "INFO" | "WARN" | "DEBUG" | "ERROR"; -const logLevelOrder: Array<ILoggerLevel> = ["DEBUG", "INFO", "WARN", "ERROR"]; +export enum LogLevel { + UNKNOWN = "UNKNOWN", + INFO = "INFO", + WARN = "WARN", + DEBUG = "DEBUG", + ERROR = "ERROR", +} +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 = () => [ - "UNKNOWN", - ...(isDebug() ? ["DEBUG"] : []), - "INFO", - "WARN", - "ERROR", - ] as Array<ILoggerLevel>; + LogLevel.UNKNOWN, + ...(isDebug() ? [LogLevel.DEBUG] : []), + LogLevel.INFO, + LogLevel.WARN, + LogLevel.ERROR, + ] as Array<LogLevel>; export const logWithLevel = ( logger: ILogger, - level: ILoggerLevel, + level: LogLevel, ): SideEffect<unknown> => { switch (level) { - case "UNKNOWN": - case "INFO": + case LogLevel.UNKNOWN: + case LogLevel.INFO: return logger.log; - case "DEBUG": + case LogLevel.DEBUG: return logger.debug; - case "WARN": + case LogLevel.WARN: return logger.warn; - case "ERROR": + case LogLevel.ERROR: return logger.error; } }; export const LoggerImpl = console; -export type LogTraceSupplier = string | Supplier<string> | { - level: ILoggerLevel; -}; +export type LogTraceSupplier = string | Supplier<string>; const foldTraces = (traces: Array<LogTraceSupplier>) => { const { line, level } = traces.reduce( (acc: { line: string; level: number }, t) => { - if (isObject(t) && "level" in t) { + const val = typeof t === "function" ? t() : t; + if (isLogLevel(val)) { return { ...acc, - level: Math.max(logLevelOrder.indexOf(t.level), acc.level), + level: Math.max(logLevelOrder.indexOf(val), acc.level), }; } const prefix = [ acc.line, - typeof t === "function" ? t() : t, + val, ].join(" "); return { ...acc, prefix }; }, { line: "", level: -1 }, ); - return { line, level: logLevelOrder[level] ?? "UNKNOWN" }; + return { line, level: logLevelOrder[level] ?? LogLevel.UNKNOWN }; }; const defaultTrace = () => `[${new Date().toISOString()}]`; export const LogTrace = ( logger: ILogger, traces: Array<LogTraceSupplier> = [defaultTrace], - allowedLevels: Supplier<Array<ILoggerLevel>> = defaultAllowedLevels, - defaultLevel: ILoggerLevel = "INFO", + allowedLevels: Supplier<Array<LogLevel>> = defaultAllowedLevels, + defaultLevel: LogLevel = LogLevel.INFO, ): ITrace<LogTraceSupplier> => { return { addTrace: (trace: LogTraceSupplier) => - LogTrace(logger, traces.concat(trace)), + LogTrace(logger, traces.concat(trace), allowedLevels, defaultLevel), trace: (trace: LogTraceSupplier) => { const { line, level: _level } = foldTraces(traces.concat(trace)); if (!allowedLevels().includes(_level)) return; - const level = _level === "UNKNOWN" ? defaultLevel : _level; + + const level = _level === LogLevel.UNKNOWN ? defaultLevel : _level; logWithLevel(logger, level)(`[${level}]${line}`); }, }; diff --git a/u/trace/trace.ts b/u/trace/trace.ts index 5d5c59b..1d3d2d8 100644 --- a/u/trace/trace.ts +++ b/u/trace/trace.ts @@ -1,31 +1,43 @@ -import type { Callable } from "@emprespresso/utils"; import { + type Callable, type ITraceableMapper, type ITraceableTuple, + LoggerImpl, + LogTrace, + type LogTraceSupplier, TraceableImpl, - TraceableLogger, -} from "./mod.ts"; +} from "@emprespresso/pengueno"; -export class Traceable<T> extends TraceableImpl<T, TraceableLogger> { +export class LogTraceable<T> extends TraceableImpl<T, LogTraceSupplier> { static from<T>(t: T) { - return new Traceable(t, new TraceableLogger()); + return new LogTraceable(t, LogTrace(LoggerImpl)); } +} - static withFunctionTrace<F extends Callable, T>( +export class TraceUtil { + static withFunctionTrace<F extends Callable, T, Trace>( f: F, - ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> { - return (t) => [t.item, f.name]; + ): ITraceableMapper< + T, + ITraceableTuple<T, Trace>, + Trace + > { + return (t) => [t.item, `[${f.name}]`]; } - static withClassTrace<C extends object, T>( + static withClassTrace<C extends object, T, Trace>( c: C, - ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> { - return (t) => [t.item, c.constructor.name]; + ): ITraceableMapper< + T, + ITraceableTuple<T, Trace>, + Trace + > { + return (t) => [t.item, `[${c.constructor.name}]`]; } - static promiseify<T, U>( - mapper: ITraceableMapper<T, TraceableLogger, U>, - ): ITraceableMapper<Promise<T>, TraceableLogger, Promise<U>> { + static promiseify<T, U, Trace>( + mapper: ITraceableMapper<T, U, Trace>, + ): ITraceableMapper<Promise<T>, Promise<U>, Trace> { return (traceablePromise) => traceablePromise.flatMapAsync(async (t) => t.move(await t.item).map(mapper) |