Functional Weave
Code in TypeScript

monitor.counter-increase@1.0.0

impl/typescript.ts

1,603 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type MetricSample } from "./monitor_series_window.ts";  ← from monitor.series-window ^1.0.0 · built alongside by fune
import { type CounterIncrease } from "./monitor_counter_increase_types.ts";

/**
 * How much a counter grew over the samples, Prometheus-style: a drop means the
 * counter restarted from zero, so the value after it is all increase. No
 * extrapolation to window edges, so the answer is a whole number.
 */
export function counterIncrease(samples: readonly MetricSample[]): CounterIncrease {
  let increase = 0;
  let resets = 0;
  for (let i = 0; i < samples.length; i++) {
    const s = samples[i];
    if (i > 0 && s.at <= samples[i - 1].at) {
      throw new RangeError(`samples must be in strictly ascending time order: ${s.at} follows ${samples[i - 1].at}`);
    }
    if (s.value < 0) throw new RangeError(`counter value must not be negative: ${s.value} at ${s.at}`);
    if (i === 0) continue;
    const prev = samples[i - 1].value;
    if (s.value >= prev) {
      increase += s.value - prev;
    } else {
      resets += 1;
      increase += s.value;
    }
  }
  if (samples.length === 0) return { increase: 0, resets: 0, ratePerSecondMilli: null, firstAt: null, lastAt: null };
  const firstAt = samples[0].at;
  const lastAt = samples[samples.length - 1].at;
  let ratePerSecondMilli: number | null = null;
  if (samples.length >= 2) {
    // increase * 1000 passes 2^53 for a byte counter in the trillions: BigInt.
    const n = BigInt(increase) * 1000n;
    const d = BigInt(lastAt - firstAt);
    ratePerSecondMilli = Number((2n * n + d) / (2n * d));
  }
  return { increase, resets, ratePerSecondMilli, firstAt, lastAt };
}