PromQL: An Introduction


We run MuleSoft Mule Runtimes Standalone on Linux servers. We need those runtimes to stay healthy. We need to know when a CPU spikes, when memory fills up, or when a disk runs out of space. Prometheus collects those metrics. But collecting them is only half the job. We need to query them.


That is where PromQL comes in.


What Is PromQL?

PromQL stands for Prometheus Query Language. It is the language we use to read and compute data stored in Prometheus. We use it to ask Prometheus specific questions about the metrics it collects.
For example:
  • What is the current CPU usage on my MuleSoft host?
  • What is the average memory used over the last 5 minutes?
  • Is the disk on this server more than 85% full?
PromQL answers all of those questions.

New to Prometheus? Before we go further, we recommend reading our earlier posts in this series:
Those posts walk us through setting up a Prometheus server that scrapes metrics from a Linux host using Node Exporter. The examples in this series will use that exact setup.


Where Do We Use PromQL?


We write PromQL queries in three places. The diagram above shows how they all connect. Prometheus scrapes metrics from Node Exporter on our Linux server. The PromQL engine inside Prometheus then answers queries from the Prometheus UI, Grafana, and Alertmanager.

The Prometheus UI lives at http://<our-server>:9090. We open it in a browser and type PromQL queries directly. It is the fastest way to explore metrics and test queries. We will use it throughout this series of posts.

Grafana connects to Prometheus as a data source. Every panel in a Grafana dashboard runs a PromQL query behind the scenes. We write PromQL to define what each panel shows — CPU graphs, memory gauges, disk heatmaps.

Alerting rules live in Prometheus configuration files. We write PromQL expressions to define alert conditions. When the expression returns results, Prometheus fires the alert to Alertmanager.


The Node Exporter Context

In our setup, Prometheus scrapes a Linux server running Node Exporter on port 9100. Node Exporter exposes hundreds of metrics about the host OS. 

A few metrics we will see throughout this series:

Metric nameWhat it measures
node_cpu_seconds_totalCPU time spent in each mode (idle, user, system, etc.)
node_memory_MemAvailable_bytesAvailable memory in bytes
node_filesystem_avail_bytesFree disk space on each mount point
node_load11-minute load average
node_network_receive_bytes_totalNetwork bytes received per interface

These metrics are what we will query with PromQL.


PromQL Data Types

Before we start, just remember what a time series is - A time series is a sequence of numeric values recorded at regular intervals over time, identified by a unique set of labels.

Every PromQL query returns one of four result types. Understanding these types is essential. They determine what we can do with a result — display it, calculate with it, or feed it into a function.
The diagrams above show all four types with real examples. Let's walk through each one.


Instant Vector

An instant vector is the most common result type. It returns one value per time series, measured at a single point in time.
When we type a metric name directly into the Prometheus UI, we get an instant vector:
node_load1

Prometheus will return one result for each unique combination of labels it has seen for that metric. For example:

node_load1{instance="192.168.1.10:9100", job="node"}  0.21

Each result has a 
metric name, a set of labels, and a numeric value. That is one element of an instant vector.

We will use instant vectors for dashboards and alerts where we want the current value of something.


Range Vector

A range vector returns a set of samples over a time window for each series. We define the window using a duration in square brackets.

node_load1[5m]

This returns all the samples Prometheus collected for 
node_load1 in the last 5 minutes. For a 15-second scrape interval, that is about 20 samples per series.

Range vectors are not displayed directly. We will pass them to functions such as rate() or avg_over_time() to compute something meaningful from that window of data. We will cover those functions in detail later in this series.


Scalar

A scalar is a single floating-point number with no labels. It carries no time series context.

scalar(node_load1{instance="192.168.1.10:9100",job="node"})

The 
scalar() function converts a single-element instant vector into a plain number. We use scalars in arithmetic expressions — for example, dividing by a fixed value or comparing against a threshold.


String

A string is a plain text value. Prometheus supports strings in the language but they have almost no practical use in day-to-day queries. Functions that return metadata sometimes use strings internally. We will mention them when relevant but will not focus on them in this series of posts.


Our First Real Queries

We will open the Prometheus UI at http://<our-server>:9090 and try these three queries. Each one returns a different data type.

Instant vector — current load average:
node_load1

This will return the current 1-minute load average for our Linux host. We will see one result with the 
instance and job labels attached.


Range vector — load average samples over 5 minutes:
node_load1[1m]

We will see multiple timestamped samples for the same series. Prometheus will display them as a raw list in the UI.



Scalar — available memory in gigabytes:
node_memory_MemAvailable_bytes / (1024 * 1024 * 1024)

This divides the raw bytes value by 1 GB. The result is a clean number we can read directly. This is arithmetic on an instant vector — a pattern we will use constantly.



Summary

PromQL is the query language for Prometheus. We write it in the Prometheus UI to explore metrics, in Grafana to build dashboards, and in alerting rules to trigger alerts. Every query returns one of four data types: an instant vector, a range vector, a scalar, or a string. Instant vectors give us the current value of a metric. Range vectors give us a window of samples. Scalars strip labels and return a single number.

In the next post, we will go deeper. We will learn how to use selectors and matchers to filter metrics by their labels — and how to use modifiers such as offset and @ to query data at a specific point in time. Those two tools will unlock far more powerful queries.

 

Previous Post Next Post