stormlog.infer.scrape_window

Aggregate one window of vLLM /metrics scrapes for one engine.

The caller decides which scrapes form a window; this module aggregates exactly the scrapes it is given, in the order given. Every figure belongs to one engine label and is never summed across engines.

Counters and histograms are differenced between consecutive scrapes, so a counter that went backwards between two interior scrapes is caught even when the window’s first and last values look consistent. Nothing is differenced across a reset, a recreated series, a missing series, a non-finite sample or a change of exporter: the result holds None and says why, never a zero.

A scrape samples the server at some instant between the moment it was stamped (observed_at_ns) and the moment its response came back. Window durations are measured between those intervals’ midpoints and carry the bounds the intervals allow. Records written before scrapes carried completed_at_ns are bounded by observed_at_ns + duration_ms, which leaves out the fetch thread’s start delay, so such windows say placement: "approximate".

Functions

check_window(scrapes, *[, engine, min_scrapes])

Check that a window is one exporter's, long enough, and in order.

counter_pair_delta(a, b, epoch_reason, recreated)

One counter's change between two scrapes, or why there is none.

counter_window(scrapes, family, *[, labels, ...])

A counter's increase: the sum of its consecutive-scrape deltas.

created_changed(before, after, family, ...)

The family's *_created stamp differs between two scrapes.

engine_index(scrape, engine)

Series of one engine keyed by (family, extra labels beyond the engine's).

exporter_identity(scrape)

Which exporter answered: its process start and its engine set.

gauge_median(gauge)

gauge_window(scrapes, family, *[, labels, ...])

A gauge's samples over the window's successful scrapes, one exporter's: samples from both sides of a restart are not one gauge.

histogram_pair_delta(a, b, epoch_reason, ...)

One histogram's change between two scrapes, or why there is none.

histogram_quantile_bounds(scrapes, family, q, *)

The bucket containing the window's q quantile: the first bucket whose cumulative count reaches q of the observations.

histogram_share_above(scrapes, family, value, *)

The share of the window's observations above value, bounded by the bucket boundaries on either side of it.

identity_differences(identity, other)

How another scrape's exporter differs from the first scrape's.

order_reasons(scrapes[, sampled])

Scrapes must be in strictly increasing stamp order: an earlier stamp after a later one is out of order, and two at one instant give a window of no length.

sample_interval(scrape)

When the server was sampled: between the stamp and the response.

sample_stats(values)

Over the finite samples; a NaN or an infinity is counted, not averaged.

series_by_extra(name, indexed)

series_match(scrape, family, labels, engine)

As series_value(), with the matched series' full label set, so two scrapes can be checked to hold the same series.

series_value(scrape, family, labels, engine)

The one series of family matching labels and engine.

share_at_least(gauge, threshold)

The fraction of the gauge's finite samples at or above threshold.

window_identity_reasons(ok)

Why the successful scrapes are not one exporter's, checked on every scrape against the first.

Classes

CounterWindow(delta, rate_per_s, ...)

A counter's increase over the window, from consecutive deltas.

GaugeWindow(n, non_finite, min, mean, max, ...)

A gauge's finite samples over the window and their statistics.

HistogramShare(count_delta, lo, hi, reasons)

The share of a histogram's window observations above a value.

QuantileBounds(count_delta, lo, hi, reasons)

The bucket boundaries that contain a quantile of the window.

WindowCheck(sufficient, reasons, scrapes, ...)

Whether a window's scrapes can be aggregated, and how long it lasted.

class stormlog.infer.scrape_window.CounterWindow(delta, rate_per_s, rate_bounds, reasons)[source]

Bases: object

A counter’s increase over the window, from consecutive deltas.

Parameters:
  • delta (float | None)

  • rate_per_s (float | None)

  • rate_bounds (tuple[float, float | None] | None)

  • reasons (tuple[str, ...])

delta: float | None
rate_per_s: float | None
rate_bounds: tuple[float, float | None] | None
reasons: tuple[str, ...]
class stormlog.infer.scrape_window.GaugeWindow(n, non_finite, min, mean, max, last, values, reasons)[source]

Bases: object

A gauge’s finite samples over the window and their statistics.

Parameters:
  • n (int)

  • non_finite (int)

  • min (float | None)

  • mean (float | None)

  • max (float | None)

  • last (float | None)

  • values (tuple[float, ...])

  • reasons (tuple[str, ...])

n: int
non_finite: int
min: float | None
mean: float | None
max: float | None
last: float | None
values: tuple[float, ...]
reasons: tuple[str, ...]
class stormlog.infer.scrape_window.HistogramShare(count_delta, lo, hi, reasons)[source]

Bases: object

The share of a histogram’s window observations above a value.

lo and hi bound the share between bucket boundaries; they are equal when the value is itself a boundary.

Parameters:
  • count_delta (float | None)

  • lo (float | None)

  • hi (float | None)

  • reasons (tuple[str, ...])

count_delta: float | None
lo: float | None
hi: float | None
reasons: tuple[str, ...]
class stormlog.infer.scrape_window.QuantileBounds(count_delta, lo, hi, reasons)[source]

Bases: object

The bucket boundaries that contain a quantile of the window.

lo is None when the quantile is in the first bucket, whose lower bound the exposition does not give; hi is None when it is in the +Inf bucket, with the reason quantile_in_overflow_bucket.

Parameters:
  • count_delta (float | None)

  • lo (float | None)

  • hi (float | None)

  • reasons (tuple[str, ...])

count_delta: float | None
lo: float | None
hi: float | None
reasons: tuple[str, ...]
class stormlog.infer.scrape_window.WindowCheck(sufficient, reasons, scrapes, engine, seconds, seconds_bounds, placement, failed=0)[source]

Bases: object

Whether a window’s scrapes can be aggregated, and how long it lasted.

Parameters:
  • sufficient (bool)

  • reasons (tuple[str, ...])

  • scrapes (int)

  • engine (str | None)

  • seconds (float | None)

  • seconds_bounds (tuple[float, float] | None)

  • placement (str)

  • failed (int)

sufficient: bool
reasons: tuple[str, ...]
scrapes: int
engine: str | None
seconds: float | None
seconds_bounds: tuple[float, float] | None
placement: str
failed: int = 0
stormlog.infer.scrape_window.check_window(scrapes, *, engine=None, min_scrapes=2)[source]

Check that a window is one exporter’s, long enough, and in order.

Parameters:
Return type:

WindowCheck

stormlog.infer.scrape_window.counter_pair_delta(a, b, epoch_reason, recreated)[source]

One counter’s change between two scrapes, or why there is none.

Parameters:
Return type:

dict[str, Any]

stormlog.infer.scrape_window.counter_window(scrapes, family, *, labels=None, engine=None)[source]

A counter’s increase: the sum of its consecutive-scrape deltas.

Parameters:
  • scrapes (Sequence[VllmScrapeRecord])

  • family (str)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

Return type:

CounterWindow

stormlog.infer.scrape_window.created_changed(before, after, family, labels, engine, *, kind='counter')[source]

The family’s *_created stamp differs between two scrapes.

Parameters:
  • before (CompactScrape | None)

  • after (CompactScrape | None)

  • family (str)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

  • kind (str)

Return type:

bool

stormlog.infer.scrape_window.engine_index(scrape, engine)[source]

Series of one engine keyed by (family, extra labels beyond the engine’s).

Parameters:
Return type:

dict[tuple[str, tuple[tuple[str, str], …]], float | HistogramValue]

stormlog.infer.scrape_window.exporter_identity(scrape)[source]

Which exporter answered: its process start and its engine set.

Parameters:

scrape (VllmScrapeRecord)

Return type:

tuple[int, tuple[str, …]] | None

stormlog.infer.scrape_window.gauge_median(gauge)[source]
Parameters:

gauge (GaugeWindow)

Return type:

float | None

stormlog.infer.scrape_window.gauge_window(scrapes, family, *, labels=None, engine=None)[source]

A gauge’s samples over the window’s successful scrapes, one exporter’s: samples from both sides of a restart are not one gauge.

“Every sample at least t” is gauge.min >= t with n checked against the caller’s floor; share_at_least() gives the fraction.

Parameters:
  • scrapes (Sequence[VllmScrapeRecord])

  • family (str)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

Return type:

GaugeWindow

stormlog.infer.scrape_window.histogram_pair_delta(a, b, epoch_reason, recreated)[source]

One histogram’s change between two scrapes, or why there is none.

Parameters:
Return type:

dict[str, Any]

stormlog.infer.scrape_window.histogram_quantile_bounds(scrapes, family, q, *, labels=None, engine=None)[source]

The bucket containing the window’s q quantile: the first bucket whose cumulative count reaches q of the observations.

Parameters:
  • scrapes (Sequence[VllmScrapeRecord])

  • family (str)

  • q (float)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

Return type:

QuantileBounds

stormlog.infer.scrape_window.histogram_share_above(scrapes, family, value, *, labels=None, engine=None)[source]

The share of the window’s observations above value, bounded by the bucket boundaries on either side of it.

Parameters:
  • scrapes (Sequence[VllmScrapeRecord])

  • family (str)

  • value (float)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

Return type:

HistogramShare

stormlog.infer.scrape_window.identity_differences(identity, other)[source]

How another scrape’s exporter differs from the first scrape’s.

Parameters:
  • identity (tuple[int, tuple[str, ...]])

  • other (tuple[int, tuple[str, ...]] | None)

Return type:

set[str]

stormlog.infer.scrape_window.sample_interval(scrape)[source]

When the server was sampled: between the stamp and the response.

Parameters:

scrape (VllmScrapeRecord)

Return type:

tuple[int, int]

stormlog.infer.scrape_window.sample_stats(values)[source]

Over the finite samples; a NaN or an infinity is counted, not averaged.

Parameters:

values (Sequence[float])

Return type:

dict[str, Any]

stormlog.infer.scrape_window.order_reasons(scrapes, sampled=None)[source]

Scrapes must be in strictly increasing stamp order: an earlier stamp after a later one is out of order, and two at one instant give a window of no length. Durations run between sample midpoints, so of the scrapes that sampled (sampled, by default all of them) a later one whose midpoint is no later (a quick scrape inside a slow one’s interval) is out of order too: which sampled first is unknown. A failed scrape has no sample, so its midpoint orders nothing.

Parameters:
Return type:

list[str]

stormlog.infer.scrape_window.series_by_extra(name, indexed)[source]
Parameters:
  • name (str)

  • indexed (Mapping[tuple[str, tuple[tuple[str, str], ...]], float | HistogramValue])

Return type:

dict[tuple[tuple[str, str], …], float | HistogramValue]

stormlog.infer.scrape_window.series_match(scrape, family, labels, engine)[source]

As series_value(), with the matched series’ full label set, so two scrapes can be checked to hold the same series.

Parameters:
  • scrape (CompactScrape | None)

  • family (str)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

Return type:

tuple[float | HistogramValue | None, Mapping[str, str] | None, str | None]

stormlog.infer.scrape_window.series_value(scrape, family, labels, engine)[source]

The one series of family matching labels and engine.

Without engine the scrape must hold a single engine. Two matching series are ambiguous rather than summed: label sets such as reason or finished_reason are kept apart unless the caller names one.

Parameters:
  • scrape (CompactScrape | None)

  • family (str)

  • labels (Mapping[str, str] | None)

  • engine (str | None)

Return type:

tuple[float | HistogramValue | None, str | None]

stormlog.infer.scrape_window.share_at_least(gauge, threshold)[source]

The fraction of the gauge’s finite samples at or above threshold.

Parameters:
Return type:

float | None

stormlog.infer.scrape_window.window_identity_reasons(ok)[source]

Why the successful scrapes are not one exporter’s, checked on every scrape against the first. An exporter with no process start cannot be told apart from a restarted one, so it is unknown rather than assumed.

Parameters:

ok (Sequence[VllmScrapeRecord])

Return type:

list[str]