ObservabilityIII · Metrics FundamentalsMetric types
Counters, Gauges, Histograms, and Summaries
What you'll learn
- Distinguish counter, gauge, histogram, summary
- Pick the right metric type for a measurement
- Read the data model `metric_name{label="value"} value`
- Recognise what each metric type can and cannot answer
Prerequisites
Verified against Prometheus 2.55.x · Alertmanager 0.28.x · node_exporter 1.8.x · blackbox_exporter 0.26.x · Grafana 11.x · Loki 3.x · Tempo current · OpenTelemetry Collector 0.110.x · Grafana Alloy current · Docker Engine 28.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-13
The Prometheus data model is simple: a numeric time series, identified by name and label set, carrying samples at points in time. The metric type — counter, gauge, histogram, summary — constrains what those samples mean and what query language (PromQL) can do with them.
This lesson introduces the four types with the operational decision: which type fits which measurement.
The data model
metric_name{label1="value1", label2="value2"} value timestamp
A unique combination of (metric_name, label1=value1, label2=value2, ...) is a time series. Every sample for that
series is a single (value, timestamp) pair. A counter can
have thousands of series, each carrying one integer per scrape.
Two example series:
http_requests_total{method=GET, route=/checkout, status=200} 4096
http_requests_total{method="POST",route="/checkout",status="500"} 3
Both series are the same metric name. They are different time series because their labels differ. They are stored independently. They can be aggregated together by PromQL.
Counters
A counter is a value that monotonically increases, except across
a process restart where it resets to zero. Counters are
optimised for rate() queries.
# An exposed example
http_requests_total{route="/checkout",status="200"} 4096
A raw counter has limited operational meaning — “we have served
4096 requests.” The operational meaning comes from the rate
over time (rate()):
rate(http_requests_total{route="/checkout",status="200"}[5m])
That query returns “requests / second over the last 5 minutes,” which is the operational quantity.
Counters fit:
- Request counts.
http_requests_total{status="..."} - Bytes received.
network_receive_bytes_total - Errors.
http_requests_total{status="5xx"}
A counter is the right type for any “cumulative” quantity.
Gauges
A gauge is a value that can go up or down. Gauges are
optimised for avg(), sum(), min(), max() aggregations.
node_memory_MemAvailable_bytes{instance="web01"} 4.5e9
node_load1{instance="web01"} 0.85
A gauge carries instantaneous state: “memory available is 4.5 GB right now”; “load-1 is 0.85 right now.” The state is sampled at scrape time.
Gauges fit:
- Resource state.
node_memory_MemAvailable_bytes,node_filesystem_avail_bytes, CPU temperature. - Queue depth.
rabbitmq_queue_messages. - Active sessions.
nginx_connections_active.
A counter’s value grows over time; a gauge’s value reports the current state.
Histograms
A histogram is a counter with bucket boundaries. It records how many observations fell within each bucket.
http_request_duration_seconds_bucket{le="0.005"} 24054
http_request_duration_seconds_bucket{le="0.01"} 33444
http_request_duration_seconds_bucket{le="0.025"} 100392
http_request_duration_seconds_bucket{le="+Inf"} 144320
http_request_duration_seconds_sum 53423
http_request_duration_seconds_count 144320
The buckets are cumulative: each le="X" is “the count of
observations <= X seconds.” The _count field is the total
number of observations. The _sum is the sum of observation
values.
Histograms fit:
- Latency.
http_request_duration_seconds_bucket - Request size.
http_request_size_bytes_bucket - Anything aggregate-by-quantile.
histogram_quantile()
The histogram has a known operational cost: each bucket adds a time series. A histogram with 12 buckets and 10 labels adds 120 series. A histogram with native histograms (Prometheus 2.50+) compresses the bucket cost and is preferred where supported.
Summaries
A summary is a metric that computes quantiles at the source and exposes them as individual gauge samples.
http_request_duration_seconds{quantile="0.5"} 0.052
http_request_duration_seconds{quantile="0.9"} 0.180
http_request_duration_seconds{quantile="0.99"} 0.834
http_request_duration_seconds_sum 53423
http_request_duration_seconds_count 144320
The quantiles are computed inside the service. Quantiles
cannot be aggregated across instances by histogram_quantile()
in PromQL because the pre-aggregated quantiles do not preserve
the distribution.
Summaries are useful when the application itself wants to report quantiles directly (e.g. a library has built-in quantile support). They are generally less flexible than histograms because you cannot aggregate across instances.
When to pick which
| Measurement | Type | Why |
|---|---|---|
| Request count over time | counter | cumulative |
| Bytes transmitted | counter | cumulative |
| Memory in use | gauge | instantaneous state |
| Active sessions | gauge | instantaneous state |
| Request latency | histogram | aggregatable quantiles |
| Request size | histogram | aggregatable quantiles |
| Pre-computed quantiles | summary | when the library emits them |
The default choice for a measurement is:
- “Cumulative over time” → counter
- “Instantaneous state” → gauge
- “Distribution of observations” → histogram
A summary is reserved for cases where the source already computes quantiles — most Prometheus client libraries default to histograms because aggregatability is more important than pre-computation.
Reading a metric in PromQL
Three operations cover most PromQL queries against metric data:
rate(counter[5m])— per-second rate over 5 minutes.avg(gauge by (instance))— average value per instance.histogram_quantile(0.99, sum by (le) (rate(histogram[5m])))— 99th percentile across instances.
PromQL is covered in production depth in Part XII.
Production guidance
- Use counters for cumulative measurements; never reset them inside the service.
- Use gauges for instantaneous state. Avoid aggregating across counters in a way that produces gauge-shaped numbers (use histogram_quantile instead).
- Default to histograms for distribution-shaped measurements. Drop in native histograms where supported.
- Use summaries only when the library emits them and you cannot switch to histograms.
- Use recording rules to precompute repeated queries — particularly histogram quantiles and rate-based metrics.
Verification
You should be able to answer:
- What are the four Prometheus metric types?
- What is the data model
metric_name{label="value"} value? - When do you pick a counter vs a gauge vs a histogram vs a summary?
- Why are histograms preferred for latency?
Quiz
Knowledge check · 8 questions
Q1. What is the primary purpose of counters, gauges, histograms, and summaries?
Q2. Which failure mode of counters, gauges, histograms, and summaries is most operationally costly?
Q3. Production verification should run on production hosts.
Q4. First response when counters, gauges, histograms, and summaries misbehaves?
Q5. Name one signal that confirms counters, gauges, histograms, and summaries is healthy.
Q6. Which of these are validation steps?
Q7. Right discipline when changing in production?
Q8. Telemetry usefulness requires:
Passing score: 75%. Answers are checked in this browser.