Metrics & Prometheus
Prometheus is the de facto standard for collecting and querying metrics. Master the pull model, the four metric types, labels, retention, and enough PromQL to answer real questions about your systems.
What is this?
Prometheus is a pull-based time series database and monitoring toolkit. On a fixed interval it scrapes HTTP endpoints that expose metrics in a text format, stores each unique label set as its own series, and answers queries with PromQL. Four metric types encode meaning: counters only increase, gauges go up and down, histograms count observations in pre-defined buckets, and summaries expose client-computed quantiles.
Why do you need it?
- The pull model fits containers and Kubernetes naturally: Prometheus discovers targets and immediately knows when one disappears.
- A label-based data model makes queries flexible — you can slice, aggregate and join on any dimension.
- Choosing counter, gauge, histogram or summary forces you to think about what the metric actually means.
- PromQL is the industry-standard metric language, also implemented by Thanos, VictoriaMetrics, Grafana Mimir and AWS Managed Prometheus.
- Local storage, service discovery and config-file operation make it easy to self-host with predictable retention.
Mental model
A car's instruments
Prometheus metric types
The trip odometer is a counter — it only goes up and resets at zero. The speedometer is a gauge — it moves in both directions. A histogram is like tallying passengers into height buckets (under 1.5m, under 1.8m, under 2.1m); a summary is like someone pre-computing the median height for you.
How it works
- Each target exposes a /metrics endpoint in the text exposition format: comment lines starting with # HELP and # TYPE, then one sample per line with optional label sets.
- Prometheus pulls every target on its scrape_interval using HTTP; a failed scrape is recorded as the up metric being 0 for that target.
- Every unique combination of metric name and label values becomes one time series; samples are appended to a block-structured storage engine.
- PromQL resolves instant vectors (one value per series right now) and range vectors (values over a window) for functions like rate and histogram_quantile.
- Recording rules precompute expensive or repeated expressions, and alerting rules evaluate threshold conditions on the same evaluation schedule.
How Prometheus scrapes, stores and serves metrics.
Key commands
curl -s http://localhost:9090/metrics | headRead the exposition format directly from a target's /metrics endpoint.
curl -s http://localhost:9090/api/v1/targetsList configured scrape targets and their current health state.
curl -s 'http://localhost:9090/api/v1/query?query=up'Run an instant PromQL query through the HTTP API.
promtool check config prometheus.ymlValidate the Prometheus configuration before reloading it.
promtool check rules rules.ymlValidate recording and alerting rule files for syntax errors.
Examples
Query a counter correctly with rate()
# WRONG: a raw counter just grows since the last restarthttp_requests_total{job="web"} → 1284773 # RIGHT: rate() converts counter growth to requests per secondrate(http_requests_total{job="web"}[5m]) → 42.5 # Errors per second, sliced by instancesum by (instance) (rate(http_requests_total{job="web", status=~"5.."}[5m])) # p99 latency from a histogram across all instanceshistogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))A counter is monotonically increasing, so a raw value is only meaningful combined with a window. rate() computes per-second growth over that window and properly handles counter resets. Histograms aggregate cleanly with sum by (le) before histogram_quantile picks the bucket boundary containing the 99th percentile.
In production
- The kube-prometheus stack scrapes node metrics, kubelet metrics and application endpoints using relabeling to discover pods.
- SLO burn-rate alerts run recording rules against high-resolution counters and evaluate them every 30 seconds.
- Latency SLOs are computed from histograms because, unlike summaries, histograms aggregate across instances.
- Remote write or federation ships series from edge clusters to a central long-term store while each cluster keeps local Prometheus.
- Cardinality is audited with the TSDB stats tools so series growth stays inside the capacity budget.
Best practices
- Use counters only for monotonically increasing totals and always pass them through rate() or increase().
- Prefer histograms over summaries for latency: summaries cannot be aggregated across instances, histograms can.
- Keep label cardinality bounded — never embed request IDs, user IDs or IP addresses as label values.
- Follow metric naming conventions: namespace_name_unit_total, e.g. http_requests_total or node_cpu_seconds_total.
- Put expensive or repeated queries in recording rules; keep alerting rules simple and readable.
Common mistakes
- Plotting a raw counter so the chart shows 'requests since boot' instead of a useful rate.
- Using a gauge for request counts or a counter for free memory — the type must match the metric's behavior.
- Adding a per-user or per-request label value, causing cardinality explosion and slow queries.
- Setting scrape_interval too short (wasted CPU and storage) or too long (missing short spikes).
- Computing histogram quantiles over the wrong window or ignoring bucket resets on restarts.
Common issues
A metric disappears from charts after a few minutesThe target stopped reporting, the exporter crashed, or the scrape started failing.
Query up for that job and check /api/v1/targets; restart the exporter and verify its /metrics endpoint with curl.
Histogram quantile returns a wrong or empty valueA summary was used instead of a histogram, or too few observations fall into the requested bucket.
Switch to histogram buckets with sufficient resolution around the target percentile and aggregate with sum by (le).
Prometheus runs out of memory or diskCardinality explosion or a retention setting larger than the capacity supports.
Audit label usage, raise --storage.tsdb.retention.time only after reducing cardinality, and add limits on series per metric.
Debugging tips
- When a metric is missing, check /api/v1/targets first — a failing scrape is the most common cause.
- Use up == 0 in queries to distinguish a dead target from a metric that was never created.
- Test PromQL in the Expression browser before writing an alert rule so you can see the vector shape.
- Watch for stale markers in the UI — a flat line dropping to nothing usually means the target restarted.
- Run promtool check config and promtool check rules before any reload to catch YAML or syntax errors.
Interview checkpoint
Hands-on lab
- Write a minimal Prometheus configuration
- Scrape a real node-exporter target
- Verify targets and queries through the HTTP API
- Stop the components when finished
Run Prometheus, Scrape a Target and Query It
25 min · intermediate
Quick quiz
Which Prometheus metric type is a monotonically increasing total?
What does the up metric equal for a target when the scrape fails?
Summary quantiles can be aggregated across multiple instances.
Cheat sheet
rate(counter[5m])Per-second growth of a counter over 5 minutesincrease(counter[1h])Total increase over the windowsum by (instance) (...)Aggregate across one dimensionhistogram_quantile(0.99, ...)Percentile from histogram bucketspredict_linear(metric[1h], 3600)Forecast a value one hour aheadcurl /api/v1/targetsScrape target healthcurl '/api/v1/query?query=up'Instant query via the HTTP APIpromtool check configValidate prometheus.ymlpromtool check rulesValidate recording/alerting rulesPOST /-/reloadReload config without restart