Number and Duration Literals Are Now Interchangeable in PromQL

August 19, 2024 by Julius Volz

Prometheus' 2.54.0 release added experimental support for using duration literals interchangeably with number literals in PromQL. Here's what this means and why it's useful.

Number and duration literals

Number literals in PromQL are simply spelled-out numeric floating point values such as 5, 1.23, 0xef, or Inf. Number literals are their own PromQL syntax tree node and thus represent a full PromQL (sub)expression. In practice, you usually see them being used in the context of binary operators or as function parameters. Let's look at a few examples.

Number literal examples

You could use a number literal as the first parameter to the topk() aggregator to show the top 3 request rates:

topk(3, rate(http_requests_total[5m]))

You could also use number literals to convert a set of memory usages in bytes to mebibytes (MiB) and then only return the time series that represent usages greater than 20 MiB:

memory_usage_bytes / 1024^2 > 20

Duration literal examples

Duration literals are specifiers such as 5m (5 minutes) or 1h5m30s (1 hour, 5 minutes, and 30 seconds) that you allow you to select the desired duration for an operation. Up until now, duration literals couldn't be used as a standalone PromQL expression and were only allowed in special places of the PromQL syntax.

For example, as the data selection duration of a range vector selector:

http_requests_total[5m]

Or as the time-shifting duration parameter of an offset modifier:

memory_usage_bytes offset 1w

Or as the range and resolution parameters of a subquery:

max_over_time(
    rate(
        http_requests_total[5m]
    )[1d:15s] # Run the subquery over a 1-day range with a 15-second resolution.
)

Usability problem: Some numbers are semantically durations

However, there are cases in PromQL where number literals are semantically durations (usually in seconds), but where the PromQL syntax didn't allow you to use a duration literal syntax. Let's look at two prominent examples:

The second parameter of the predict_linear() function is semantically a duration in seconds, telling the function how far into the future it should extrapolate a set of gauge values:

# Predict the value in 24 hours, based on the behavior of the last 4 hours.
predict_linear(disk_usage_bytes[4h], 24 * 60 * 60)

You may also want to compare one duration with another. For example, you could query for all hosts that have been running for more than 30 days:

time() - node_boot_time_seconds > 30 * 24 * 60 * 60

As you can see, having to write out durations in seconds like this can become cumbersome and error-prone.

The solution: Making number and duration literals interchangeable

Starting with Prometheus version 2.54.0, Darshan Chaudhary has added experimental support for using duration literals in place of numbers, and vice versa. The support is enabled by default, but may still change due to its experimental nature. As Prometheus generally advises keeping metrics in base units, and numeric durations also occur most commonly in seconds in PromQL, a given duration literal now translates into an equivalent number of seconds when used as a PromQL expression.

So the following are now equivalent in PromQL:

  • 1s and 1
  • 5m and 300 or 5 * 60
  • 10ms and 0.01

This means you can now write the above duration expressions more naturally:

predict_linear(disk_usage_bytes[4h], 24h)

And:

time() - node_boot_time_seconds > 30d

As a result, PromQL expressions involving numeric numbers will now be easier to write and understand.

Note: In Prometheus 2.54.0, the UI will still show a linter error for duration literals used as numeric PromQL expressions and not highlight them properly yet:

Prometheus 2.54.0 linter error for duration literal expressions

This has already been fixed in a followup Pull Request by Augustin Husson and should be working fine in the next Prometheus release.

Since the two syntactical elements are now interchangeable, you could even use a number as a duration now, like:

rate(http_requests_total[300])

However, this is generally not going to be as useful as the reverse case.

Note also that binary operations such as 1d * 30 are still only possible in places where the duration literal represents a full PromQL expression. So you still would not be able to query for something like memory_usage_bytes[1d * 30], since the contents of the square brackets are syntactically part of a range vector selector and not a full PromQL expression that can be multiplied with another number.

Conclusion

As we've seen, the new support in Prometheus 2.54.0 for treating number literals and duration literals interchangeably will make PromQL use cases involving numeric durations much more natural to read and write.

If you want to understand more about Prometheus and PromQL, you may also want to take a look at our Prometheus training courses, especially our Understanding PromQL training.


August 19, 2024 by Julius Volz

Tags: promql, durations, numbers, literals