PROMETHEUS
Last reviewed: 2026-06-16
Purpose: Comprehensive knowledge base article covering Prometheus architecture, PromQL fundamentals, all functions and operators, and a library of practical production queries.
Table of Contents
- Architecture Overview
- PromQL Data Types
- Selectors & Matchers
- Modifiers: Offset & @
- Binary Operators
- Aggregation Operators
- PromQL Functions by Category
- Counter Functions
- Gauge Functions
- Histogram Functions
- Aggregation Helpers
- Time & Date Functions
- Label Manipulation Functions
- Math & Utility Functions
- Common Queries
Architecture Overview
Prometheus is an open-source systems monitoring and alerting toolkit originally built at SoundCloud. Its core components:
| Component | Role |
|---|---|
| Prometheus Server | Scrapes and stores time-series data, evaluates rules, serves queries |
| Targets | Endpoints exposing metrics (typically /metrics via HTTP) |
| Service Discovery | Automatically finds targets (Kubernetes, Consul, DNS, file-based, etc.) |
| Alertmanager | Handles deduplication, grouping, silencing, and routing of alerts |
| Pushgateway | Accepts short-lived job metrics for scraping (used for batch/cron jobs) |
| Exporters | Third-party agents that translate non-Prometheus metrics (node_exporter, blackbox_exporter, etc.) |
| Recording Rules | Pre-compute expensive queries for faster dashboard rendering |
| Alerting Rules | Define alert conditions based on PromQL expressions |
Data model: Every time series is identified by a metric name and a set of key-value labels. Samples are (timestamp, value) pairs.
Pull model: Prometheus scrapes targets on a schedule (configured via scrape_interval), unlike push-based systems.
PromQL Data Types
PromQL expressions evaluate to one of four data types:
| Type | Description | Example |
|---|---|---|
| Instant Vector | A set of time series with a single sample per series at the current evaluation timestamp | node_cpu_seconds_total |
| Range Vector | A set of time series with a range of samples over a time window | node_cpu_seconds_total[5m] |
| Scalar | A single numeric value | 42, 3.14 |
| String | A string value (rarely used, only inๆไบ functions) | "info" |
Instant vector is the default; you use it for comparisons, aggregations, and most queries.
Range vector is obtained by appending a duration in square brackets: [5m], [1h], [30s]. Required by rate()-family functions.
Selectors & Matchers
Metric Name Selector
The simplest selector is just a metric name:
Returns all time series with that metric name.
Label Matchers
Filter series by label values using matchers inside curly braces {}:
| Matcher | Meaning | Example |
|---|---|---|
= |
Equals | {job="prometheus"} |
!= |
Not equals | {job!="prometheus"} |
=~ |
Regex matches | {job=~"node|prometheus"} |
!~ |
Regex not matches | {job!~".*exporter"} |
Implicit __name__ Matcher
The metric name itself is a label __name__. These are equivalent:
Modifiers: Offset & @
Offset Modifier
Shift a query backward in time. Useful for comparing current values to a previous period.
# Memory usage now vs. 1 hour ago
node_memory_MemTotal_bytes - (node_memory_MemFree_bytes offset 1h)
@ Modifier
Evaluate a query at a specific Unix timestamp (in seconds).
# The value of this metric at exactly 2025-01-01 00:00:00 UTC
prometheus_http_requests_total @ 1735689600
Can be combined with offset and range vectors.
Binary Operators
Arithmetic Operators
| Operator | Meaning |
|---|---|
+ |
Addition |
- |
Subtraction |
* |
Multiplication |
/ |
Division |
% |
Modulo |
^ |
Power / exponentiation |
# CPU utilization percentage
(1 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[1m]))) * 100
Comparison Operators
| Operator | Meaning |
|---|---|
== |
Equal |
!= |
Not equal |
> |
Greater than |
< |
Less than |
>= |
Greater or equal |
<= |
Less or equal |
Comparison operators produce 0 (false) or 1 (true):
# Which nodes have less than 10% free space?
node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.1
Logical / Set Operators
| Operator | Meaning |
|---|---|
and |
Intersection โ returns LHS elements matching RHS |
or |
Union โ returns LHS elements, adding RHS elements not in LHS |
unless |
Subtraction โ returns LHS elements not present in RHS |
# Nodes that are up AND have high CPU
up == 1 and (1 - rate(node_cpu_seconds_total{mode="idle"}[5m])) > 0.9
Vector Matching
When binary operators involve two vectors, Prometheus matches them by labels:
- One-to-one (default): same labels on both sides
- Many-to-one / One-to-many: use
onorignoringwithgroup_left/group_right
# Many-to-one: divide by total count, ignoring 'mode'
rate(node_cpu_seconds_total[1m]) / ignoring(mode) group_left sum(rate(node_cpu_seconds_total[1m]))
Aggregation Operators
Aggregation operators combine series across dimensions. They always produce an instant vector.
Basic form: <aggregation>([parameter,] <expression>) [by|without (<label list>)]
| Operator | Description |
|---|---|
sum |
Sum over dimensions |
avg |
Average over dimensions |
min |
Minimum value |
max |
Maximum value |
count |
Count of series |
stddev |
Population standard deviation |
stdvar |
Population standard variance |
topk |
K largest values (returns series, not scalar) |
bottomk |
K smallest values |
quantile |
ฯ-quantile (0 โค ฯ โค 1) |
count_values |
Count of series with each unique value |
by vs without
by (<labels>)โ group by the specified labels onlywithout (<labels>)โ group by all labels except those listed
# Total requests per job
sum by(job) (prometheus_http_requests_total)
# Average CPU per instance (drops 'mode' label)
avg without(mode) (rate(node_cpu_seconds_total[5m]))
Examples for Each Aggregation Operator
# sum โ total HTTP requests across all handlers
sum(prometheus_http_requests_total)
# avg โ average request rate per instance
avg by(instance) (rate(prometheus_http_requests_total[5m]))
# min โ node with lowest free memory
min by(instance) (node_memory_MemAvailable_bytes)
# max โ node with highest free memory
max by(instance) (node_memory_MemAvailable_bytes)
# count โ how many distinct handler/code combinations have errors
count by(handler) (prometheus_http_requests_total{code=~"5.."})
# topk โ top 5 CPU-consuming processes
topk(5, rate(process_cpu_seconds_total[1m]))
# bottomk โ bottom 10 by free memory
bottomk(10, node_memory_MemAvailable_bytes)
# quantile โ 95th percentile of request duration (from a Summary/Histogram)
quantile(0.95, rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))
# stddev โ standard deviation of request rates across instances
stddev by(job) (rate(prometheus_http_requests_total[5m]))
# stdvar โ variance of request rates
stdvar by(job) (rate(prometheus_http_requests_total[5m]))
# count_values โ how many instances report each CPU count value
count_values("cpu_count", node_cpu_seconds_total{mode="idle"})
PromQL Functions by Category
Counter Functions
Counters are monotonically increasing. Use these functions to derive rates and deltas.
rate()
Signature: rate(v range-vector) -> instant-vector
Description: Calculates the per-second average rate of increase of a counter over the specified time window. Handles counter resets correctly. The most commonly used PromQL function.
Explanation: Takes the counter's value at start and end of the 5m window, computes (end - start) / 300 seconds.irate()
Signature: irate(v range-vector) -> instant-vector
Description: Calculates the instantaneous rate based on the last two data points in the range window. More volatile than rate(), useful for spotting spikes.
# Instantaneous HTTP requests per second (last two samples)
irate(prometheus_http_requests_total[1m])
increase()
Signature: increase(v range-vector) -> instant-vector
Description: Returns the total increase in a counter over the specified time window. Handles resets.
Explanation: Computes how many requests happened in the last hour by subtracting the counter value at the start from the value at the end. Equivalent torate(metric[1h]) * 3600.
Gauge Functions
Gauges can go up and down. These functions analyze their behavior.
delta()
Signature: delta(v range-vector) -> instant-vector
Description: Computes the difference between the first and last value of a gauge over the range window. Does not handle counter resets.
Explanation: Takes the last sample minus the first sample over 15m. If the current temperature is 25ยฐC and 15m ago it was 22ยฐC, result is 3.deriv()
Signature: deriv(v range-vector) -> instant-vector
Description: Calculates the per-second derivative of a gauge using simple linear regression over the range window.
Explanation: Fits a straight line to the samples in the 10m window and returns the slope in bytes/second. Negative means memory is being consumed (available decreasing).predict_linear()
Signature: predict_linear(v range-vector, t scalar) -> instant-vector
Description: Predicts the value of a gauge t seconds from now using linear regression over the range window.
# Predicted disk usage in 6 hours (21600 seconds)
predict_linear(node_filesystem_avail_bytes[1h], 21600)
idelta()
Signature: idelta(v range-vector) -> instant-vector
Description: Calculates the difference between the last two samples in a range vector. Useful for finding the most recent change.
Explanation: Takes the last sample minus the second-to-last sample in the 5m window. If samples are 15s apart, shows the change over ~15s.Histogram Functions
histogram_quantile()
Signature: histogram_quantile(ฯ scalar, b instant-vector) -> instant-vector
Description: Calculates the ฯ-quantile (0 โค ฯ โค 1) from a native Histogram or a classic Histogram metric (bucketed). For classic histograms, the second argument must be a rate() of the histogram bucket's _bucket metric.
# 99th percentile request latency (classic histogram)
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
le), and computes the 99th percentile. le is the "less than or equal" upper bound of each bucket.
# 50th, 90th, and 99th percentiles in one query
histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)),
histogram_quantile(0.90, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)),
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
Aggregation Helpers
count_values
Signature: count_values(output-label string, v instant-vector) -> instant-vector
Description: Counts the number of series that have each distinct value of the input metric.
# How many instances report each number of CPUs?
count_values("cpu_count", node_cpu_seconds_total{mode="idle"})
{cpu_count="4"} -> 3 and {cpu_count="8"} -> 2.
Time & Date Functions
time()
Signature: time() -> scalar
Description: Returns the current Unix timestamp in seconds (from the Prometheus server's system clock).
# Time elapsed since a metric changed (seconds since last scrape)
time() - process_start_time_seconds
timestamp()
Signature: timestamp(v instant-vector) -> instant-vector
Description: Returns the Unix timestamp of each sample in the instant vector.
Explanation: Eachup series has a sample from the last scrape. timestamp() returns the scrape timestamp, so you can identify stale targets.
changes()
Signature: changes(v range-vector) -> instant-vector
Description: Returns the number of times the value changed (not counting interval resets) within the range window.
# How many times did the leader election change in the last hour?
changes(etcd_server_leader_changes_seen_total[1h])
day_of_week()
Signature: day_of_week(v instant-vector) -> instant-vector
Description: Returns the day of the week (0=Sunday, 1=Monday, ..., 6=Saturday) for each sample's timestamp.
days_in_month()
Signature: days_in_month(v instant-vector) -> instant-vector
Description: Returns the number of days in the month for each sample's timestamp.
hour()
Signature: hour(v instant-vector) -> instant-vector
Description: Returns the hour (0โ23) of the day for each sample's timestamp.
minute()
Signature: minute(v instant-vector) -> instant-vector
Description: Returns the minute (0โ59) for each sample's timestamp.
month()
Signature: month(v instant-vector) -> instant-vector
Description: Returns the month (1โ12) for each sample's timestamp.
year()
Signature: year(v instant-vector) -> instant-vector
Description: Returns the four-digit year for each sample's timestamp.
Label Manipulation Functions
label_replace()
Signature: label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string) -> instant-vector
Description: Copies and transforms a label value via regex replacement. Creates a new time series set; does not modify the original.
Explanation: Forinstance="10.0.0.1:9090", the regex captures 10.0.0.1 into $1 and assigns it to a new label ip.
label_join()
Signature: label_join(v instant-vector, dst_label string, separator string, src_labels ...string) -> instant-vector
Description: Joins the values of multiple source labels into a single destination label, separated by the given separator.
Explanation: Ifjob="node" and instance="10.0.0.1:9100", the result gets job_instance="node/10.0.0.1:9100".
Math & Utility Functions
abs()
Signature: abs(v instant-vector) -> instant-vector
Description: Returns the absolute value of each sample.
absent()
Signature: absent(v instant-vector) -> instant-vector
Description: Returns an empty series if the expression has results, or a 1 if the expression has no results. Useful for alerting on missing metrics.
Explanation: Ifup{job="myapp"} has no data, returns {job="myapp"} -> 1. If data exists, returns nothing.
ceil()
Signature: ceil(v instant-vector) -> instant-vector
Description: Rounds each sample up to the nearest integer.
floor()
Signature: floor(v instant-vector) -> instant-vector
Description: Rounds each sample down to the nearest integer.
clamp()
Signature: clamp(v instant-vector, min scalar, max scalar) -> instant-vector
Description: Clamps each sample's value between a minimum and maximum.
# Clamp CPU percentage to 0-100 range
clamp(100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100), 0, 100)
clamp_min()
Signature: clamp_min(v instant-vector, min scalar) -> instant-vector
Description: Clamps values to be at least min. Values below min are raised to min.
clamp_max()
Signature: clamp_max(v instant-vector, max scalar) -> instant-vector
Description: Clamps values to be at most max. Values above max are lowered to max.
exp()
Signature: exp(v instant-vector) -> instant-vector
Description: Returns the exponential (e^x) of each sample.
log()
Signature: log(v instant-vector) -> instant-vector
Description: Returns the natural logarithm of each sample.
log2()
Signature: log2(v instant-vector) -> instant-vector
Description: Returns the base-2 logarithm of each sample.
log10()
Signature: log10(v instant-vector) -> instant-vector
Description: Returns the base-10 logarithm of each sample.
sqrt()
Signature: sqrt(v instant-vector) -> instant-vector
Description: Returns the square root of each sample.
sgn()
Signature: sgn(v instant-vector) -> instant-vector
Description: Returns the sign of each sample: -1 for negative, 0 for zero, 1 for positive.
round()
Signature: round(v instant-vector, to_nearest=1 scalar) -> instant-vector
Description: Rounds each sample to the nearest integer or to the nearest multiple of to_nearest.
sort()
Signature: sort(v instant-vector) -> instant-vector
Description: Returns series sorted ascending by value.
# Instances sorted by error rate (ascending)
sort(rate(prometheus_http_requests_total{code=~"5.."}[5m]))
sort_desc()
Signature: sort_desc(v instant-vector) -> instant-vector
Description: Returns series sorted descending by value.
# Instances sorted by error rate (descending)
sort_desc(rate(prometheus_http_requests_total{code=~"5.."}[5m]))
vector()
Signature: vector(s scalar) -> instant-vector
Description: Converts a scalar value into an instant vector with no labels. Useful in recording rules or calculations where a scalar needs to be treated as a vector.
Common Queries
1. Error Rate (Percentage)
# Percentage of HTTP 5xx responses in the last 5 minutes
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
* 100
2. Request Latency P99
# 99th percentile of request duration (classic histogram)
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job)
)
3. Request Latency P50 / P90 / P99 (All at Once)
# Three quantiles in a single query using label_replace trick
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))
and
histogram_quantile(0.90, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))
and
histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))
4. CPU Usage Per Instance (Percentage)
# CPU utilization per instance, as a percentage
(1 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))) * 100
5. CPU Usage Per Core
6. Memory Usage Percentage
# Memory used as percentage of total
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
7. Disk Space Percentage (Per Filesystem)
# Disk usage percentage, excluding tmpfs and devtmpfs
(node_filesystem_size_bytes{mountpoint!~"^/dev|^/run|^/sys|^/proc"}
- node_filesystem_avail_bytes{mountpoint!~"^/dev|^/run|^/sys|^/proc"})
/
node_filesystem_size_bytes{mountpoint!~"^/dev|^/run|^/sys|^/proc"}
* 100
8. Up / Down Targets
9. Memory Forecasting (Will we run out?)
# Predict available memory in 2 hours (7200s)
predict_linear(node_memory_MemAvailable_bytes[1h], 7200) < 0
10. Disk Fill Forecasting
# Predict disk space exhaustion in 24 hours (86400s)
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[4h], 86400) < 0
11. Compare Current vs. Last Week
# Request rate now vs. same time last week
rate(http_requests_total[5m]) / rate(http_requests_total[5m] offset 1w) - 1
12. Top 10 Services by Request Rate
13. Network I/O Rate
14. Scrape Duration and Samples
15. Service Uptime Over the Last 30 Days
# Percentage of time a target was up over the last 30 days
avg_over_time(up{job="myapp"}[30d]) * 100
16. Rate of Change in Request Errors (Acceleration)
# Second derivative of error count (rate of change of error rate)
deriv(rate(http_requests_total{status=~"5.."}[5m])[10m])
17. Alert: Metric Disappeared
18. Application Restart Detection
19. Memory per Process (with node_exporter)
20. Saturation: CPU Load vs. CPU Count
# Load average divided by number of CPUs (1.0 = fully saturated)
node_load1 / count by(instance)(node_cpu_seconds_total{mode="idle"})
Tips & Best Practices
| Practice | Recommendation |
|---|---|
Use rate() over irate() for dashboards |
rate() smooths spikes; irate() is good for troubleshooting spiky behavior |
Always use rate() with histograms |
Pass rate(..._bucket[5m]) into histogram_quantile(), never raw counters |
| Choose the right range window | For rate(), use at least 4ร the scrape interval (e.g., [5m] for 15s scrape) |
| Use recording rules | Pre-compute expensive queries that appear on multiple dashboards |
| Label hygiene | Keep label cardinality low; avoid labels with unlimited values (user IDs, emails, IPs) |
Prefer by over without |
by makes your intent explicit and avoids surprises if labels change |
| Always compare gauges with offset | Use offset to compare current vs. previous period for seasonality-aware alerts |
Alert on absent() for critical metrics |
Missing metrics are often worse than bad metrics |