diff options
Diffstat (limited to 'u/trace')
-rw-r--r-- | u/trace/index.ts | 5 | ||||
-rw-r--r-- | u/trace/itrace.ts | 91 | ||||
-rw-r--r-- | u/trace/log/ansi.ts | 15 | ||||
-rw-r--r-- | u/trace/log/index.ts | 5 | ||||
-rw-r--r-- | u/trace/log/level.ts | 19 | ||||
-rw-r--r-- | u/trace/log/logger.ts | 5 | ||||
-rw-r--r-- | u/trace/log/pretty_json_console.ts | 39 | ||||
-rw-r--r-- | u/trace/log/trace.ts | 60 | ||||
-rw-r--r-- | u/trace/metric/emittable.ts | 18 | ||||
-rw-r--r-- | u/trace/metric/index.ts | 41 | ||||
-rw-r--r-- | u/trace/metric/metric.ts | 54 | ||||
-rw-r--r-- | u/trace/metric/trace.ts | 59 | ||||
-rw-r--r-- | u/trace/trace.ts | 77 | ||||
-rw-r--r-- | u/trace/util.ts | 59 |
14 files changed, 0 insertions, 547 deletions
diff --git a/u/trace/index.ts b/u/trace/index.ts deleted file mode 100644 index 332fb52..0000000 --- a/u/trace/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './itrace.js'; -export * from './metric/index.js'; -export * from './log/index.js'; -export * from './trace.js'; -export * from './util.js'; diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts deleted file mode 100644 index e2019fa..0000000 --- a/u/trace/itrace.ts +++ /dev/null @@ -1,91 +0,0 @@ -import type { Mapper, SideEffect, Supplier } from '@emprespresso/pengueno'; - -/** - * the "thing" every Trace writer must "trace()". - */ -type BaseTraceWith = string; -export type ITraceWith<T> = BaseTraceWith | T; -export interface ITrace<TraceWith> { - /** - * creates a new trace scope which inherits from this trace. - */ - traceScope: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>; - - /** - * does the tracing. - */ - trace: SideEffect<ITraceWith<TraceWith>>; -} - -export type ITraceableTuple<T, TraceWith> = { item: T; trace: BaseTraceWith | TraceWith }; -export type ITraceableMapper<T, _T, TraceWith> = (w: ITraceable<T, TraceWith>) => _T; - -export interface ITraceable<T, Trace = BaseTraceWith> { - readonly trace: ITrace<Trace>; - readonly get: Supplier<T>; - - readonly move: <_T>(t: _T) => ITraceable<_T, Trace>; - readonly map: <_T>(mapper: ITraceableMapper<T, _T, Trace>) => ITraceable<_T, Trace>; - readonly bimap: <_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) => ITraceable<_T, Trace>; - readonly coExtend: <_T>(mapper: ITraceableMapper<T, Array<_T>, Trace>) => Array<ITraceable<_T, Trace>>; - readonly peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>; - - readonly traceScope: (mapper: ITraceableMapper<T, Trace, Trace>) => ITraceable<T, Trace>; - - readonly flatMap: <_T>(mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>) => ITraceable<_T, Trace>; - readonly flatMapAsync: <_T>( - mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>, - ) => ITraceable<Promise<_T>, Trace>; -} - -export class TraceableImpl<T, Trace> implements ITraceable<T, Trace> { - protected constructor( - private readonly item: T, - public readonly trace: ITrace<Trace>, - ) {} - - public map<_T>(mapper: ITraceableMapper<T, _T, Trace>) { - const result = mapper(this); - return new TraceableImpl(result, this.trace); - } - - public coExtend<_T>(mapper: ITraceableMapper<T, Array<_T>, Trace>): Array<ITraceable<_T, Trace>> { - const results = mapper(this); - return Array.from(results).map((result) => this.move(result)); - } - - public flatMap<_T>(mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>): ITraceable<_T, Trace> { - return mapper(this); - } - - public flatMapAsync<_T>( - mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>, - ): ITraceable<Promise<_T>, Trace> { - return new TraceableImpl( - mapper(this).then((t) => t.get()), - this.trace, - ); - } - - public traceScope(mapper: ITraceableMapper<T, Trace, Trace>): ITraceable<T, Trace> { - return new TraceableImpl(this.get(), this.trace.traceScope(mapper(this))); - } - - public peek(peek: ITraceableMapper<T, void, Trace>) { - peek(this); - return this; - } - - public move<_T>(t: _T): ITraceable<_T, Trace> { - return this.map(() => t); - } - - public bimap<_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) { - const { item, trace: _trace } = mapper(this); - return this.move(item).traceScope(() => <Trace>_trace); - } - - public get() { - return this.item; - } -} diff --git a/u/trace/log/ansi.ts b/u/trace/log/ansi.ts deleted file mode 100644 index 7ff16a3..0000000 --- a/u/trace/log/ansi.ts +++ /dev/null @@ -1,15 +0,0 @@ -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', -}; diff --git a/u/trace/log/index.ts b/u/trace/log/index.ts deleted file mode 100644 index 670e333..0000000 --- a/u/trace/log/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './ansi.js'; -export * from './level.js'; -export * from './logger.js'; -export * from './pretty_json_console.js'; -export * from './trace.js'; diff --git a/u/trace/log/level.ts b/u/trace/log/level.ts deleted file mode 100644 index 027dd71..0000000 --- a/u/trace/log/level.ts +++ /dev/null @@ -1,19 +0,0 @@ -export enum LogLevel { - UNKNOWN = 'UNKNOWN', - INFO = 'INFO', - WARN = 'WARN', - DEBUG = 'DEBUG', - ERROR = 'ERROR', - SYS = 'SYS', -} - -export 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); diff --git a/u/trace/log/logger.ts b/u/trace/log/logger.ts deleted file mode 100644 index 3ced60a..0000000 --- a/u/trace/log/logger.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { LogLevel } from './level.js'; - -export interface ILogger { - readonly log: (level: LogLevel, ...args: string[]) => void; -} diff --git a/u/trace/log/pretty_json_console.ts b/u/trace/log/pretty_json_console.ts deleted file mode 100644 index 758af51..0000000 --- a/u/trace/log/pretty_json_console.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ANSI, LogLevel, ILogger } from './index.js'; - -export class PrettyJsonConsoleLogger implements ILogger { - public log(level: LogLevel, ...trace: string[]) { - const message = JSON.stringify( - { - level, - trace, - }, - null, - 4, - ); - const styled = `${this.getStyle(level)}${message}${ANSI.RESET}\n`; - this.getStream(level)(styled); - } - - private getStream(level: LogLevel) { - if (level === LogLevel.ERROR) { - return console.error; - } - return console.log; - } - - 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}`; - } - } -} diff --git a/u/trace/log/trace.ts b/u/trace/log/trace.ts deleted file mode 100644 index 3f9f1b2..0000000 --- a/u/trace/log/trace.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { isDebug, ITrace, ITraceWith, memoize, Supplier } from '@emprespresso/pengueno'; -import { ILogger, isLogLevel, LogLevel, logLevelOrder, PrettyJsonConsoleLogger } from './index.js'; - -export type LogTraceSupplier = ITraceWith<Supplier<string>> | ITraceWith<Error>; - -export class LogTrace implements ITrace<LogTraceSupplier> { - constructor( - private readonly logger: ILogger = new PrettyJsonConsoleLogger(), - private readonly traces: Array<LogTraceSupplier> = [defaultTrace], - private readonly defaultLevel: LogLevel = LogLevel.INFO, - private readonly allowedLevels: Supplier<Set<LogLevel>> = defaultAllowedLevelsSupplier, - ) {} - - public traceScope(trace: LogTraceSupplier): ITrace<LogTraceSupplier> { - return new LogTrace(this.logger, this.traces.concat(trace), this.defaultLevel, this.allowedLevels); - } - - public trace(trace: LogTraceSupplier) { - const { traces, level: _level } = this.foldTraces(this.traces.concat(trace)); - if (!this.allowedLevels().has(_level)) return; - - const level = _level === LogLevel.UNKNOWN ? this.defaultLevel : _level; - this.logger.log(level, ...traces); - } - - private foldTraces(_traces: Array<LogTraceSupplier>) { - const _logTraces = _traces.map((trace) => (typeof trace === 'function' ? trace() : trace)); - const _level = _logTraces - .filter((trace) => isLogLevel(trace)) - .reduce((acc, level) => Math.max(logLevelOrder.indexOf(level), acc), -1); - const level = logLevelOrder[_level] ?? LogLevel.UNKNOWN; - - 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, - }; - } -} - -const defaultTrace = () => `TimeStamp = ${new Date().toISOString()}`; -const defaultAllowedLevels = memoize( - (isDebug: boolean) => - new Set([ - LogLevel.UNKNOWN, - ...(isDebug ? [LogLevel.DEBUG] : []), - LogLevel.INFO, - LogLevel.WARN, - LogLevel.ERROR, - LogLevel.SYS, - ]), -); -const defaultAllowedLevelsSupplier = () => defaultAllowedLevels(isDebug()); diff --git a/u/trace/metric/emittable.ts b/u/trace/metric/emittable.ts deleted file mode 100644 index f3441ec..0000000 --- a/u/trace/metric/emittable.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { IEmittableMetric, MetricValue, MetricValueTag, Unit } from './index.js'; - -export class EmittableMetric implements IEmittableMetric { - constructor( - public readonly name: string, - public readonly unit: Unit, - ) {} - - public withValue(value: number): MetricValue { - return { - name: this.name, - unit: this.unit, - emissionTimestamp: Date.now(), - value, - _tag: MetricValueTag, - }; - } -} diff --git a/u/trace/metric/index.ts b/u/trace/metric/index.ts deleted file mode 100644 index 72c37d2..0000000 --- a/u/trace/metric/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { isTagged, Tagged, type Mapper } from '@emprespresso/pengueno'; - -export enum Unit { - COUNT = 'COUNT', - MILLISECONDS = 'MILLISECONDS', -} - -export const MetricValueTag = 'MetricValue' as const; -export type MetricValueTag = typeof MetricValueTag; -export const isMetricValue = (t: unknown): t is MetricValue => isTagged(t, MetricValueTag); -export interface MetricValue extends Tagged<MetricValueTag> { - readonly name: string; - readonly unit: Unit; - readonly value: number; - readonly emissionTimestamp: number; -} - -export interface IEmittableMetric { - readonly name: string; - readonly unit: Unit; - readonly withValue: Mapper<number, MetricValue>; -} - -export const IMetricTag = 'IMetric' as const; -export type IMetricTag = typeof IMetricTag; -export const isIMetric = (t: unknown): t is IMetric => isTagged(t, IMetricTag); -export interface IMetric extends Tagged<IMetricTag> { - readonly count: IEmittableMetric; - readonly time: IEmittableMetric; - readonly parent: undefined | IMetric; -} - -export interface IResultMetric extends IMetric { - readonly failure: IMetric; - readonly success: IMetric; - readonly warn: IMetric; -} - -export * from './emittable.js'; -export * from './metric.js'; -export * from './trace.js'; diff --git a/u/trace/metric/metric.ts b/u/trace/metric/metric.ts deleted file mode 100644 index 8ef339f..0000000 --- a/u/trace/metric/metric.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { EmittableMetric, IMetric, IMetricTag, IResultMetric, Unit } from './index.js'; - -class _Tagged { - protected constructor(public readonly _tag = IMetricTag) {} -} - -export class Metric extends _Tagged implements IMetric { - private static DELIM = '.'; - - protected constructor( - public readonly name: string, - public readonly parent: undefined | IMetric = undefined, - public readonly count = new EmittableMetric(Metric.join(name, 'count'), Unit.COUNT), - public readonly time = new EmittableMetric(Metric.join(name, 'time'), Unit.MILLISECONDS), - ) { - super(); - } - - public child(_name: string): Metric { - const childName = Metric.join(this.name, _name); - return new Metric(childName, this); - } - - public asResult() { - return ResultMetric.from(this); - } - - static join(...name: Array<string>) { - return name.join(Metric.DELIM); - } - - static fromName(name: string): Metric { - return new Metric(name); - } -} - -export class ResultMetric extends Metric implements IResultMetric { - protected constructor( - public readonly name: string, - public readonly parent: undefined | IMetric = undefined, - public readonly failure: IMetric, - public readonly success: IMetric, - public readonly warn: IMetric, - ) { - super(name, parent); - } - - static from(metric: Metric) { - const failure = metric.child('failure'); - const success = metric.child('success'); - const warn = metric.child('warn'); - return new ResultMetric(metric.name, metric.parent, failure, success, warn); - } -} diff --git a/u/trace/metric/trace.ts b/u/trace/metric/trace.ts deleted file mode 100644 index 0c5fe37..0000000 --- a/u/trace/metric/trace.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { IMetric, isIMetric, isMetricValue, ITrace, ITraceWith, MetricValue, SideEffect } from '@emprespresso/pengueno'; - -export type MetricsTraceSupplier = - | ITraceWith<IMetric | MetricValue | undefined> - | Array<ITraceWith<IMetric | MetricValue | undefined>>; -export const isMetricsTraceSupplier = (t: unknown): t is MetricsTraceSupplier => - isMetricValue(t) || isIMetric(t) || (Array.isArray(t) && t.every((_m) => isMetricValue(_m) || isIMetric(_m))); - -export class MetricsTrace implements ITrace<MetricsTraceSupplier> { - constructor( - private readonly metricConsumer: SideEffect<Array<MetricValue>>, - private readonly activeTraces: ReadonlyMap<IMetric, number> = new Map(), - private readonly completedTraces: ReadonlySet<IMetric> = new Set(), - ) {} - - public traceScope(trace: MetricsTraceSupplier): MetricsTrace { - const now = Date.now(); - const metricsToTrace = (Array.isArray(trace) ? trace : [trace]).filter(isIMetric); - - const initialTraces = new Map(metricsToTrace.map((metric) => [metric, now])); - - return new MetricsTrace(this.metricConsumer, initialTraces); - } - - public trace(metrics: MetricsTraceSupplier): MetricsTrace { - if (!metrics || typeof metrics === 'string') { - return this; - } - - const now = Date.now(); - const allMetrics = Array.isArray(metrics) ? metrics : [metrics]; - - // partition the incoming metrics - const valuesToEmit = allMetrics.filter(isMetricValue); - const traceableMetrics = allMetrics.filter(isIMetric); - - const metricsToStart = traceableMetrics.filter((m) => !this.activeTraces.has(m)); - const metricsToEnd = traceableMetrics.filter((m) => this.activeTraces.has(m) && !this.completedTraces.has(m)); - - // the new metrics to emit based on traces ending *now* - const endedMetricValues = metricsToEnd.flatMap((metric) => [ - metric.count.withValue(1.0), - metric.time.withValue(now - this.activeTraces.get(metric)!), - ]); - - const allMetricsToEmit = [...valuesToEmit, ...endedMetricValues]; - if (allMetricsToEmit.length > 0) { - this.metricConsumer(allMetricsToEmit); - } - - // the next immutable state - const nextActiveTraces = new Map([ - ...this.activeTraces, - ...metricsToStart.map((m): [IMetric, number] => [m, now]), - ]); - const nextCompletedTraces = new Set([...this.completedTraces, ...metricsToEnd]); - return new MetricsTrace(this.metricConsumer, nextActiveTraces, nextCompletedTraces); - } -} diff --git a/u/trace/trace.ts b/u/trace/trace.ts deleted file mode 100644 index bde83a3..0000000 --- a/u/trace/trace.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { - isMetricsTraceSupplier, - type ITrace, - type ITraceable, - type ITraceWith, - LogLevel, - LogTrace, - type LogTraceSupplier, - MetricsTrace, - type MetricsTraceSupplier, - type MetricValue, - TraceableImpl, -} from './index.js'; - -export class LogTraceable<T> extends TraceableImpl<T, LogTraceSupplier> { - public static LogTrace = new LogTrace(); - static of<T>(t: T) { - return new LogTraceable(t, LogTraceable.LogTrace); - } -} - -const getEmbeddedMetricConsumer = (logTrace: ITrace<LogTraceSupplier>) => (metrics: Array<MetricValue>) => { - if (metrics.length === 0) return; - logTrace.traceScope(LogLevel.SYS).trace(`Metrics = <metrics>${JSON.stringify(metrics)}</metrics>`); -}; - -export class EmbeddedMetricsTraceable<T> extends TraceableImpl<T, MetricsTraceSupplier> { - public static MetricsTrace = new MetricsTrace(getEmbeddedMetricConsumer(LogTraceable.LogTrace)); - - static of<T>(t: T, metricsTrace = EmbeddedMetricsTraceable.MetricsTrace) { - return new EmbeddedMetricsTraceable(t, metricsTrace); - } -} - -export type LogMetricTraceSupplier = ITraceWith<LogTraceSupplier | MetricsTraceSupplier>; -export class LogMetricTrace implements ITrace<LogMetricTraceSupplier> { - constructor( - private logTrace: ITrace<LogTraceSupplier>, - private metricsTrace: ITrace<MetricsTraceSupplier>, - ) {} - - // public traceScope(trace: LogTraceSupplier | MetricsTraceSupplier): LogMetricTrace { - // if (isMetricsTraceSupplier(trace)) { - // this.metricsTrace = this.metricsTrace.traceScope(trace); - // return this; - // } - // this.logTrace = this.logTrace.traceScope(trace); - // return this; - // } - public traceScope(trace: LogTraceSupplier | MetricsTraceSupplier): LogMetricTrace { - if (isMetricsTraceSupplier(trace)) { - return new LogMetricTrace(this.logTrace, this.metricsTrace.traceScope(trace)); - } - return new LogMetricTrace(this.logTrace.traceScope(trace), this.metricsTrace); - } - - public trace(trace: LogTraceSupplier | MetricsTraceSupplier) { - if (isMetricsTraceSupplier(trace)) { - this.metricsTrace.trace(trace); - return this; - } - this.logTrace.trace(trace); - return this; - } -} - -export class LogMetricTraceable<T> extends TraceableImpl<T, MetricsTraceSupplier | LogTraceSupplier> { - static ofLogTraceable<T>(t: ITraceable<T, LogTraceSupplier>) { - const metricsTrace = new MetricsTrace(getEmbeddedMetricConsumer(t.trace)); - return new LogMetricTraceable(t.get(), new LogMetricTrace(t.trace, metricsTrace)); - } - - static of<T>(t: T) { - const logTrace = LogTraceable.of(t); - return LogMetricTraceable.ofLogTraceable(logTrace); - } -} diff --git a/u/trace/util.ts b/u/trace/util.ts deleted file mode 100644 index ec67571..0000000 --- a/u/trace/util.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - IEither, - IMetric, - isEither, - ITraceable, - ITraceWith, - LogLevel, - ResultMetric, - type Callable, - type ITraceableMapper, -} from '@emprespresso/pengueno'; - -export class TraceUtil { - 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.get()).map(mapper)).get(); - } - - static traceResultingEither<TErr, TOk, Trace>( - metric?: ResultMetric, - warnOnFailure = false, - ): ITraceableMapper<IEither<TErr, TOk>, ITraceable<IEither<TErr, TOk>, Trace>, Trace> { - return (t) => { - if (metric) - t.trace.trace( - t.get().fold( - (_err) => <Trace>(warnOnFailure ? metric.warn : metric.failure), - (_ok) => <Trace>metric.success, - ), - ); - return t.traceScope((_t) => - _t.get().fold( - (_err) => <Trace>(warnOnFailure ? LogLevel.WARN : LogLevel.ERROR), - (_ok) => <Trace>LogLevel.INFO, - ), - ); - }; - } - - static withTrace<T, Trace, _Trace extends ITraceWith<Trace>>( - trace: _Trace, - ): ITraceableMapper<T, ITraceable<T, Trace>, Trace> { - return (t) => t.traceScope(() => <Trace>trace); - } - - static withMetricTrace<T, Trace>(metric: IMetric): ITraceableMapper<T, ITraceable<T, Trace>, Trace> { - return TraceUtil.withTrace(<Trace>metric); - } - - static withFunctionTrace<F extends Callable, T, Trace>(f: F): ITraceableMapper<T, ITraceable<T, Trace>, Trace> { - return TraceUtil.withTrace(<Trace>`fn.${f.name}`); - } - - static withClassTrace<C extends object, T, Trace>(c: C): ITraceableMapper<T, ITraceable<T, Trace>, Trace> { - return TraceUtil.withTrace(<Trace>`class.${c.constructor.name}`); - } -} |