summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-08-17 23:56:14 -0700
committerElizabeth Hunt <me@liz.coffee>2025-08-17 23:56:40 -0700
commit3a303475b763cbbf4d3491146582faccd8b93c99 (patch)
treeaf7fb2811a7ce48cbec32df8075c19fc6f977d12
parentd9656076ec5c4138201080f0a250b57533357165 (diff)
downloadpengueno-3a303475b763cbbf4d3491146582faccd8b93c99.tar.gz
pengueno-3a303475b763cbbf4d3491146582faccd8b93c99.zip
Trace metrics by name which 'should' be unique
-rw-r--r--lib/trace/metric/index.ts1
-rw-r--r--lib/trace/metric/trace.ts44
-rw-r--r--lib/trace/trace.ts8
-rw-r--r--package.json2
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",