18

I have 2 different metrics : metric_a with a field type metric_b with a field type (same one)

I'm trying to summarise a and b, of the same type. If type exists only on metric_a and not on metric_b - it should return metric_b's result. I've tried a lot of options on prometheus:

sum by (type)(metric_a{job=~"provision-dev"}) or vector(0) + sum by(type)(metric_b{job=~"provision-dev"}) or vector(0) : returns only the values from metric_a, and doesn't calculate metric_b's results.

sum by (type)(metric_a{job=~"provision-dev"}) + sum by(type)(metric_b{job=~"provision-dev"}) : returns only the values from metric_b, and doesn't calculate metric_a's results.

sum by (cluster_id)(provision_scale_out_failures{job=~"provision-dev"} + provision_scale_out_success{job=~"provision-dev"}) : well this isn't even a right query

Basically here's an example of a success :

metric_a :

  • type = type_1, sum = 5
  • type = type_2, sum = 2

metric_b :

  • type = type_1, sum = 4
  • type = type_3, sum = 3

result of the query :

  • type = type_1, sum = 9
  • type = type_2, sum = 2
  • type = type_3, sum = 3

2 Answers 2

16

This is the expected behavior when using a binary operator: both side must have a matching label set to be taken into account.

If you want to be able to aggregate both side and get the single one, you first must get the union of different metrics using the __name__ label:

 sum by(__name__,type)(metric_a{job=~"provision-dev"}) or on(__name__) sum by(__name__,type)(metric_b{job=~"provision-dev"})

You can cascade the aggregation operator:

sum by (type) (sum by (__name__,type)(metric_a{job=~"provision-dev"}) or on(__name__) sum by(__name__,type)(metric_b{job=~"provision-dev"}))

Finally, you can also compact everything into:

sum by (type) ({__name__=~"metric_a|metric_b",job=~"provision-dev"})
2
  • This works great, but I have a question, do you know how to add a Range operation to the sum? I tried sum by(type) (idelta({__name__=~"metric_a|metric_b", name=~"my_thing"}[5m])) but I get an execution: vector cannot contain metrics with the same labelset error.
    – Juan Perez
    Commented Feb 17 at 15:00
  • 1
    See stackoverflow.com/questions/68944000/… Commented Feb 17 at 23:10
9

The following PromQL query should sum metric_a and metric_b by type:

(sum(metric_a) by (type) + sum(metric_b) by (type))
or
(sum(metric_a) by (type) unless sum(metric_b) by (type))
or
(sum(metric_b) by (type) unless sum(metric_a) by (type))

How it works:

  • The sum(metric_a) by (type) + sum(metric_b) by (type) sums time series with matching type label values on both sides of + according to matching rules
  • The sum(metric_a) by (type) unless sum(metric_b) by (type) returns sum(metric_a) by (type) results for type label values missing in sum(metric_b) by (type). See docs about unless operator.
  • The sum(metric_b) by (type) unless sum(metric_a) by (type) returns sum(metric_a) by (type) results for type label values missing in sum(metric_a) by (type).

Then results from these three queries are joined with or operator.

This query is equivalent to the query proposed by Michael: sum({__name__=~"metric_a|metric_b"}) by (type) .

P.S. This query can be simplified further when using MetricsQL:

sum(metric_a, metric_b) by (type)

This query works, since sum() function in MetricsQL accepts and sums arbitrary number of arguments.

2
  • 1
    Thank you! This form saved me (vs the name one), since I could apply rate to the metrics within the sum this way too. With the name form, prometheus was not very happy.
    – ron
    Commented Feb 10, 2023 at 7:37
  • @valyala thanks, another question, how to calc sum(redis_max_bytes) when redis_up=1 by both shared label redis_url?
    – Panic
    Commented Apr 11 at 8:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.