A cumulative counter records how many events a process has counted since its current origin. A snapshot of 120 requests is not a count of the last ten seconds. If the earlier snapshot was 100, the observed interval contains twenty counted requests. Divide that delta by ten seconds to obtain two requests per second. Keep the unit in the name: a count, a rate and a fraction answer different questions.
An error counter is useful only with a compatible request counter. The failure fraction is interval errors divided by interval requests. Errors per second is another useful metric, but it is not the same fraction. This build uses cumulative requests and errors for one defined service population, with error counts included in total requests. It rejects snapshots or deltas that violate that subset relationship.
intervals = [(1, 1), (99, 0)] # requests, errors
requests = sum(n for n, errors in intervals)
errors = sum(errors for n, errors in intervals)
print(errors / requests)The combined fraction is 1%, although the two interval fractions are 100% and 0%. Their unweighted average would be 50%. Aggregate compatible numerators and denominators before dividing. The same care applies to rate: add counted work and accepted seconds, instead of giving a one-second interval the same weight as a long interval. Preserve the support counts beside the summary so a reviewer can see what it describes.
A process restart can reset counters. A decreasing snapshot is visible evidence that naive subtraction is unsafe. Our conservative fixture policy discards the entire affected interval: both request/error deltas and its seconds. It counts a reset and resumes from the next snapshot. This avoids claiming work during an interval whose origin is unknown. It can undercount total activity; a reset followed by enough increments can even be invisible between nondecreasing snapshots.
This arithmetic is an explicit offline model, not Prometheus rate() or increase(). Those functions have their own range, reset and extrapolation behavior. Real series also need instance identity, collection health, scrape cadence and compatible labels. Adding arbitrary user IDs as metric labels can create unbounded series cardinality; retain detailed request identifiers in logs/traces under an appropriate data policy rather than assuming every identifier is a safe metric dimension.
Zero observed requests yields an unknown failure fraction, represented by None. It is not 0% successful evidence. An accepted zero-work interval can still support a measured request rate of zero if its duration and snapshots are observed. Empty input or one snapshot supports neither an interval rate nor a fraction.
The exercises distinguish lifetime totals from deltas, fractions from rates and missing coverage from zero work. The build validates chronological order, catches bool masquerading as an integer, handles several restart segments and consumes input once. Its result is a summary of accepted fixture coverage; it is not proof that the service met a production objective throughout discarded intervals.