探索PromQL

通过PromQL用户可以非常方便地对监控样本数据进行统计分析,PromQL支持常见的运算操作符,同时PromQL中还提供了大量的内置函数可以实现对数据的高级处理。在学习PromQL之前,还需要了解Prometheus的样本数据模型。PromQL作为Prometheus的核心能力除了实现数据的对外查询和展现,同时告警监控也是依赖PromQL实现的。

理解时间序列


初识Prometheus一文中我们使用Node Exporter采集主机数据,通过其暴露的HTTP服务,可以看到Prometheus采集到的当前主机所有监控指标的样本数据。

1
2
3
4
5
6
# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 386.33
# HELP node_load1 1m load average.
# TYPE node_load1 gauge
node_load1 0

其中非#开头的每一行表示当前Node Exporter采集到的一个监控样本:node_cpu_seconds_totalnode_load1表明了当前指标的名称、大括号中的标签则反映了当前样本的一些特征和维度、浮点数则是该监控样本的具体值。

样本

Prometheus会将所有采集到的样本数据以时间序列(time-series)的方式保存在内存数据库中,并且定时保存到硬盘上。time-series是按照时间戳和值的序列顺序存放的,我们称之为向量(vector). 每条time-series通过指标名称(metrics name)和一组标签集(labelset)命名。如下所示,可以将time-series理解为一个以时间为X轴的数字矩阵:

1
2
3
4
5
6
7
^
│ . . . . . . . . . . . . . . . . . . . node_cpu{cpu="cpu0",mode="idle"}
│ . . . . . . . . . . . . . . . . . . . node_cpu{cpu="cpu0",mode="system"}
│ . . . . . . . . . . . . . . . . . . node_load1{}
│ . . . . . . . . . . . . . . . . . .
v
<------------------ 时间 ---------------->

在time-series中的每一个点称为一个样本(sample),样本由以下三部分组成:

  • 指标(metric):metric name和描述当前样本特征的labelsets;
  • 时间戳(timestamp):一个精确到毫秒的时间戳;
  • 样本值(value):一个float64的浮点型数据表示当前样本的值。

指标

在形式上,所有的指标(Metric)都通过如下格式标示:

<metric name>{<label name>=<label value>, ...}

指标的名称(metric name)可以反映被监控样本的含义(例如prometheus_http_requests_total - 表示当前系统接收到的HTTP请求总量)。指标名称只能由ASCII字符、数字、下划线以及冒号组成并必须符合正则表达式[a-zA-Z_:][a-zA-Z0-9_:]*

标签(label)反映了当前样本的特征维度,通过这些维度Prometheus可以对样本数据进行过滤,聚合等。标签的名称只能由ASCII字符、数字以及下划线组成并满足正则表达式[a-zA-Z_][a-zA-Z0-9_]*

其中以__作为前缀的标签,是系统保留的关键字,只能在系统内部使用。标签的值则可以包含任何Unicode编码的字符。在Prometheus的底层实现中指标名称实际上是以__name__=<metric name>的形式保存在数据库中的,因此以下两种方式均表示的同一条time-series

1
prometheus_http_requests_total{code="200", handler="/metrics", instance="localhost:9090", job="prometheus"}

等同于

1
{__name__="prometheus_http_requests_total",code="200", handler="/metrics", instance="localhost:9090", job="prometheus"}

在Prometheus源码中也可以找到指标(Metric)对应的数据结构,如下所示

1
2
3
4
5
6
7
type Metric LabelSet

type LabelSet map[LabelName]LabelValue

type LabelName string

type LabelValue string

Metrics类型


在Prometheus的存储实现上所有的监控样本都是以time-series的形式保存在Prometheus内置的TSDB(时序数据库)中,而time-series所对应的监控指标(metric)也是通过labelset进行唯一命名的。

从存储上来讲所有的监控指标metric都是相同的,但是在不同的场景下这些metric又有一些细微的差异。 例如,在Node Exporter返回的样本中指标node_load1反应的是当前系统的负载状态,随着时间的变化这个指标返回的样本数据是在不断变化的。而指标node_cpu_seconds_total所获取到的样本数据却不同,它是一个持续增大的值,因为其反应的是CPU的累积使用时间,从理论上讲只要系统不关机,这个值是会无限变大的。

为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheus定义了4种不同的指标类型(metric type):Counter(计数器)Gauge(仪表盘)Histogram(直方图)Summary(摘要)

在Exporter返回的样本数据中,其注释中也包含了该样本的类型。例如

1
2
3
# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 386.33

Counter——只增不减的计数器

Counter类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)。常见的监控指标,如prometheus_http_requests_totalnode_cpu_seconds_total都是Counter类型的监控指标。 一般在定义Counter类型指标的名称时推荐使用_total作为后缀。

Counter是一个简单但有强大的工具,例如我们可以在应用程序中记录某些事件发生的次数,通过以时序的形式存储这些数据,我们可以轻松的了解该事件产生速率的变化。 PromQL内置的聚合操作和函数可以让用户对这些数据进行进一步的分析.

例如,通过rate()函数获取HTTP请求量的增长率

1
rate(prometheus_http_requests_total[5m])

查询当前系统中,访问量前10的HTTP地址

1
topk(10, prometheus_http_requests_total)

Gauge——可增可减的仪表盘

与Counter不同,Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。常见指标如:node_memory_MemFree_bytes(主机当前空闲的内存大小)、node_memory_MemAvailable_bytes(可用内存大小)都是Gauge类型的监控指标。

通过Gauge指标,用户可以直接查看系统的当前状态

1
node_memory_MemFree_bytes

对于Gauge类型的监控指标,通过PromQL内置函数delta()可以获取样本在一段时间返回内的变化情况。例如,计算硬件温度在两个小时内的差异

1
delta(node_hwmon_temp_celsius{instance="10.211.55.4:9100"}[2h])

还可以使用deriv()计算样本的线性回归模型,甚至是直接使用predict_linear()对数据的变化趋势进行预测。例如,预测系统磁盘空间在4个小时之后的剩余情况

1
predict_linear(node_filesystem_free_bytes{}[1h],4*3600)

使用Histogram和Summary分析数据分布情况

除了Counter和Gauge类型的监控指标以外,Prometheus还定义了Histogram和Summary的指标类型。Histogram和Summary主用用于统计和分析样本的分布情况。

在大多数情况下人们都倾向于使用某些量化指标的平均值,例如CPU的平均使用率、页面的平均响应时间。这种方式的问题很明显,以系统API调用的平均响应时间为例:如果大多数API请求都维持在100ms的响应时间范围内,而个别请求的响应时间需要5s,那么就会导致某些WEB页面的响应时间落到中位数的情况,而这种现象被称为长尾问题。

为了区分是平均的慢还是长尾的慢,最简单的方式就是按照请求延迟的范围进行分组。例如,统计延迟在0 ~ 10ms之间的请求数有多少而10 ~ 20ms之间的请求数又有多少。通过这种方式可以快速分析系统慢的原因。Histogram和Summary都是为了能够解决这样问题的存在,通过Histogram和Summary类型的监控指标,我们可以快速了解监控样本的分布情况。

例如,指标prometheus_tsdb_wal_fsync_duration_seconds的指标类型为Summary。 它记录了Prometheus Server中wal_fsync处理的处理时间,通过访问Prometheus Server的/metrics地址,可以获取到以下监控样本数据

1
2
3
4
5
6
7
# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.000788591
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.000788591
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.000788591
prometheus_tsdb_wal_fsync_duration_seconds_sum 0.000788591
prometheus_tsdb_wal_fsync_duration_seconds_count 1

从上面的样本中可以得知当前Prometheus Server进行wal_fsync操作的总次数为1次,耗时0.000788591s。其中中位数(quantile=0.5)的耗时为0.000788591,9分位数(quantile=0.9)的耗时为0.000788591。

在Prometheus Server自身返回的样本数据中,我们还能找到类型为Histogram的监控指标prometheus_tsdb_compaction_chunk_range_seconds_bucket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# HELP prometheus_tsdb_compaction_chunk_range_seconds Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range_seconds histogram
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="100"} 0
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="400"} 0
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="1600"} 0
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="6400"} 0
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="25600"} 2
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="102400"} 3
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="409600"} 1346
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="1.6384e+06"} 1360
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="6.5536e+06"} 6510
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="2.62144e+07"} 6511
prometheus_tsdb_compaction_chunk_range_seconds_bucket{le="+Inf"} 6511
prometheus_tsdb_compaction_chunk_range_seconds_sum 9.546195003e+09
prometheus_tsdb_compaction_chunk_range_seconds_count 6511

与Summary类型的指标相似之处在于Histogram类型的样本同样会反应当前指标的记录总数(以_count作为后缀)以及其值的总量(以_sum作为后缀)。不同在于Histogram指标直接反应了在不同区间内样本的个数,区间通过标签len进行定义。

同时对于Histogram的指标,我们还可以通过histogram_quantile()函数计算出其值的分位数。不同在于Histogram通过histogram_quantile函数是在服务器端计算的分位数。 而Sumamry的分位数则是直接在客户端计算完成。因此对于分位数的计算而言,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之对于客户端而言Histogram消耗的资源更少。在选择这两种方式时用户应该按照自己的实际场景进行选择。

初识PromQL


Prometheus通过指标名称(metrics name)以及对应的一组标签(labelset)唯一定义一条时间序列。指标名称反映了监控样本的基本标识,而label则在这个基本特征上为采集到的数据提供了多种特征维度。用户可以基于这些特征维度过滤,聚合,统计从而产生新的计算后的一条时间序列。

PromQL是Prometheus内置的数据查询语言,其提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。并且被广泛应用在Prometheus的日常应用当中,包括对数据查询、可视化、告警处理当中。可以这么说,PromQL是Prometheus所有应用场景的基础,理解和掌握PromQL是Prometheus入门的第一课。

查询时间序列

当Prometheus通过Exporter采集到相应的监控指标样本数据后,我们就可以通过PromQL对监控样本数据进行查询。

当我们直接使用监控指标名称查询时,可以查询该指标下的所有时间序列。如:

1
prometheus_http_requests_total

等同于

1
prometheus_http_requests_total{}

该表达式会返回指标名称为prometheus_http_requests_total的所有时间序列

PromQL还支持用户根据时间序列的标签匹配模式来对时间序列进行过滤,目前主要支持两种匹配模式:完全匹配和正则匹配。

PromQL支持使用=!=两种完全匹配模式:

  • 通过使用label=value可以选择那些标签满足表达式定义的时间序列;
  • 反之使用label!=value则可以根据标签匹配排除时间序列;

例如,如果我们只需要查询所有prometheus_http_requests_total时间序列中满足标签handler/metrics的时间序列,则可以使用如下表达式:

1
prometheus_http_requests_total{handler="/metrics"}

反之使用handler!="/metrics"则可以排除这些时间序列:

1
prometheus_http_requests_total{handler!="/metrics"}

除了使用完全匹配的方式对时间序列进行过滤以外,PromQL还可以支持使用正则表达式作为匹配条件,多个表达式之间使用|进行分离:

  • 使用label=~regx表示选择那些标签符合正则表达式定义的时间序列;
  • 反之使用label!~regx进行排除;

例如,如果想查询多个handler的时间序列可以使用如下表达式:

1
prometheus_http_requests_total{handler=~"/metrics|/api/v1/query|/graph"}

范围查询

直接通过类似于PromQL表达式prometheus_http_requests_total查询时间序列时,返回值中只会包含该时间序列中的最新的一个样本值,这样的返回结果我们称之为瞬时向量。而相应的这样的表达式称之为瞬时向量表达式

而如果我们想过去一段时间范围内的样本数据时,我们则需要使用区间向量表达式。区间向量表达式和瞬时向量表达式之间的差异在于在区间向量表达式中我们需要定义时间选择的范围,时间范围通过时间范围选择器[]进行定义。例如,通过以下表达式可以选择最近5分钟内的所有样本数据:

1
prometheus_http_requests_total{}[5m]

该表达式将会返回查询到的时间序列中最近5分钟的所有样本数据:

通过区间向量表达式查询到的结果我们称为区间向量

除了使用m表示分钟以外,PromQL的时间范围选择器支持其它时间单位:

  • s(秒)
  • m(分钟)
  • h(小时)
  • d(天)
  • w(周)
  • y(年)

时间位移操作

在瞬时向量表达式或者区间向量表达式中,都是以当前时间为基准:

1
2
prometheus_http_requests_total{} # 瞬时向量表达式,选择当前最新的数据
prometheus_http_requests_total{}[5m] # 区间向量表达式,选择以当前时间为基准,5分钟内的数据

而如果我们想查询,5分钟前的瞬时样本数据,或昨天一天的区间内的样本数据呢? 这个时候我们就可以使用位移操作,位移操作的关键字为offset

可以使用offset时间位移操作:

1
2
prometheus_http_requests_total{} offset 5m
prometheus_http_requests_total{}[1d] offset 1d

使用聚合操作

一般来说,如果描述样本特征的标签(label)在并非唯一的情况下,通过PromQL查询数据,会返回多条满足这些特征维度的时间序列。而PromQL提供的聚合操作可以用来对这些时间序列进行处理,形成一条新的时间序列:

1
2
3
4
5
# 查询系统所有http请求的总量
sum(prometheus_http_requests_total)

# 按照mode计算主机CPU的平均使用时间
avg(node_cpu_seconds_total) by (mode)

标量和字符串

除了使用瞬时向量表达式和区间向量表达式以外,PromQL还直接支持用户使用标量(Scalar)和字符串(String)。

标量(Scalar):一个浮点型的数字值

标量只有一个数字,没有时序。

例如:

1
10

需要注意的是,当使用表达式count(prometheus_http_requests_total),返回的数据类型,依然是瞬时向量。用户可以通过内置函数scalar()将单个瞬时向量转换为标量。

字符串(String):一个简单的字符串值

直接使用字符串,作为PromQL表达式,则会直接返回字符串。

1
2
3
"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`

合法的PromQL表达式

所有的PromQL表达式都必须至少包含一个指标名称(例如prometheus_http_requests_total),或者一个不会匹配到空字符串的标签过滤器(例如{code="200"})。

因此以下两种方式,均为合法的表达式:

1
2
3
prometheus_http_requests_total # 合法
prometheus_http_requests_total{} # 合法
{method="get"} # 合法

而如下表达式,则不合法:

1
{job=~".*"} # 不合法

同时,除了使用<metric name>{label=value}的形式以外,我们还可以使用内置的__name__标签来指定监控指标名称:

1
2
{__name__=~"prometheus_http_requests_total"} # 合法
{__name__=~"node_disk_read_bytes_total|node_disk_written_bytes_total"} # 合法

PromQL操作符


使用PromQL除了能够方便的按照查询和过滤时间序列以外,PromQL还支持丰富的操作符,用户可以使用这些操作符进一步的对时间序列进行二次加工。这些操作符包括:数学运算符逻辑运算符布尔运算符等等。

数学运算

例如,我们可以通过指标node_memory_MemFree_bytes获取当前主机可用的内存空间大小,其样本单位为Bytes。这是如果客户端要求使用MB作为单位响应数据,那只需要将查询到的时间序列的样本值进行单位换算即可:

1
node_memory_MemFree_bytes / (1024 * 1024)

node_memory_MemFree_bytes表达式会查询出所有满足表达式条件的时间序列,在上一小节中我们称该表达式为瞬时向量表达式,而返回的结果成为瞬时向量。

当瞬时向量与标量之间进行数学运算时,数学运算符会依次作用于瞬时向量中的每一个样本值,从而得到一组新的时间序列。

而如果是瞬时向量与瞬时向量之间进行数学运算时,过程会相对复杂一点。 例如,如果我们想根据node_disk_written_bytes_totalnode_disk_read_bytes_total获取主机磁盘IO的总量,可以使用如下表达式:

1
node_disk_written_bytes_total + node_disk_read_bytes_total

那这个表达式是如何工作的呢?依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。同时新的时间序列将不会包含指标名称。 该表达式返回结果的示例如下所示:

PromQL支持的所有数学运算符如下所示:

  • +(加法)
  • -(减法)
  • *(乘法)
  • /(除法)
  • %(求余)
  • ^(幂运算)

使用布尔运算过滤时间序列

在PromQL通过标签匹配模式,用户可以根据时间序列的特征维度对其进行查询。而布尔运算则支持用户根据时间序列中样本的值,对时间序列进行过滤。

例如,通过数学运算符我们可以很方便的计算出,当前所有主机节点的内存使用率:

1
(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes

而系统管理员在排查问题的时候可能只想知道当前内存使用率超过95%的主机呢?通过使用布尔运算符可以方便的获取到该结果:

1
(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes > 0.95

瞬时向量与标量进行布尔运算时,PromQL依次比较向量中的所有时间序列样本的值,如果比较结果为true则保留,反之丢弃。

瞬时向量与瞬时向量直接进行布尔运算时,同样遵循默认的匹配模式:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行相应的操作,如果没找到匹配元素,则直接丢弃。

目前,Prometheus支持以下布尔运算符如下:

  • ==(相等)
  • !=(不相等)
  • >(大于)
  • <(小于)
  • >=(大于等于)
  • <=(小于等于)

使用bool修饰符改变布尔运算符的行为

布尔运算符的默认行为是对时序数据进行过滤。而在其它的情况下我们可能需要的是真正的布尔结果。例如,只需要知道当前模块的HTTP请求量是否>=500,如果大于等于500则返回1(true)否则返回0(false)。这时可以使用bool修饰符改变布尔运算的默认行为。 例如:

1
prometheus_http_requests_total >= bool 500

使用bool修改符后,布尔运算不会对时间序列进行过滤,而是直接依次瞬时向量中的各个样本数据与标量的比较结果0或者1。从而形成一条新的时间序列。

同时需要注意的是,如果是在两个标量之间使用布尔运算,则必须使用bool修饰符

1
2 == bool 2 # 结果为1

使用集合运算符

使用瞬时向量表达式能够获取到一个包含多个时间序列的集合,我们称为瞬时向量。 通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。目前,Prometheus支持以下集合运算符:

  • and(并且)
  • or(或者)
  • unless(排除)

vector1 and vector2会产生一个由vector1的元素组成的新的向量。该向量包含vector1中完全匹配vector2中的元素组成。

vector1 or vector2会产生一个新的向量,该向量包含vector1中所有的样本数据,以及vector2中没有与vector1匹配到的样本数据。

vector1 unless vector2会产生一个新的向量,新向量中的元素由vector1中没有与vector2匹配的元素组成。

操作符优先级

对于复杂类型的表达式,需要了解运算操作的运行优先级

例如,查询主机的CPU使用率,可以使用表达式:

1
100 * (1 - avg (irate(node_cpu_seconds_total{mode='idle'}[5m])) by(job) )

其中irate是PromQL中的内置函数,用于计算区间向量中时间序列每秒的即时增长率。关于内置函数的部分,会后面详细介绍。

在PromQL操作符中优先级由高到低依次为:

  1. ^
  2. *, /, %
  3. +, -
  4. ==, !=, <=, <, >=, >
  5. and, unless
  6. or

匹配模式详解

向量与向量之间进行运算操作时会基于默认的匹配规则:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。

接下来将介绍在PromQL中有两种典型的匹配模式:一对一(one-to-one),多对一(many-to-one)或一对多(one-to-many)。

一对一匹配

一对一匹配模式会从操作符两边表达式获取的瞬时向量依次比较并找到唯一匹配(标签完全一致)的样本值。默认情况下,使用表达式:

1
vector1 <operator> vector2

在操作符两边表达式标签不一致的情况下,可以使用on(label list)或者ignoring(label list)来修改便签的匹配行为。使用ignoreing可以在匹配时忽略某些便签。而on则用于将匹配行为限定在某些便签之内

1
2
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>

例如当存在样本:

1
2
3
4
5
6
7
8
9
method_code:http_errors:rate5m{method="get", code="500"}  24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21

method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120

使用PromQL表达式:

1
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m

该表达式会返回在过去5分钟内,HTTP请求状态码为500的在所有请求中的比例。如果没有使用ignoring(code),操作符两边表达式返回的瞬时向量中将找不到任何一个标签完全相同的匹配项。

因此结果如下:

1
2
{method="get"}  0.04            # 24 / 600
{method="post"} 0.05 # 6 / 120

多对一和一对多

多对一和一对多两种匹配模式指的是“一”侧的每一个向量元素可以与”多”侧的多个元素匹配的情况。在这种情况下,必须使用group修饰符:group_left或者group_right来确定哪一个向量具有更高的基数(充当“多”的角色)。

1
2
3
4
<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>

多对一和一对多两种模式一定是出现在操作符两侧表达式返回的向量标签不一致的情况。因此需要使用ignoringon修饰符来排除或者限定匹配的标签列表。例如使用表达式:

1
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m

该表达式中,左向量method_code:http_errors:rate5m包含两个标签methodcode。而右向量method:http_requests:rate5m中只包含一个标签method,因此匹配时需要使用ignoring限定匹配的标签为method。 在限定匹配标签后,右向量中的元素可能匹配到多个左向量中的元素 因此该表达式的匹配模式为多对一,需要使用group修饰符group_left指定左向量具有更好的基数。

最终的运算结果如下:

1
2
3
4
{method="get", code="500"}  0.04            # 24 / 600
{method="get", code="404"} 0.05 # 30 / 600
{method="post", code="500"} 0.05 # 6 / 120
{method="post", code="404"} 0.175 # 21 / 120

说明
group修饰符只能在布尔和数学运算符中使用。在逻辑运算and,unless和or操作中默认与右向量中的所有元素进行匹配。

PromQL聚合操作


Prometheus还提供了下列内置的聚合操作符,这些操作符作用于瞬时向量。可以将瞬时表达式返回的样本数据进行聚合,形成一个新的时间序列。

  • sum(求和)
  • min(最小值)
  • max(最大值)
  • avg(平均值)
  • stddev(标准差)
  • stdvar(标准方差)
  • count(计数)
  • count_values(对value进行计数)
  • bottomk(后n条时序)
  • topk(前n条时序)
  • quantile(分位数)

使用聚合操作的语法如下:

1
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]

其中只有count_values,quantile,topk,bottomk支持参数(parameter)。

without用于从计算结果中移除列举的标签,而保留其它标签。by则正好相反,结果向量中只保留列出的标签,其余标签则移除。通过without和by可以按照样本的问题对数据进行聚合。例如:

1
sum(prometheus_http_requests_total) without(instance)

等价于

1
sum(prometheus_http_requests_total) by(code,handler,job)

如果只需要计算整个应用的HTTP请求总量,可以直接使用表达式:

1
sum(prometheus_http_requests_total)

count_values用于统计时间序列中每一个样本值出现的次数。count_values会为每一个唯一的样本值输出一个时间序列,并且每一个时间序列包含一个额外的标签。例如

1
count_values("count", prometheus_http_requests_total)

topkbottomk则用于对样本值进行排序,返回当前样本值前n位,或者后n位的时间序列。例如获取HTTP请求数前5位的时序样本数据,可以使用表达式:

1
topk(5, prometheus_http_requests_total)

quantile用于计算当前样本数据值的分布情况quantile(φ, express)其中0 ≤ φ ≤ 1。例如,当φ为0.5时,即表示找到当前样本数据中的中位数:

1
quantile(0.5, prometheus_http_requests_total)

PromQL内置函数


在前面内容中我们已经看到了类似于irate()这样的函数,可以帮助我们计算监控指标的增长率。除了irate以外,Prometheus还提供了其它大量的内置函数,可以对时序数据进行丰富的处理。某些函数有默认的参数,例如:year(v=vector(time()) instant-vector)。其中参数v是一个瞬时向量,如果不提供该参数,将使用默认值vector(time())。instant-vector表示参数类型。本小节将介绍一些常用的内置函数以及相关的使用场景和用法。

abs()

abs(v instant-vector)返回输入向量的所有样本的绝对值。

absent()

absent(v instant-vector),如果传递给它的向量参数具有样本数据,则返回空向量;如果传递的向量参数没有样本数据,则返回不带度量指标名称且带有标签的时间序列,且样本值为1。

当监控度量指标时,如果获取到的样本数据是空的,使用absent方法对告警是非常有用的。例如:

1
2
3
4
5
6
7
8
9
10
11
# 这里提供的向量有样本数据,返回空向量
absent(prometheus_http_requests_total{handler="/metrics"}) # Empty query result
absent(sum(prometheus_http_requests_total{handler="/metrics"})) # Empty query result

# 由于不存在度量指标nonexistent,所以返回不带度量指标名称且带有标签的时间序列,且样本值为1
absent(nonexistent{job="myjob"}) # {job="myjob"} 1
# 正则匹配的instance不作为返回 labels 中的一部分
absent(nonexistent{job="myjob",instance=~".*"}) # {job="myjob"} 1

# sum函数返回的时间序列不带有标签,且没有样本数据
absent(sum(nonexistent{job="myjob"})) # {} 1

ceil()

ceil(v instant-vector)v中所有元素的样本值向上四舍五入到最接近的整数。例如:

1
2
node_load5{instance="10.211.55.4:9100"}    # 结果为0.01
ceil(node_load5{instance="10.211.55.4:9100"}) # 结果为1

changes()

changes(v range-vector)输入一个区间向量,返回这个区间向量内每个样本数据值变化的次数(瞬时向量)。如下所示node_memory_MemFree_bytes指标在1m内变化次数为3

clamp_max()

clamp_max(v instant-vector, max scalar)函数,输入一个瞬时向量和最大值,样本数据值若大于max,则改为max,否则不变。例如:

1
2
node_load15{instance="10.211.55.4:9100"}    # 结果为0.05
clamp_max(node_load15{instance="10.211.55.4:9100"},0.04) # 结果为0.04

clamp_min()

clamp_min(v instant-vector, min scalar)函数,输入一个瞬时向量和最小值,样本数据值若小于min,则改为min,否则不变。例如:

1
2
node_load15{instance="10.211.55.4:9100"}    # 结果为0.05
clamp_min(node_load15{instance="10.211.55.4:9100"},0.06) # 结果为0.06

day_of_month()

day_of_month(v=vector(time()) instant-vector)函数,返回被给定UTC时间所在月的第几天。返回值范围:1~31

day_of_week()

day_of_week(v=vector(time()) instant-vector)函数,返回被给定UTC时间所在周的第几天。返回值范围:0~6,0表示星期天。

days_in_month()

days_in_month(v=vector(time()) instant-vector)函数,返回当月一共有多少天。返回值范围:28~31

delta()

delta(v range-vector)的参数是一个区间向量,返回一个瞬时向量。它计算一个区间向量v的第一个元素和最后一个元素之间的差值。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如,下面的例子返回过去两小时的磁盘根分区可用空间字节数差:

1
delta(node_filesystem_free_bytes{device="/dev/sda2",fstype="ext4",mountpoint="/"}[1h])

说明
这个计算会做线性的补全,例如数据是10分钟的一个点,你计算25分钟的一个差值,但是25分钟只有2个点,他会根据这两个点的情况,推断出25分钟的差值的情况。这个在表达的时候算是一个小坑点,我们经常计算1分钟的一个情况,往往会算出一个稍微多一些的不怎么合理的值,主要就是他的线性推断导致的。但是看趋势的话是不影响的,如果拿具体值就不怎么合适了。

说明
这个函数一般只用在 Gauge 类型的时间序列上。

deriv()

deriv(v range-vector)的参数是一个区间向量,返回一个瞬时向量。它使用简单的线性回归计算区间向量v中各个时间序列的导数。

说明
这个函数一般只用在 Gauge 类型的时间序列上。

exp()

exp(v instant-vector)函数,输入一个瞬时向量,返回各个样本值的e的指数值,即e的N次方。当N的值足够大时会返回+Inf。特殊情况为:

  • Exp(+Inf) = +Inf
  • Exp(NaN) = NaN

floor()

floor(v instant-vector)函数与ceil()函数相反,将v中所有元素的样本值向下四舍五入到最接近的整数。

1
2
node_load5{instance="10.211.55.4:9100"}    # 结果为0.01
floor(node_load5{instance="10.211.55.4:9100"}) # 结果为0

histogram_quantile()

官网

holt_winters()

holt_winters(v range-vector, sf scalar, tf scalar)函数基于区间向量v,生成时间序列数据平滑值。平滑因子sf越低, 对旧数据的重视程度越高。趋势因子tf越高,对数据的趋势的考虑就越多。其中,0< sf, tf <=1

说明
holt_winters仅适用于Gauge类型的时间序列。

hour()

hour(v=vector(time()) instant-vector)函数返回被给定UTC时间的当前第几个小时,时间范围:0~23

idelta()

idelta(v range-vector)的参数是一个区间向量, 返回一个瞬时向量。它计算最新的2个样本值之间的差值。例如:

1
idelta(node_load5[1m])

这个函数一般只用在Gauge类型的时间序列上。

increase()

increase(v range-vector)函数获取区间向量中的第一个和最后一个样本并返回其增长量, 它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如,以下表达式返回区间向量中每个时间序列过去5分钟内HTTP请求数的增长数:

1
increase(prometheus_http_requests_total{}[5m])

increase的返回值类型只能是计数器类型,主要作用是增加图表和数据的可读性。使用rate函数记录规则的使用率,以便持续跟踪数据样本值的变化。

irate()

irate(v range-vector)函数用于计算区间向量的增长率,但是其反应出的是瞬时增长率。irate函数是通过区间向量中最后两个两本数据来计算区间向量的增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度,通过irate函数绘制的图标能够更好的反应样本数据的瞬时变化状态。

例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内最后两个样本数据的 HTTP 请求数的增长率:

1
irate(prometheus_http_requests_total{}[5m])

irate只能用于绘制快速变化的计数器,在长期趋势分析或者告警中更推荐使用rate函数。因为使用irate函数时,速率的简短变化会重置FOR语句,形成的图形有很多波峰,难以阅读。

警告
当将irate()函数与聚合运算符(例如sum())或随时间聚合的函数(任何以_over_time结尾的函数)一起使用时,必须先执行irate函数,然后再进行聚合操作,否则当采样目标重新启动时irate()无法检测到计数器是否被重置。

label_join()

label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...)

label_join函数可以将时间序列v中多个标签src_label的值,通过separator作为连接符写入到一个新的标签dst_label中。可以有多个src_label标签。

例如,以下表达式返回的时间序列多了一个 foo 标签,标签值为 etcd,etcd-k8s

1
2
3
4
5
up{endpoint="api",instance="192.168.123.248:2379",job="etcd",namespace="monitoring",service="etcd-k8s"}
=> up{endpoint="api",instance="192.168.123.248:2379",job="etcd",namespace="monitoring",service="etcd-k8s"} 1

label_join(up{endpoint="api",instance="192.168.123.248:2379",job="etcd",namespace="monitoring",service="etcd-k8s"}, "foo", ",", "job", "service")
=> up{endpoint="api",foo="etcd,etcd-k8s",instance="192.168.123.248:2379",job="etcd",namespace="monitoring",service="etcd-k8s"} 1

label_replace()

为了能够让客户端的图表更具有可读性,可以通过label_replace函数为时间序列添加额外的标签。label_replace的具体参数如下:

1
label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)

该函数会依次对v中的每一条时间序列进行处理,通过regex匹配src_label的值,并将匹配部分relacement写入到dst_label标签中。如下所示:

1
label_replace(up, "host", "$1", "instance",  "(.*):.*")

函数处理后,时间序列将包含一个host标签,host标签的值为Exporter实例的IP地址:

1
2
3
up{host="localhost",instance="localhost:8080",job="cadvisor"}   1
up{host="localhost",instance="localhost:9090",job="prometheus"} 1
up{host="localhost",instance="localhost:9100",job="node"} 1

ln()

ln(v instant-vector)计算瞬时向量v中所有样本数据的自然对数。特殊情况:

  • ln(+Inf) = +Inf
  • ln(0) = -Inf
  • ln(x < 0) = NaN
  • ln(NaN) = NaN

log2()

log2(v instant-vector)函数计算瞬时向量v中所有样本数据的二进制对数。特殊情况同上。

log10()

log10(v instant-vector)计算瞬时向量v中所有样本数据的十进制对数。特殊情况同上。

minute()

minute(v=vector(time()) instant-vector)函数返回给定UTC时间当前小时的第多少分钟。结果范围:0~59

month()

month(v=vector(time()) instant-vector)函数返回给定UTC时间当前属于第几个月,结果范围:0~12

predict_linear()

predict_linear(v range-vector, t scalar)函数可以预测时间序列v在t秒后的值。它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。该函数的返回结果不带有度量指标,只有标签列表。

例如,基于2小时的样本数据,来预测主机可用磁盘空间的是否在4个小时候被占满,可以使用如下表达式:

1
predict_linear(node_filesystem_free_bytes{job="node"}[2h], 4 * 3600) < 0

说明
这个函数一般只用在 Gauge 类型的时间序列上。

通过下面的例子来观察返回值:

1
predict_linear(prometheus_http_requests_total{code="200",instance="localhost:9090",job="prometheus"}[5m], 3600)

rate()

rate(v range-vector)函数可以直接计算区间向量v在时间窗口内平均增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。该函数的返回结果不带有度量指标,只有标签列表。

例如,以下表达式返回区间向量中每个时间序列过去5分钟内HTTP请求数的每秒增长率:

1
rate(prometheus_http_requests_total[5m])

说明
rate() 函数返回值类型只能用计数器,在长期趋势分析或者告警中推荐使用这个函数。

警告
当将rate()函数与聚合运算符(例如sum())或随时间聚合的函数(任何以_over_time结尾的函数)一起使用时,必须先执行rate函数,然后再进行聚合操作,否则当采样目标重新启动时rate()无法检测到计数器是否被重置。

resets()

resets(v range-vector)的参数是一个区间向量。对于每个时间序列,它都返回一个计数器重置的次数。两个连续样本之间的值的减少被认为是一次计数器重置

说明
这个函数一般只用在计数器类型的时间序列上。

round()

round(v instant-vector, to_nearest=1 scalar)函数与ceilfloor函数类似,返回向量中所有样本值的最接近的整数。to_nearest参数是可选的,默认为1,表示样本返回的是最接近1的整数倍的值。你也可以将该参数指定为任意值(也可以是小数),表示样本返回的是最接近它的整数倍的值。

scalar()

scalar(v instant-vector)函数的参数是一个单元素的瞬时向量,它返回其唯一的时间序列的值作为一个标量。如果度量指标的样本数量大于1或者等于0, 则返回NaN

sort()

sort(v instant-vector)函数对向量按元素的值进行升序排序,返回结果:key:value = 度量指标:样本值[升序排列]

sort_desc()

sort(v instant-vector)函数对向量按元素的值进行降序排序,返回结果:key:value = 度量指标:样本值[降序排列]

sqrt()

sqrt(v instant-vector)函数计算向量v中所有元素的平方根。

time()

time()函数返回从1970-01-01到现在的秒数。

说明
它不是直接返回当前时间,而是时间戳

timestamp()

timestamp(v instant-vector)函数返回向量v中的每个样本的时间戳(从 1970-01-01 到现在的秒数)。

说明
该函数从Prometheus 2.0版本开始引入。

vector()

vector(s scalar)函数将标量s作为没有标签的向量返回,即返回结果为:key:value= {},s

year()

year(v=vector(time()) instant-vector)函数返回被给定UTC时间的当前年份。

<aggregation>_over_time()

下面的函数列表允许传入一个区间向量,它们会聚合每个时间序列的范围,并返回一个瞬时向量:

  • avg_over_time(range-vector):区间向量内每个度量指标的平均值。
  • min_over_time(range-vector):区间向量内每个度量指标的最小值。
  • max_over_time(range-vector):区间向量内每个度量指标的最大值。
  • sum_over_time(range-vector):区间向量内每个度量指标的求和。
  • count_over_time(range-vector):区间向量内每个度量指标的样本数据个数。
  • quantile_over_time(scalar, range-vector):区间向量内每个度量指标的样本数据值分位数,φ-quantile (0 ≤ φ ≤ 1)。
  • stddev_over_time(range-vector):区间向量内每个度量指标的总体标准差。
  • stdvar_over_time(range-vector):区间向量内每个度量指标的总体标准方差。

说明
即使区间向量内的值分布不均匀,它们在聚合时的权重也是相同的

更多聚合函数可参考官方文档https://prometheus.io/docs/prometheus/latest/querying/functions/

在HTTP API中使用PromQL


https://prometheus.io/docs/prometheus/latest/querying/api/

说明
Prometheus当前稳定的HTTP API可以通过/api/v1访问

API响应格式

Prometheus API使用了JSON格式的响应内容。当API调用成功后将会返回2xx的HTTP状态码。

反之,当API调用失败时会返回JSON错误对象和以下HTTP状态码之一:

  • 404 Bad Request:当参数错误或者缺失时
  • 422 Unprocessable Entity:当表达式无法执行时
  • 503 Service Unavailable:当请求超时或者被中断时

如果存在不影响请求执行的错误,则可能会返回一系列警告。所有成功收集的数据都将在data字段中返回

所有的API请求返回的格式均使用以下的JSON格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"status": "success" | "error",
"data": <data>,

// Only set if status is "error". The data field may still hold
// additional data.
"errorType": "<string>",
"error": "<string>",

// Only if there were warnings while executing the request.
// There will still be data in the data field.
"warnings": ["<string>"]
}

通用占位符定义如下:

  • <rfc3339 | unix_timestamp>:输入时间戳可以以RFC3339格式或者Unix时间戳提供,后面可选的小数位可以精确到亚秒级别。输出时间戳始终以Unix时间戳的方式呈现
  • <series_selector>:Prometheus时间序列选择器,如prometheus_http_requests_totalprometheus_http_requests_total{handler=~"/api/v1/query|/graph"},并且需要进行URL编码
  • <duration>:指形如[0-9]+[smhdwy]的Prometheus持续时间字符串。例如5m表示5分钟的持续时间
  • <bool>:布尔值(字符串truefalse

说明
可能重复的查询参数名称以[]结尾

表达式查询

通过HTTP API我们可以分别通过/api/v1/query/api/v1/query_range查询PromQL表达式当前或者一定时间范围内的计算结果。

瞬时数据查询

通过使用QUERY API我们可以查询PromQL在特定时间点下的计算结果。

1
2
GET /api/v1/query
POST /api/v1/query

URL请求参数:

  • query=<string>:PromQL表达式
  • time=<rfc3339 | unix_timestamp>:指定用于计算PromQL的时间戳,可以由RFC3339格式或者Unix时间戳提供,后面可选的小数位可以精确到亚秒级别,可选参数,默认情况下使用当前系统时间
  • timeout=<duration>:超时设置。可选参数,默认使用全局设置的--query.timeout参数

说明
如果time参数缺省,则使用当前服务器时间

说明
可以使用POST方法与Content-Type: application/x-www-form-urlencoded标头直接在请求正文中对这些参数进行URL编码。这在指定可能违反服务端URL字符限制的大型查询时非常有用

当API调用成功后,Prometheus会返回JSON格式的响应内容,格式如上小节所示。并且在data部分返回查询结果。data部分格式如下:

1
2
3
4
{
"resultType": "matrix" | "vector" | "scalar" | "string",
"result": <value>
}

<value>指的是查询结果数据,具体的格式取决于resultType,不同的结果类型,会有不同的结果数据格式,参考下面的“响应数据格式”章节。

例如使用以下命令查询表达式up在时间点2021-09-29T03:05:53.942Z(北京时间2021-09-29 11:05:53)的计算结果

1
curl 'http://localhost:9090/api/v1/query?query=up&time=2021-09-29T03:05:53.942Z'

返回结果如下:

说明
命令返回结果默认会进行常规压缩(压缩成一行字符串),为了方便阅读,可通过jq命令对JSON数据进行处理。有关jq的安装和使用可见此处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "up",
"instance": "10.211.55.4:9100",
"job": "node"
},
"value": [
1632884753.942,
"1"
]
},
{
"metric": {
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
},
"value": [
1632884753.942,
"1"
]
}
]
}
}

区间数据查询

使用QUERY_RANGE API我们可以直接查询PromQL表达式在一段时间内的计算结果。

1
2
GET /api/v1/query_range
POST /api/v1/query_range

URL请求参数:

  • query=<string>:PromQL表达式
  • start=<rfc3339 | unix_timestamp>:起始时间戳
  • end=<rfc3339 | unix_timestamp>:结束时间戳
  • step=<duration | float>:查询时间步长,时间区间内每step秒执行一次
  • timeout=<duration>:超时设置。可选参数,默认使用全局设置的--query.timeout参数

说明
可以使用POST方法与Content-Type: application/x-www-form-urlencoded标头直接在请求正文中对这些参数进行URL编码。这在指定可能违反服务端URL字符限制的大型查询时非常有用

当使用QUERY_RANGE API查询PromQL表达式时,返回结果一定是一个区间向量。查询结果的data部分格式如下:

1
2
3
4
{
"resultType": "matrix",
"result": <value>
}

说明
QUERY_RANGE API中PromQL只能使用瞬时向量选择器类型的表达式。

例如使用以下命令查询表达式up在30秒范围内以15秒为间隔的计算结果

1
curl 'http://localhost:9090/api/v1/query_range?query=up&start=2021-09-29T03:05:30.942Z&end=2021-09-29T03:06:00.942Z&step=15s'

返回结果如下:

说明
命令返回结果默认会进行常规压缩(压缩成一行字符串),为了方便阅读,可通过jq命令对JSON数据进行处理。有关jq的安装和使用可见此处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"__name__": "up",
"instance": "10.211.55.4:9100",
"job": "node"
},
"values": [
[
1632884730.942,
"1"
],
[
1632884745.942,
"1"
],
[
1632884760.942,
"1"
]
]
},
{
"metric": {
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
},
"values": [
[
1632884730.942,
"1"
],
[
1632884745.942,
"1"
],
[
1632884760.942,
"1"
]
]
}
]
}
}

查询元数据

通过标签选择器查找时间序列

使用/api/v1/series可以返回与特定标签集匹配的时间序列列表

1
2
GET /api/v1/series
POST /api/v1/series

URL请求参数:

  • match[]=<series_selector>:表示标签选择器是series_selector。必须至少提供一个match[]参数。
  • start=<rfc3339 | unix_timestamp>:起始时间戳
  • end=<rfc3339 | unix_timestamp>:结束时间戳

说明
可以使用POST方法与Content-Type: application/x-www-form-urlencoded标头直接在请求正文中对这些参数进行URL编码。这在指定可能违反服务端URL字符限制的大型查询时非常有用

返回结果的data部分是由key-value键值对的对象列表组成的。

例如使用以下任意命令查询表达式upprocess_start_time_seconds{job="prometheus"}的计算结果

1
2
3
curl -g 'http://localhost:9090/api/v1/series?match[]=up&match[]=process_start_time_seconds{job="prometheus"}'

curl 'http://localhost:9090/api/v1/series?' --data-urlencode 'match[]=up' --data-urlencode 'match[]=process_start_time_seconds{job="prometheus"}'

返回结果如下:

说明
命令返回结果默认会进行常规压缩(压缩成一行字符串),为了方便阅读,可通过jq命令对JSON数据进行处理。有关jq的安装和使用可见此处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"status": "success",
"data": [
{
"__name__": "process_start_time_seconds",
"instance": "localhost:9090",
"job": "prometheus"
},
{
"__name__": "up",
"instance": "10.211.55.4:9100",
"job": "node"
},
{
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
}
]
}

查询标签名称

使用/api/v1/labels可以返回标签名称列表

1
2
GET /api/v1/labels
POST /api/v1/labels

URL请求参数:

  • start=<rfc3339 | unix_timestamp>:起始时间戳,可选
  • end=<rfc3339 | unix_timestamp>:结束时间戳,可选
  • match[]=<series_selector>:表示标签选择器是series_selector,可选。

返回结果的data部分是字符串标签名称的列表

例如使用以下命令查询表达式up的标签名称列表

1
curl -g 'http://localhost:9090/api/v1/labels?match[]=up'

返回结果如下:

说明
命令返回结果默认会进行常规压缩(压缩成一行字符串),为了方便阅读,可通过jq命令对JSON数据进行处理。有关jq的安装和使用可见此处

1
2
3
4
5
6
7
8
{
"status": "success",
"data": [
"__name__",
"instance",
"job"
]
}

查询标签值

使用/api/v1/label/<label_name>/values可以返回指定标签名称的标签值列表

1
GET /api/v1/label/<label_name>/values

URL请求参数:

  • start=<rfc3339 | unix_timestamp>:起始时间戳,可选
  • end=<rfc3339 | unix_timestamp>:结束时间戳,可选
  • match[]=<series_selector>:表示标签选择器是series_selector,可选。

返回结果的data部分是标签值列表

例如使用以下命令可以查询表达式up标签名为job的所有标签值

1
curl -g http://localhost:9090/api/v1/label/job/values?match[]=up

返回结果如下:

说明
命令返回结果默认会进行常规压缩(压缩成一行字符串),为了方便阅读,可通过jq命令对JSON数据进行处理。有关jq的安装和使用可见此处

1
2
3
4
5
6
7
{
"status": "success",
"data": [
"node",
"prometheus"
]
}

响应数据格式

表达式查询结果可能会在data部分的result字段中返回以下响应值。其中<sample_value>占位符是数值样本值。由于JSON不支持特殊浮点值,例如:NaNInf-Inf,所以样本值将会作为带引号的JSON字符串(而不是原始数值)来进行传输。

区间向量

区间向量返回结果中数据类型resultType为matrix,相应的result响应格式如下:

1
2
3
4
5
6
7
[
{
"metric": { "<label_name>": "<label_value>", ... },
"values": [ [ <unix_time>, "<sample_value>" ], ... ]
},
...
]

其中metrics表示当前时间序列的特征维度,values包含当前事件序列的一组样本。

瞬时向量

瞬时向量返回结果中数据类型resultType为vector,相应的result响应格式如下:

1
2
3
4
5
6
7
[
{
"metric": { "<label_name>": "<label_value>", ... },
"value": [ <unix_time>, "<sample_value>" ]
},
...
]

其中metrics表示当前时间序列的特征维度,values包含当前事件序列的一组样本。

标量

标量返回结果中数据类型resultType为scalar,相应的result响应格式如下:

1
[ <unix_time>, "<scalar_value>" ]

由于标量不存在时间序列一说,因此result表示为当前系统时间一个标量的值。

字符串

标量返回结果中数据类型resultType为string,相应的result响应格式如下:

1
[ <unix_time>, "<string_value>" ]

字符串类型的响应内容格式和标量相同。

说明
更多API说明可阅读官方API文档