You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prometheus告警规则单元测试:如何Mock hour()函数?

解决Prometheus告警规则测试中Mock hour()函数的问题

首先先修正你告警规则里的语法错误:(hour()) < 16 > 7 是无效的PromQL表达式,正确的工作时段判断应该写成 hour() > 7 and hour() < 16,否则规则本身无法正常执行。

针对Mock hour() 函数的需求,核心思路是通过控制规则的评估时间来间接控制hour()的返回值——因为hour()函数的结果完全依赖于Prometheus执行规则时的当前时间(或者说评估时间)。下面是两种常用的实现方式:

1. 使用promtool进行规则测试(官方工具)

promtool是Prometheus官方提供的规则测试工具,你可以通过指定evaluation_time来模拟不同的时间点,从而让hour()返回预期的小时数。

示例测试文件

创建一个alert_test.yaml测试文件,包含两种场景的测试:

groups:
- name: service_alerts
  rules:
  - alert: CounterStuckDuringWorkHours
    expr: round(sum(increase(counter_total{cluster="prod",service="xxx"}[1h])),1) == 0 and hour() > 7 and hour() < 16
    for: 0m
    labels:
      severity: warning
    annotations:
      summary: "[prod] xxx服务计数器1小时无增长"

# 测试场景1:工作时段内计数器无增长,预期触发告警
tests:
- interval: 1m
  evaluation_time: "2024-05-20T09:30:00Z" # 模拟上午9点30分,hour()返回9
  input_series:
  - series: 'counter_total{cluster="prod",service="xxx"}'
    values: '25 25 25 25 25 25 25' # 连续60个1分钟样本数值不变(这里简化为7个),increase计算为0
  alert_rule_test:
  - alertname: CounterStuckDuringWorkHours
    eval_time: 2024-05-20T09:30:00Z
    exp_alerts:
    - labels:
        severity: warning
      annotations:
        summary: "[prod] xxx服务计数器1小时无增长"

# 测试场景2:非工作时段计数器无增长,预期不触发告警
- interval: 1m
  evaluation_time: "2024-05-20T18:00:00Z" # 模拟下午6点,hour()返回18
  input_series:
  - series: 'counter_total{cluster="prod",service="xxx"}'
    values: '25 25 25 25 25 25 25'
  alert_rule_test:
  - alertname: CounterStuckDuringWorkHours
    eval_time: 2024-05-20T18:00:00Z
    exp_alerts: [] # 预期无告警输出

运行测试

执行以下命令即可运行测试:

promtool test rules alert_test.yaml

2. 自定义代码测试(如Go测试框架)

如果你的团队用自定义代码编写测试(比如基于Prometheus的Go客户端库),可以通过Mock系统时间来控制hour()的返回值:

  • 使用Go的time包Mock工具(比如github.com/benbjohnson/clock),将当前时间设置为你需要的测试时间点。
  • 在评估告警规则前,把Prometheus的评估时间替换为Mock的时间,这样hour()就会返回对应时间的小时数。

举个简化的Go测试片段:

package alerttests

import (
	"testing"
	"time"

	"github.com/benbjohnson/clock"
	"github.com/prometheus/prometheus/model/labels"
	"github.com/prometheus/prometheus/promql"
)

func TestCounterStuckAlert(t *testing.T) {
	// 创建Mock时钟,设置为工作时段
	mockClock := clock.NewMock()
	mockClock.Set(time.Date(2024, 5, 20, 10, 0, 0, 0, time.UTC))

	// 构造测试样本数据(计数器1小时无增长)
	series := promql.NewSeriesIterator(&promql.Series{
		Labels: labels.FromStrings("cluster", "prod", "service", "xxx"),
		Points: []promql.Point{{T: mockClock.Now().Unix() - 3600, V: 10}, {T: mockClock.Now().Unix(), V: 10}},
	})

	// 评估告警规则时使用Mock时间
	// 省略规则解析和评估的具体代码,核心是让评估逻辑使用mockClock.Now()作为当前时间
}

关键注意点

  • hour()函数返回的是UTC时间的小时数,如果你需要的是本地时间,得用hour(timezone("Asia/Shanghai"))这类表达式,测试时也要对应设置UTC时间到目标时区的工作时段。
  • 测试increase()函数时,要确保输入的样本时间范围覆盖规则里的[1h]窗口,否则increase()会返回空值,影响测试结果。

内容的提问来源于stack exchange,提问作者Mr. Invisible

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 07:17:41