summaryrefslogtreecommitdiff
path: root/u/trace
diff options
context:
space:
mode:
authorElizabeth Hunt <lizhunt@amazon.com>2025-05-14 18:02:34 -0700
committerElizabeth Hunt <lizhunt@amazon.com>2025-05-14 18:03:15 -0700
commit3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4 (patch)
treebb44512bccceee43c57372a4ae325b5b70a6e192 /u/trace
parentf316b4a015b5b2e2988b250b3c34bbb7f9994709 (diff)
downloadci-3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4.tar.gz
ci-3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4.zip
moar
Diffstat (limited to 'u/trace')
-rw-r--r--u/trace/itrace.ts68
-rw-r--r--u/trace/logger.ts67
-rw-r--r--u/trace/trace.ts40
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)