diff options
-rw-r--r-- | lib/trace/metric/index.ts | 1 | ||||
-rw-r--r-- | lib/trace/metric/trace.ts | 44 | ||||
-rw-r--r-- | lib/trace/trace.ts | 8 | ||||
-rw-r--r-- | package.json | 2 |
4 files changed, 32 insertions, 23 deletions
diff --git a/lib/trace/metric/index.ts b/lib/trace/metric/index.ts index aebc890..35a0693 100644 --- a/lib/trace/metric/index.ts +++ b/lib/trace/metric/index.ts @@ -25,6 +25,7 @@ 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 name: string; readonly count: IEmittableMetric; readonly time: IEmittableMetric; readonly parent: undefined | IMetric; diff --git a/lib/trace/metric/trace.ts b/lib/trace/metric/trace.ts index 0c5fe37..6508831 100644 --- a/lib/trace/metric/trace.ts +++ b/lib/trace/metric/trace.ts @@ -9,17 +9,16 @@ export const isMetricsTraceSupplier = (t: unknown): t is MetricsTraceSupplier => 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(), + private readonly activeTraces: ReadonlyMap<string, number> = new Map(), + private readonly completedTraces: ReadonlySet<string> = 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.name, now])); - const initialTraces = new Map(metricsToTrace.map((metric) => [metric, now])); - - return new MetricsTrace(this.metricConsumer, initialTraces); + return new MetricsTrace(this.metricConsumer, initialTraces, this.completedTraces); } public trace(metrics: MetricsTraceSupplier): MetricsTrace { @@ -30,30 +29,47 @@ export class MetricsTrace implements ITrace<MetricsTraceSupplier> { 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)); + const metricsToStart = traceableMetrics.filter((m) => !this.activeTraces.has(m.name)); + const metricsToEnd = traceableMetrics.filter( + (m) => this.activeTraces.has(m.name) && !this.completedTraces.has(m.name), + ); - // 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)!), + metric.time.withValue(now - this.activeTraces.get(metric.name)!), ]); - const allMetricsToEmit = [...valuesToEmit, ...endedMetricValues]; + const parentBasedMetrics = metricsToStart.filter((metric) => { + const parent = metric.parent; + return parent && this.activeTraces.has(parent.name); + }); + + const parentBasedValues = parentBasedMetrics.flatMap((metric) => { + const parentStart = this.activeTraces.get(metric.parent!.name)!; + return [ + metric.count.withValue(1.0), + metric.time.withValue(now - parentStart), + ]; + }); + + const allMetricsToEmit = [...valuesToEmit, ...endedMetricValues, ...parentBasedValues]; if (allMetricsToEmit.length > 0) { this.metricConsumer(allMetricsToEmit); } - // the next immutable state const nextActiveTraces = new Map([ ...this.activeTraces, - ...metricsToStart.map((m): [IMetric, number] => [m, now]), + ...metricsToStart.map((m): [string, number] => [m.name, now]), ]); - const nextCompletedTraces = new Set([...this.completedTraces, ...metricsToEnd]); + const nextCompletedTraces = new Set([ + ...this.completedTraces, + ...metricsToEnd.map((m) => m.name), + ...parentBasedMetrics.map((m) => m.name), + ]); + return new MetricsTrace(this.metricConsumer, nextActiveTraces, nextCompletedTraces); } } diff --git a/lib/trace/trace.ts b/lib/trace/trace.ts index ab7e841..d7f631e 100644 --- a/lib/trace/trace.ts +++ b/lib/trace/trace.ts @@ -39,14 +39,6 @@ export class LogMetricTrace implements ITrace<LogMetricTraceSupplier> { 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)); diff --git a/package.json b/package.json index d4bb7e5..7a6465d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@emprespresso/pengueno", - "version": "0.0.11", + "version": "0.0.12", "description": "emprespresso pengueno utils", "main": "./dist/index.js", "types": "./dist/index.d.ts", |