Prometheus 二进制发行版中包含的 promtool 工具允许我们定义测试用例来验证我们编写的规则是否符合预期。本章的测试环境还附带了一套针对我们迄今为止探索过的规则的预构建测试。你可以看看这里的配置:
vagrant@prometheus:~$ cat /etc/prometheus/tests.yml
该文件对本章中介绍的所有记录和警报规则进行了测试。尽管您不需要在单个文件中定义每个测试(事实上,为每个规则组创建一个测试文件以保持事物井井有条),但为了简单起见,在本例中这样做了。现在,让我们只分析记录规则,因为它们更容易掌握。测试文件的顶级配置键定义了要加载的规则文件和测试的默认评估间隔,当它们没有明确声明自己的规则评估时,它控制记录和警报规则评估的周期:
rule_files:
- /etc/prometheus/recording_rules.yml
...
evaluation_interval: 1m
虽然 测试文件中的
rule_files 配置键可能看起来与主 Prometheus 配置文件中的相同,它不支持通配符(使用文件名通配符)。
在这些全局配置之后是测试用例的定义,在 tests 键下。您可以定义多个测试包,每个测试包都有自己的模拟抓取间隔、收集的系列和正在测试的规则。让我们看一下文件中定义的第一个测试,我们在其中添加了一些注释以使其更易于理解:
tests:
interval 设置在我们的模拟时间序列中生成间隔样本的时间:
- interval: 15s
input_series 列表定义了要生成的时间序列以及在模拟收集间隔的每次迭代中要生成的值:
input_series:
- series: 'node_cpu_seconds_total{cpu="0",instance="prometheus:9100",job="node",mode="user"}'
values: '1 1 1 1 1 1 1 1 1 1'
- series: 'node_cpu_seconds_total{cpu="1",instance="prometheus:9100",job="node",mode="user"}'
values: '1 1 1 1 1 1 1 1 1 1'
- series: 'node_cpu_seconds_total{cpu="0",instance="example:9100",job="node",mode="idle"}'
values: '1 1 1 1 1 1 1 1 1 1'
- series: 'node_cpu_seconds_total{cpu="0",instance="example:9100",job="node",mode="system"}'
values: '1 1 1 1 1 1 1 1 1 1'
要测试的 PromQL 表达式列表定义为 promql_expr_test:
promql_expr_test:
每个 expr 定义一个特定的表达式:
- expr: instance:node_cpu:count
通过设置 eval_time 设置该表达式将运行的时间点,并且应通过将该表达式作为 exp_samples 运行来返回预期的样本:
eval_time: 1m
exp_samples:
- labels: 'instance:node_cpu:count{instance="prometheus:9100", job="node"}'
value: 2
- labels: 'instance:node_cpu:count{instance="example:9100", job="node"}'
value: 1
在这个测试包中,我们可以看到每 15 秒针对相同的指标 node_cpu_seconds_total 生成四个时间序列。由于这些系列的实际值与此记录规则无关(它只计算每个实例的 CPU 数量),因此为每个样本设置了 1 的值。请注意当前标签的变化,即 prometheus:9100 实例报告两个 CPU 的指标,而 example:9100 报告一个。实际测试只是验证,当在 t=1m 处评估 instance:node_cpu:count 表达式时(好像在生成的集合开始后经过了 1 分钟),返回的样本应显示每个实例的正确 CPU 计数。
我们现在准备使用以下指令执行测试:
vagrant@prometheus:/etc/prometheus$ promtool test rules tests.yml
Unit Testing: tests.yml
SUCCESS
这可确保配置的记录规则按照我们预期的方式运行。您可以尝试通过从 instance:node_cpu:count 测试包中的 prometheus:9100 实例中删除输入系列之一来打破测试。当您再次运行测试时,将显示以下内容,因为其中一个测试现在失败:
vagrant@prometheus:/etc/prometheus$ promtool test rules tests.yml
Unit Testing: tests.yml
FAILED:
expr:'instance:node_cpu:count', time:1m0s,
exp:"{__name__=\"instance:node_cpu:count\", instance=\"example:9100\", job=\"node\"} 1E+00, {__name__=\"instance:node_cpu:count\", instance=\"example:9100\", job=\"node\"} 1E+00, {__name__=\"instance:node_cpu:count\", instance=\"prometheus:9100\", job=\"node\"} 2E+00",
got:"{__name__=\"instance:node_cpu:count\", instance=\"example:9100\", job=\"node\"} 1E+00, {__name__=\"instance:node_cpu:count\", instance=\"example:9100\", job=\"node\"} 1E+00, {__name__=\"instance:node_cpu:count\", instance=\"prometheus:9100\", job=\"node\"} 1E+00"
这个输出告诉我们的是 promtool 期待定义的样本集,但返回了不同的样本集。您可以看到,正如我们配置的那样,记录规则现在只为 prometheus:9100 实例报告一个 CPU。这让我们确信规则的行为完全符合我们的要求。
第二个记录规则组的测试基本相同,但它们展示了一个强大的符号来生成更丰富的输入序列:
- interval: 5s
input_series:
- series: 'prometheus_http_request_duration_seconds_count{handler="/",instance="localhost:9090",job="prometheus"}'
values: '0+5x60'
- series: 'prometheus_http_request_duration_seconds_sum{handler="/",instance="localhost:9090",job="prometheus"}'
values: '0+1x60'
这称为扩展符号。这是声明随时间生成时间序列值的公式的简洁方式。它采用 A+BxC 或 A-BxC 的形式,其中 A 是起始值,B是序列值在每次迭代中应该具有的增加量(当以 + 开头时)或减少(当以 - 开头时),并且 C 是应该应用这个增加或减少的迭代次数。
回到我们的示例,0+5x60 将扩展为以下系列:
0 5 10 15 20 … 290 295 300
在声明输入时间序列的值时,您可以将文字值与扩展符号混合和匹配。这使您可以轻松创建复杂的行为。举个例子:
0 1 1 0 1+0x3 0 1 1 0 1 1 0 0 0 1 1 0+0x3 1
这将扩展为以下内容:
0 1 1 0 1 1 1 1 0 1 1 0 1 1 0 0 0 1 1 0 0 0 0 1
测试是避免不可预见问题的基础,根据目前介绍的信息,您现在可以生成自己的单元测试来记录规则。接下来,我们将继续处理单元测试,但这次专门与警报规则相关。