PromQL if/else like expression

28.1k views Asked by At

I'm trying to calculate easter sunday in PromQL using Gauss's Easter algorithm (I need to ignore some alert rules on public holidays).

I can calculate the day, but I'm having a problem with the month as I need something like an if/else expression. My recording rule easter_sunday_in_april returns 1 if eastern is in april and 0 if it is in march.

(How) can I express the following in PromQL?

if(easter_sunday_in_april > 0)
    return 4
else
    return 3

For the sake of completeness, I attach my recording rules here:

- record: a
    expr: year(europe_time) % 4

  - record: b
    expr: year(europe_time) % 7

  - record: c
    expr: year(europe_time) % 19

  - record: d
    expr: (19*c + 24) % 30

  - record: e
    expr: (2*a + 4*b + 6*d + 5) % 7

  - record: f
    expr: floor((c + 11*d + 22*e)/451)

  - record: easter_sunday_day_of_month_temp
    expr: 22 + d +e - (7*f)


  - record: easter_sunday_day_of_month_in_april
    expr: easter_sunday_day_of_month_temp > bool 31

  - record: easter_sunday_day_of_month
    expr: easter_sunday_day_of_month_temp % 31
3

There are 3 answers

0
valyala On BEST ANSWER

The

if(easter_sunday_in_april > 0)
    return 4
else
    return 3

can be expressed as the following PromQL query:

(vector(4) and on() (easter_sunday_in_april > 0)) or on() vector(3)

It uses and and or logical operators and on() modifier.

P.S. This query can be expressed in more easy-to-understand form with MetricsQL via if and default operators:

(4 if (easter_sunday_in_april > 0)) default 3

MetricsQL is PromQL-like query language provided by VictoriaMetrics - the project I work on.

0
Mirco On

Think I found a way:

((easter_sunday_day_of_month_temp > bool 31 ) +3)

easter_sunday_day_of_month_temp returns the "raw" day of month of easter sunday (1-31: day in march, > 31 day in april, we must calculate modulo 31 to get the day in april).

So if easter_sunday_day_of_month_temp > bool 31 is true, it returns 1 and I add 3 to get 4 (April), otherwise, I return 3 for March.

Edit: Please proof me wrong or show me a better solution :-) otherwise I'll accept mine in two days.

0
Bryan On

From Julien Pivotto's PromCon talk: https://promcon.io/2019-munich/talks/improved-alerting-with-prometheus-and-alertmanager/

groups:
- name: Easter Meeus/Jones/Butcher Algorithm
interval: 60s
rules:
- record: easter_y
expr: year(belgium_localtime)
- record: easter_a
expr: easter_y % 19
- record: easter_b
expr: floor(easter_y / 100)
- record: easter_c
expr: easter_y % 100
- record: easter_d
expr: floor(easter_b / 4)
- record: easter_e
expr: easter_b % 4
- record: easter_f
expr: floor((easter_b +8 ) / 25)
- record: easter_g
expr: floor((easter_b - easter_f + 1 ) / 3)
- record: easter_h
expr: (19*easter_a + easter_b - easter_d - easter_g + 15 ) % 30
- record: easter_i
expr: floor(easter_c/4)
- record: easter_k
expr: easter_c%4
- record: easter_l
expr: (32 + 2*easter_e + 2*easter_i - easter_h - easter_k) % 7
- record: easter_m
expr: floor((easter_a + 11*easter_h + 22*easter_l) / 451)
- record: easter_month
expr: floor((easter_h + easter_l - 7*easter_m + 114) / 31)
- record: easter_day
expr: ((easter_h + easter_l - 7*easter_m + 114) %31) + 1

- record: public_holiday
expr: |
vector(1) and
day_of_month(belgium_localtime-86400) == easter_day
and month(belgium_localtime-86400) == easter_month
labels:
name: Easter Monday
- record: public_holiday
expr: |
vector(1) and
day_of_month(belgium_localtime-40*86400) == easter_day
and month(belgium_localtime-40*86400) == easter_month
labels:
name: Feast of the Ascension