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 that a window is one exporter's, long enough, and in order. |
|
One counter's change between two scrapes, or why there is none. |
|
A counter's increase: the sum of its consecutive-scrape deltas. |
|
The family's |
|
Series of one engine keyed by (family, extra labels beyond the engine's). |
|
Which exporter answered: its process start and its engine set. |
|
|
|
A gauge's samples over the window's successful scrapes, one exporter's: samples from both sides of a restart are not one gauge. |
|
One histogram's change between two scrapes, or why there is none. |
|
The bucket containing the window's |
|
The share of the window's observations above |
|
How another scrape's exporter differs from the first scrape's. |
|
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. |
|
When the server was sampled: between the stamp and the response. |
|
Over the finite samples; a NaN or an infinity is counted, not averaged. |
|
|
|
As |
|
The one series of |
|
The fraction of the gauge's finite samples at or above |
Why the successful scrapes are not one exporter's, checked on every scrape against the first. |
Classes
|
A counter's increase over the window, from consecutive deltas. |
|
A gauge's finite samples over the window and their statistics. |
|
The share of a histogram's window observations above a value. |
|
The bucket boundaries that contain a quantile of the window. |
|
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:
objectA 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:
objectA 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, ...]
Bases:
objectThe share of a histogram’s window observations above a value.
loandhibound 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, ...])
- class stormlog.infer.scrape_window.QuantileBounds(count_delta, lo, hi, reasons)[source]
Bases:
objectThe bucket boundaries that contain a quantile of the window.
lois None when the quantile is in the first bucket, whose lower bound the exposition does not give;hiis None when it is in the+Infbucket, with the reasonquantile_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:
objectWhether 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:
scrapes (Sequence[VllmScrapeRecord])
engine (str | None)
min_scrapes (int)
- Return type:
- 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:
a (float | HistogramValue | None)
b (float | HistogramValue | None)
epoch_reason (str | None)
recreated (bool)
- 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:
- stormlog.infer.scrape_window.created_changed(before, after, family, labels, engine, *, kind='counter')[source]
The family’s
*_createdstamp 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:
scrape (CompactScrape)
engine (str)
- 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” isgauge.min >= twithnchecked 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:
- 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:
a (HistogramValue | None)
b (HistogramValue | None)
epoch_reason (str | None)
recreated (bool)
- 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
qquantile: the first bucket whose cumulative count reachesqof the observations.- Parameters:
scrapes (Sequence[VllmScrapeRecord])
family (str)
q (float)
labels (Mapping[str, str] | None)
engine (str | None)
- Return type:
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:
- 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:
scrapes (Sequence[VllmScrapeRecord])
sampled (Sequence[VllmScrapeRecord] | None)
- 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
familymatchinglabelsandengine.Without
enginethe scrape must hold a single engine. Two matching series are ambiguous rather than summed: label sets such asreasonorfinished_reasonare 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]
The fraction of the gauge’s finite samples at or above
threshold.- Parameters:
gauge (GaugeWindow)
threshold (float)
- 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]