如何在Prometheus查询中“合并”两个指标?

53

我正在使用 consul exporter 将我的服务的健康和状态导入到 Prometheus 中。当 Consul 中的服务和节点状态为关键状态时,我想触发警报,然后在路由这些警报时使用从 Consul 中提取的标签。

根据这个讨论,我了解到服务标签可能会作为单独的指标导出,但是我不确定如何将一个系列与另一个系列连接起来,以便利用标签和健康状态。

例如,以下查询:

max(consul_health_service_status{status="critical"}) by (service_name, status,node) == 1

能够返回:

{node="app-server-02",service_name="app-server",status="critical"} 1

但我也想要这个系列中的 'env':

consul_service_tags{node="app-server-02",service_name="app-server",env="prod"} 1

将节点和服务名称连接起来,以单个系列的形式将以下内容传递给Alertmanager:

{node="app-server-02",service_name="app-server",status="critical",env="prod"} 1

我可以在我的路由中匹配 'env'。

有没有办法做到这一点?在我看来,似乎没有任何操作或函数可以让我像这样分组或连接。就我所知,标记已经需要成为consul_health_service_status指标上的标签。


这是一篇很好的文章,用可视化的方式描述了在Prometheus中如何连接向量。https://iximiuz.com/en/posts/prometheus-vector-matching/ - undefined
3个回答

70

您可以使用group_left的参数列表,从右操作数中包括额外的标签(为了清晰起见使用括号和缩进):

(
  max(consul_health_service_status{status="critical"}) 
  by (service_name,status,node) == 1
)
   + on(service_name,node) group_left(env)
(
   0 * consul_service_tags
)

这里重要的部分是操作 + on(service_name,node) group_left(env):

  • +被“滥用”为连接运算符(因为0 * consul_service_tags始终为0,所以可以这样做)
  • group_left(env)是修改器,它从右侧(consul_service_tags)包含额外的标签env

1
一个改进的方法是强制加入的度量不影响你的度量,可以像这样做(添加一个被强制为0的度量):+ on(service_name,node) group_left(env) (0 *consul_service_tags) - Elad Amit
@EladAmit - 是的,太棒了!谢谢。我已经修改了帖子以反映您的改进。 - user2361830
2
consul_service_tags is always 1, so instead of the * 0 and +, a simpler way of doing this is more like (max(consul_health_service_status{status="critical"}) by (service_name,status,node) == 1) * on(service_name,node) group_left(env) consul_service_tags - gwk
4
如果你和我几个小时前一样看不懂这篇PromQL入门指南,那么我建议你使用这篇好的入门指南。 :joy: (注:上文中的笑脸表情是在用幽默语气说话,并非字面意思) - mgalgs

7
在Prometheus生态系统中,公开附加标签是一个好的做法。这些标签可以通过类似于info的指标单独公开,并可以与多个度量相关联,如this article所述。例如,consul_service_tags指标公开了一组标签,可以通过(service_name, node)标签与度量相关联。
通常,使用on()group_left()修饰符将这些标签与度量进行连接,然后应用*操作。由于info类指标通常具有恒定的1值,因此*不会修改左侧时间序列的值。使用on()修饰符限制用于查找匹配左右两侧时间序列的标签。使用group_left()修饰符从右侧时间序列中添加其他标签。有关详细信息,请参见these docs
例如,下面的 PromQL 查询将从 consul_service_tags 指标中添加 env 标签到具有相同一组 (service_name, node) 标签的 consul_health_service_status 指标中:
consul_health_service_status
  * on(service_name, node) group_left(env)
consul_service_tags

如果需要,可以向consul_health_service_status添加其他标签过滤器。例如,以下查询仅返回具有status="critical"标签的时间序列:
consul_health_service_status{status="critical"}
  * on(service_name, node) group_left(env)
consul_service_tags

有没有办法从右侧添加所有标签,而不是在group_left()中指定标签列表? - undefined
Prometheus无法提供从group_left()右侧选择所有标签的功能,但是在VictoriaMetrics中可以通过group_left(*)语法实现。请参阅https://stackoverflow.com/questions/76661818/how-to-add-namespace-labels-to-pod-labels-in-prometheus - undefined

1
这个问题的答案是准确的。我还想分享一下关于加入两个指标并保留相同标签的更清晰解释(可能不是直接回答这个问题)。在这些指标中,以下标签是存在的:
  • 名称(例如:aaa、bbb、ccc)
我有一个叫做 metric_a 的指标,如果该指标没有某些标签的数据,则希望从 metric_b 获取数据。即:
  • metric_a 对 {name="aaa"} 和 {name="bbb"} 有值
  • metric_b 对 {name="ccc"} 有值
我希望所有三个名称标签的输出结果。解决方法是在Prometheus中使用 or
sum by (name) (increase(metric_a[1w]))
or
sum by (name) (increase(metric_b[1w]))

这将会得到 {name="aaa"}, {name="bbb"} 和 {name="ccc"} 的数值结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接