PromQL Selectors
Introduction
Selectors are a fundamental component of PromQL (Prometheus Query Language) that allow you to filter and identify specific time series data from your metrics. In Prometheus, every time series is uniquely identified by its metric name and a set of key-value pairs called labels. Selectors provide a powerful mechanism to pinpoint exactly which time series you want to query.
Think of selectors as the "where clause" in SQL, enabling you to choose precisely which data points you want to examine from the vast collection of metrics stored in Prometheus.
Basic Selector Syntax
The most basic selector consists of a metric name enclosed in curly braces:
metric_name{}
This selects all time series with the given metric name. For example:
http_requests_total{}
This query returns all time series with the metric name http_requests_total
, regardless of their labels.
Label Matchers
To refine your selection, you can add one or more label matchers inside the curly braces. A label matcher consists of:
- A label name
- A matching operator
- A label value (usually in quotes)
Basic Label Matcher Example
http_requests_total{job="api-server", environment="production"}
This selects all http_requests_total
metrics where the job
label equals api-server
AND the environment
label equals production
.
Matching Operators
PromQL supports four types of matching operators:
Operator | Description | Example |
---|---|---|
= | Equals | {job="api-server"} |
!= | Not equals | {job!="api-server"} |
=~ | Regex matches | {job=~"api-.*"} |
!~ | Regex does not match | {job!~"api-.*"} |
Examples of Matching Operators
Equals (=
)
http_requests_total{status_code="200"}
Selects time series where status_code
exactly equals 200
.
Not Equals (!=
)
http_requests_total{status_code!="200"}
Selects time series where status_code
is not equal to 200
.
Regex Matches (=~
)
http_requests_total{path=~"/api/v[1-3]/.*"}
Selects time series where the path
label matches the regular expression /api/v[1-3]/.*
(paths starting with /api/v1/
, /api/v2/
, or /api/v3/
).
Regex Does Not Match (!~
)
http_requests_total{path!~"/static/.*"}
Selects time series where the path
label does not match the regular expression /static/.*
(paths not starting with /static/
).
Combining Multiple Label Matchers
You can combine multiple label matchers to create more specific selections:
http_requests_total{environment="production", job="api-server", method="GET", status_code=~"2.."}
This selects all HTTP requests where:
- The environment is "production"
- The job is "api-server"
- The HTTP method is "GET"
- The status code starts with "2" (2xx status codes)
When multiple label matchers are specified, they are combined with a logical AND operation - all conditions must be met for a time series to be selected.
Special Empty Label Matchers
You can also use empty label matchers to select time series based on the presence or absence of a label:
http_requests_total{handler=""}
This selects time series where the handler
label exists but has an empty value.
http_requests_total{handler=~".*"}
This selects time series where the handler
label exists (with any value).
Selecting by Metric Name Only
If you want to select all time series for a given metric without any label filtering, you can use:
http_requests_total
This is equivalent to:
http_requests_total{}
Real-World Examples
Let's explore some practical examples of using selectors in real-world scenarios:
Example 1: Monitoring Specific Services
Suppose you want to monitor the CPU usage of only your production database servers:
node_cpu_seconds_total{job="node-exporter", service="database", environment="production", mode="user"}
Example 2: Filtering Error Responses
To monitor the rate of HTTP errors on your API servers:
rate(http_requests_total{job="api-server", status_code=~"5.."}[5m])
This query:
- Selects HTTP request metrics for all API servers
- Filters for status codes in the 5xx range (server errors)
- Calculates the per-second rate over a 5-minute window
Example 3: Excluding Development Environments
To view the total memory usage across all production and staging environments, excluding development:
sum by (environment) (
node_memory_MemTotal_bytes{environment!="development"}
)
Example 4: Multiple Service Variants
If you want to monitor latency across different versions of your payment service:
histogram_quantile(0.95,
sum by (le, version) (
rate(request_duration_seconds_bucket{service="payment", version=~"v[1-3]"}[5m])
)
)
This query calculates the 95th percentile latency for payment services, but only for versions v1, v2, and v3.
Common Patterns and Best Practices
1. Start Broad, Then Refine
When debugging or exploring metrics, start with a broad selector and then add label matchers to narrow down your search:
# Start with all HTTP requests
http_requests_total
# Add environment
http_requests_total{environment="production"}
# Add service
http_requests_total{environment="production", service="authentication"}
# Add status code filter
http_requests_total{environment="production", service="authentication", status_code!="200"}
2. Use Regex Sparingly
Regular expressions are powerful but can be performance-intensive. When possible, use exact matching:
# Less efficient
http_requests_total{service=~"auth.*"}
# More efficient if you know the exact name
http_requests_total{service="authentication"}
3. Label Consistency
Maintain consistent label names and values across your metrics to make selectors more predictable:
# These should use the same label names
http_requests_total{environment="production", service="api"}
http_errors_total{environment="production", service="api"}
Visualizing Selector Matching Logic
The following diagram illustrates how selectors filter time series data:
Technical Details
Internal Representation
In Prometheus, selectors are internally represented as a tuple of metric name and label matchers. The label matchers are evaluated against all stored time series with the matching metric name to determine the final result set.
Performance Considerations
Prometheus optimizes selector evaluation by:
- First filtering by metric name (which is indexed)
- Then applying label matchers
- Caching frequently used selector results
For best performance:
- Be as specific as possible with your selectors
- Put the most restrictive label matchers first when possible
- Use exact matching (
=
and!=
) before regex matching (=~
and!~
)
Common Mistakes and Troubleshooting
1. Empty Result Sets
If your query returns no data, your selector might be too restrictive. Try removing label matchers one by one to identify which constraint is filtering out all results.
2. Too Many Results
If your query returns too many time series, your selector might be too broad. Add additional label matchers to narrow down the results.
3. Inconsistent Label Names
Watch out for inconsistencies in label names or values:
# This won't match if the actual label is "environment" (singular)
http_requests_total{environments="production"}
4. Regex Syntax Errors
Regular expression syntax errors will cause queries to fail:
# Invalid regex (unclosed bracket)
http_requests_total{path=~"/api/v[1-3/.*"}
Summary
PromQL selectors are a powerful mechanism for filtering and selecting time series data in Prometheus. By combining metric names with label matchers, you can precisely target the data you need for monitoring and alerting.
Key points to remember:
- Basic selectors consist of a metric name and optional label matchers
- Four matching operators:
=
,!=
,=~
, and!~
- Multiple label matchers are combined with logical AND
- Regular expressions provide flexible matching capabilities
- Start broad and refine your selectors as needed
- Consistent labeling makes selectors more predictable
Exercises
- Write a selector that matches all HTTP requests with status codes 400-499 (client errors).
- Create a selector that targets metrics from both "api-gateway" and "auth-service" jobs.
- Write a selector that excludes development environments but includes both staging and production.
- Create a selector that matches metrics where the
version
label is either missing or empty.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)