← Back to list

PromQL: The Query Language That Makes Your Metrics Talk

A practical guide to querying Prometheus — what it is, how it works, and when to use it

Latha Narayanappa · 2026-06-08 16:45 · 0 claps · 4.7 min read paywalled
#promql #prometheus #devops
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

PromQL: The Query Language That Makes Your Metrics Talk

A practical guide to querying Prometheus — what it is, how it works, and when to use it

What Is PromQL?

Prometheus Query Language — PromQL — is a functional, read-only query language built specifically for time-series data stored in Prometheus. If Prometheus is the engine that scrapes and stores your metrics, PromQL is the steering wheel that lets you ask questions of that data.

Unlike SQL, which operates on rows and tables, PromQL operates on time-series vectors — streams of timestamped float64 values identified by a metric name and a set of key-value labels.

http_requests_total{job="api-server", status="200"}

That single expression returns every time series that matches those label filters — no FROM, no JOIN, no WHERE. The data model and the query language are tightly coupled, which makes PromQL terse but extremely powerful once you understand the building blocks.

The Data Model in 60 Seconds

Before writing queries, you need to understand what you’re querying. Prometheus stores four metric types:

Every metric is tagged with labels — key-value pairs that add dimensions. Labels are what make PromQL’s filtering and aggregation so expressive.

The Four Building Blocks of PromQL

1. Instant Vectors

A snapshot of all matching time series at a single point in time.

node_cpu_seconds_total

Returns one sample per matching series — the current value. This is the most basic query form.

2. Range Vectors

All samples in a time window for each series — required as input for functions like rate().

node_cpu_seconds_total[5m]

The [5m] window says: give me the last 5 minutes of data. You can use s, m, h, d, w, y as duration suffixes.

3. Scalars

Plain numeric values with no time-series context.

1024 * 1024

Useful as multipliers or thresholds in expressions.

4. Strings

Used in some special functions, rarely in practice.

Label Filtering

Label matchers let you slice your data precisely. There are four operators:

# Equality
http_requests_total{status="200"}
# Inequality
http_requests_total{status!="500"}
# Regex match
http_requests_total{path=~"/api/.*"}
# Regex non-match
http_requests_total{path!~"/health|/metrics"}

Combining multiple matchers acts as a logical AND:

http_requests_total{job="api-server", status=~"5.."}

The Functions You’ll Use Daily

rate() — For Counters

Calculates the per-second average rate of increase over a range window, handling counter resets gracefully.

rate(http_requests_total[5m])

Rule of thumb: Always use rate() on counters, never raw values. Counters only go up — rate() gives you the meaningful derivative.

Use irate() instead when you want the instantaneous rate (last two samples only) — useful for fast-moving metrics where averages would smooth out spikes.

increase() — Total Change Over a Window

increase(http_requests_total[1h])

Returns the total number of requests in the last hour. Internally equivalent to rate() * duration.

sum(), avg(), min(), max() — Aggregations

Aggregate across label dimensions using the by or without clause:

# Total request rate across all instances
sum(rate(http_requests_total[5m]))
# Per-job breakdown
sum by (job) (rate(http_requests_total[5m]))
# Drop the instance label, keep everything else
sum without (instance) (http_requests_total)

histogram_quantile() — Latency Percentiles

The most powerful function for latency analysis:

histogram_quantile(0.99,
  sum by (le) (
    rate(http_request_duration_seconds_bucket[5m])
  )
)

This computes the p99 latency across all request durations. The le label (less-than-or-equal) is the bucket boundary that Prometheus histograms use.

topk() / bottomk() — Finding the Extremes

topk(5, sum by (endpoint) (rate(http_requests_total[5m])))

Returns the 5 busiest endpoints by request rate. Indispensable for debugging traffic spikes.

How to Configure Prometheus for PromQL

PromQL is usable anywhere Prometheus exposes its HTTP API — but you need a properly configured Prometheus instance first.

Basic prometheus.yml

global:
  scrape_interval: 15s       # How often to scrape targets
  evaluation_interval: 15s   # How often to evaluate rules
scrape_configs:
  - job_name: "node-exporter"
    static_configs:
      - targets: ["localhost:9100"]
  - job_name: "my-api"
    static_configs:
      - targets: ["api-server:8080"]
    metrics_path: /metrics
    scrape_interval: 10s     # Override global for this job

Recording Rules — Pre-compute Expensive Queries

For heavy queries you run frequently (dashboards, alerts), record them as new metrics:

# rules/recording.yml
groups:
  - name: api_metrics
    interval: 30s
    rules:
      - record: job:http_requests:rate5m
        expr: sum by (job) (rate(http_requests_total[5m]))

Load in prometheus.yml:

rule_files:
  - "rules/*.yml"

Alerting Rules

groups:
  - name: availability
    rules:
      - alert: HighErrorRate
        expr: |
          rate(http_requests_total{status=~"5.."}[5m])
          /
          rate(http_requests_total[5m]) > 0.05
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Error rate above 5% for {{ $labels.job }}"

Real-World Use Cases

1. Service Health Dashboard

# Request rate
sum(rate(http_requests_total[5m])) by (service)
# Error ratio
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/ sum(rate(http_requests_total[5m])) by (service)
# p95 latency
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))

These three queries — rate, error ratio, latency percentile — are the RED method (Rate, Errors, Duration), the gold standard for service monitoring.

2. Infrastructure Capacity Planning

# CPU utilisation per node
1 - avg by (instance) (
  rate(node_cpu_seconds_total{mode="idle"}[5m])
)
# Memory pressure
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
# Disk space trend — will I run out in 4 hours?
predict_linear(node_filesystem_avail_bytes[1h], 4 * 3600) < 0

predict_linear() does linear regression on a range vector and extrapolates — powerful for proactive alerting.

3. SLO Burn Rate Alerting

Multi-window burn rate is the modern approach to SLO alerting (from Google’s SRE workbook):

# 5-minute burn rate
rate(http_requests_total{status=~"5.."}[5m])
/ rate(http_requests_total[5m])
# 1-hour burn rate  
rate(http_requests_total{status=~"5.."}[1h])
/ rate(http_requests_total[1h])
# Alert when fast AND slow windows both exceed threshold
(burn_rate_5m > 14.4) and (burn_rate_1h > 14.4)

4. Kubernetes Pod Resource Monitoring

# CPU throttling ratio per pod
sum by (pod, namespace) (
  rate(container_cpu_cfs_throttled_seconds_total[5m])
)
/ sum by (pod, namespace) (
  rate(container_cpu_cfs_periods_total[5m])
)
# Memory usage vs limit
sum by (pod) (container_memory_working_set_bytes)
/ sum by (pod) (kube_pod_container_resource_limits{resource="memory"})

Accessing PromQL

Common Pitfalls

Using rate() on a gaugerate() is only meaningful for counters. Use plain values or delta() for gauges.

Too-short range windowsrate(metric[1m]) with a 15s scrape interval gives only ~4 samples. Use at least 4× your scrape interval as the window.

Label cardinality explosion — Adding high-cardinality labels like user_id to metrics will bloat your TSDB. Keep label values bounded.

Forgetting by in aggregationssum(metric) drops all labels. If you need a specific breakdown, always specify by (label1, label2).

The Mental Model

Think of PromQL as a pipeline:

raw time series
  → filter with label matchers
  → apply functions (rate, histogram_quantile)
  → aggregate across label dimensions (sum by, avg by)
  → compare or combine with operators (+, /, >, and)
  → single number or vector ready for alerting/dashboards

Once that pipeline clicks, even complex multi-step queries become readable.

Wrapping Up

PromQL has a learning curve — the vector model feels foreign at first — but it pays off fast. A handful of functions (rate, sum by, histogram_quantile, predict_linear) covers 90% of real-world monitoring needs. Start with the RED method for your services, layer in infrastructure metrics, and build alerting rules incrementally.

The best way to learn is the expression browser at http://your-prometheus:9090/graph. Type a metric name, add label filters, wrap in rate(), aggregate — within an hour you'll be writing queries that would have taken dozens of SQL lines.


메타데이터
post_id
188ff1ab51ca
slug
promql-the-query-language-that-makes-your-metrics-talk-188ff1ab51ca
url
https://medium.com/@puttt.spl/promql-the-query-language-that-makes-your-metrics-talk-188ff1ab51ca
canonical_url
https://medium.com/@puttt.spl/promql-the-query-language-that-makes-your-metrics-talk-188ff1ab51ca
author_url
https://medium.com/@puttt.spl
status
ok
fetched_at
2026-07-13 06:23:13