diff options
Diffstat (limited to 'u/trace/metrics.ts')
-rw-r--r-- | u/trace/metrics.ts | 229 |
1 files changed, 109 insertions, 120 deletions
diff --git a/u/trace/metrics.ts b/u/trace/metrics.ts index 822fc38..2301afd 100644 --- a/u/trace/metrics.ts +++ b/u/trace/metrics.ts @@ -1,151 +1,140 @@ import { - isObject, - type ITrace, - type ITraceWith, - type Mapper, - type SideEffect, - type Supplier, -} from "@emprespresso/pengueno"; + isObject, + type ITrace, + type ITraceWith, + type Mapper, + type SideEffect, + type Supplier, +} from '@emprespresso/pengueno'; export enum Unit { - COUNT = "COUNT", - MILLISECONDS = "MILLISECONDS", + COUNT = 'COUNT', + MILLISECONDS = 'MILLISECONDS', } export interface IMetric { - readonly count: IEmittableMetric; - readonly time: IEmittableMetric; - readonly failure?: IMetric; - readonly success?: IMetric; - readonly warn?: IMetric; - readonly children: Supplier<Array<IMetric>>; - - readonly _tag: "IMetric"; + readonly count: IEmittableMetric; + readonly time: IEmittableMetric; + readonly failure: undefined | IMetric; + readonly success: undefined | IMetric; + readonly warn: undefined | IMetric; + readonly children: Supplier<Array<IMetric>>; + + readonly _tag: 'IMetric'; } -export const isIMetric = (t: unknown): t is IMetric => - isObject(t) && "_tag" in t && t._tag === "IMetric"; +export const isIMetric = (t: unknown): t is IMetric => isObject(t) && '_tag' in t && t._tag === 'IMetric'; export interface IEmittableMetric { - readonly name: string; - readonly unit: Unit; - withValue: Mapper<number, MetricValue>; + readonly name: string; + readonly unit: Unit; + withValue: Mapper<number, MetricValue>; } 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: "MetricValue", - }; - } + 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: 'MetricValue', + }; + } } export class Metric implements IMetric { - constructor( - public readonly count: IEmittableMetric, - public readonly time: IEmittableMetric, - public readonly failure?: Metric, - public readonly success?: Metric, - public readonly warn?: Metric, - public readonly _tag: "IMetric" = "IMetric", - ) {} - - public children() { - return [this.failure, this.success, this.warn].filter( - (x) => x, - ) as IMetric[]; - } - - static fromName(name: string, addChildren = true): Metric { - return new Metric( - new EmittableMetric(`${name}.count`, Unit.COUNT), - new EmittableMetric(`${name}.elapsed`, Unit.MILLISECONDS), - addChildren ? Metric.fromName(`${name}.failure`, false) : undefined, - addChildren ? Metric.fromName(`${name}.success`, false) : undefined, - addChildren ? Metric.fromName(`${name}.warn`, false) : undefined, - ); - } + constructor( + public readonly count: IEmittableMetric, + public readonly time: IEmittableMetric, + public readonly failure: undefined | Metric = undefined, + public readonly success: undefined | Metric = undefined, + public readonly warn: undefined | Metric = undefined, + public readonly _tag: 'IMetric' = 'IMetric', + ) {} + + public children() { + return [this.failure, this.success, this.warn].filter((x) => x) as IMetric[]; + } + + static fromName(name: string, addChildren = true): Metric { + return new Metric( + new EmittableMetric(`${name}.count`, Unit.COUNT), + new EmittableMetric(`${name}.elapsed`, Unit.MILLISECONDS), + addChildren ? Metric.fromName(`${name}.failure`, false) : undefined, + addChildren ? Metric.fromName(`${name}.success`, false) : undefined, + addChildren ? Metric.fromName(`${name}.warn`, false) : undefined, + ); + } } export interface MetricValue { - readonly name: string; - readonly unit: Unit; - readonly value: number; - readonly emissionTimestamp: number; - readonly _tag: "MetricValue"; + readonly name: string; + readonly unit: Unit; + readonly value: number; + readonly emissionTimestamp: number; + readonly _tag: 'MetricValue'; } -export const isMetricValue = (t: unknown): t is MetricValue => - isObject(t) && "_tag" in t && t._tag === "MetricValue"; +export const isMetricValue = (t: unknown): t is MetricValue => isObject(t) && '_tag' in t && t._tag === 'MetricValue'; -export const isMetricsTraceSupplier = (t: unknown): t is MetricsTraceSupplier => - isMetricValue(t) || isIMetric(t); +export const isMetricsTraceSupplier = (t: unknown): t is MetricsTraceSupplier => isMetricValue(t) || isIMetric(t); -export type MetricsTraceSupplier = ITraceWith< - IMetric | MetricValue | undefined ->; +export type MetricsTraceSupplier = ITraceWith<IMetric | MetricValue | undefined>; type MetricTracingTuple = [IMetric, Date]; export class MetricsTrace implements ITrace<MetricsTraceSupplier> { - constructor( - private readonly metricConsumer: SideEffect<Array<MetricValue>>, - private readonly tracing: Array<MetricTracingTuple> = [], - private readonly flushed: Set<IMetric> = new Set(), - ) {} - - public addTrace(trace: MetricsTraceSupplier) { - if (!isIMetric(trace)) return this; - return new MetricsTrace(this.metricConsumer)._nowTracing(trace); - } - - public trace(metric: MetricsTraceSupplier) { - if (typeof metric === "undefined" || typeof metric === "string") - return this; - if (isMetricValue(metric)) { - this.metricConsumer([metric]); - return this; + constructor( + private readonly metricConsumer: SideEffect<Array<MetricValue>>, + private readonly tracing: Array<MetricTracingTuple> = [], + private readonly flushed: Set<IMetric> = new Set(), + ) {} + + public addTrace(trace: MetricsTraceSupplier) { + if (!isIMetric(trace)) return this; + return new MetricsTrace(this.metricConsumer)._nowTracing(trace); } - const foundMetricValues = this.tracing - .flatMap(([tracing, startedTracing]) => - [tracing, ...tracing.children()] - .filter((_tracing) => metric === _tracing) - .flatMap((metric) => [ - this.addMetric(metric, startedTracing), - this.addMetric(tracing, startedTracing), - ]), - ) - .flatMap((values) => values); - - if (foundMetricValues.length === 0) { - return this._nowTracing(metric); + public trace(metric: MetricsTraceSupplier) { + if (typeof metric === 'undefined' || typeof metric === 'string') return this; + if (isMetricValue(metric)) { + this.metricConsumer([metric]); + return this; + } + + const foundMetricValues = this.tracing + .flatMap(([tracing, startedTracing]) => + [tracing, ...tracing.children()] + .filter((_tracing) => metric === _tracing) + .flatMap((metric) => [ + this.addMetric(metric, startedTracing), + this.addMetric(tracing, startedTracing), + ]), + ) + .flatMap((values) => values); + + if (foundMetricValues.length === 0) { + return this._nowTracing(metric); + } + + this.metricConsumer(foundMetricValues); + return this; } - this.metricConsumer(foundMetricValues); - return this; - } + private addMetric(metric: IMetric, startedTracing: Date): Array<MetricValue> { + if (this.flushed.has(metric)) { + return []; + } - private addMetric(metric: IMetric, startedTracing: Date): Array<MetricValue> { - if (this.flushed.has(metric)) { - return []; + this.flushed.add(metric); + return [metric.count.withValue(1.0), metric.time.withValue(Date.now() - startedTracing.getTime())]; } - this.flushed.add(metric); - return [ - metric.count.withValue(1.0), - metric.time.withValue(Date.now() - startedTracing.getTime()), - ]; - } - - private _nowTracing(metric?: IMetric): MetricsTrace { - if (!metric) return this; - this.tracing.push([metric, new Date()]); - return this; - } + private _nowTracing(metric?: IMetric): MetricsTrace { + if (!metric) return this; + this.tracing.push([metric, new Date()]); + return this; + } } |