Skip to content
About
Main content

Metrics: counters, gauges and histograms

Why do counters survive lost scrapes when gauges do not, and why can percentiles never be averaged?

A metric is a number sampled over time: orders per second, queue length, memory used. There are three basic kinds. The differences are not cosmetic. They decide what survives when data is lost.

Counters survive loss; gauges do not

A counter only goes up (total orders so far). A gauge is a value that moves up and down (current queue length).

A counter is monotonic (never decreases) by construction, and this single property is the whole design. Suppose the monitoring system reads the counter every 15 s and one read fails:

t=0s   orders_total = 1000
t=15s  (scrape lost)
t=30s  orders_total = 1090

Nothing is lost. The next value still carries the full history. The rate is (1090 − 1000) / 30 s = 3 orders per second. The calculation simply spans a wider interval.

A gauge is only a point sample of a continuous signal. A missed scrape is permanently lost. Worse, a phenomenon that is shorter than twice the is aliased: it looks like noise, or like a slow trend that does not exist. (This is the limit of Nyquist: to see a repeating pattern you must sample at least twice as fast as the pattern repeats.) Example: a queue that fills to 10,000 records for 5 seconds and empties again, once a minute, is invisible with a 60 s scrape. The sampled values look flat, or show a random small bump.

The spike between two scrapesscrape every 60 s

So the rule is: Anything you care about should be emitted as an accumulator (a counter) and differentiated at read time (turn into a rate when you query), not accumulated at write time.

# Emit an accumulator, compute the rate when you read it.
orders_total.inc()                      # in the application: one line per order

# In the query language of a monitoring system (PromQL-style):
#   rate(orders_total[5m])             # orders per second over the last 5 minutes

Histograms fix their resolution before the question

You cannot store every observation (a service handling 20,000 requests per second would produce 1.7 billion latency values per day). And the mean destroys exactly the information you need: a mean of 120 ms can hide a of 5 s. This is the variance beats volume law: the spread is the problem, and the average hides the spread.

So a counts observations in buckets:

Bucket (latency)Count
≤ 50 ms9,200
≤ 100 ms600
≤ 250 ms150
≤ 500 ms40
≤ 1 s10
> 1 s0 (no bucket above 1 s)

But the bucket boundaries are (this is : you decide the structure before you know the question). Ask for p99.9 on a system whose largest bucket is 1 s, and the answer is "somewhere above 1 second", permanently. The information was never stored.

There is an operational corollary: pre-bucketed histograms can be summed across instances, pre-computed cannot.

the q-th percentile of a set of measurements