For now the only solution I have is with query duplication:
(
(sum(kafka_consumergroup_lag[1d]) by (consumergroup) >= 100)
* on(consumergroup) group_left(team)
catalog_entities_info
)
or ignoring(team) (sum(kafka_consumergroup_lag[1d]) by (consumergroup) >= 100)
First half will add team label where possible, and second or half will add missed data (important to merge vectors while ignoring added team label, otherwise we will have duplicates).
promql - join prometheus queries while keeping data from the left side - Stack Overflow
monitoring - How can I 'join' two metrics in a Prometheus query? - Stack Overflow
Error when using group_left in Prometheus - Stack Overflow
Prometheus add extra label on join request without using group statement? - Stack Overflow
What is the difference between group_left and group_right in Prometheus?
How can I group labels in a Prometheus query?
What is the job label in Prometheus?
You can use the argument list of group_left to include extra labels from the right operand (parentheses and indents for clarity):
(
max(consul_health_service_status{status="critical"})
by (service_name,status,node) == 1
)
+ on(service_name,node) group_left(env)
(
0 * consul_service_tags
)
The important part here is the operation + on(service_name,node) group_left(env):
- the
+is "abused" as a join operator (fine since0 * consul_service_tagsalways has the value 0) group_left(env)is the modifier that includes the extra labelenvfrom the right (consul_service_tags)
It is a good practice in Prometheus ecosystem to expose additional labels, which can be joined to multiple metrics, via a separate info-like metric as explained in this article. For example, consul_service_tags metric exposes a set of tags, which can be joined to metrics via (service_name, node) labels.
The join is usually performed via on() and group_left() modifiers applied to * operation. The * doesn't modify values for time series on the left side because info-like metrics usually have constant 1 values. The on() modifier is used for limiting the labels used for finding matching time series on the left and the right side of *. The group_left() modifier is used for adding additional labels from time series on the right side of *. See these docs for details.
For example, the following PromQL query adds env label from consul_service_tags metric to consul_health_service_status metric with the same set of (service_name, node) labels:
consul_health_service_status
* on(service_name, node) group_left(env)
consul_service_tags
Additional label filters can be added to consul_health_service_status if needed. For example, the following query returns only time series with status="critical" label:
consul_health_service_status{status="critical"}
* on(service_name, node) group_left(env)
consul_service_tags
The RHS has no instance label, so it's trying to match all those series to one on the LHS. Try max by (node, instance) (kube_node_labels{label_grid="true"})
The group_left() modifier expects that the right-hand side of * operator (and any other operator) contains only a single time series per each label=value set specified inside on() modifier. Otherwise it returns duplicate series for the match group error. See these docs for more details.
The solution is to specify the proper labels inside on() modifier, so every label=value set for these labels would have only a single time series on the right-hand side of * operator. The instance label is a good candidate to put inside on() modifier. The only issue is that the dcgm_gpu_utilization and kube_node_labels are collected from different targets with different TCP port numbers. So they have different instance label values (see these docs explaining how instance label is generated). This breaks matching rules for * operator, so the following query returns nothing:
floor(avg_over_time(dcgm_gpu_utilization{cluster_name="researchers"}[5m]))
* on (instance) group_left(node)
kube_node_labels{label_grid="true"}
This can be fixed by stripping the port number from instance label at both sides of * operator with the help of label_replace function:
label_replace(
floor(avg_over_time(dcgm_gpu_utilization{cluster_name="researchers"}[5m])),
"hostname",
"$1",
"instance",
"([^:]+):.+"
)
* on (hostname) group_left(node)
label_replace(
kube_node_labels{label_grid="true"},
"hostname",
"$1",
"instance",
"([^:]+):.+"
)
This query extracts hostname part from instance labels, puts it into a hostname label and then joins the left-hand side and the right-hand side time series on this label.