mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 21:24:05 -08:00
promql: use natural sort in sort_by_label and sort_by_label_desc (#13411)
These functions are intended for humans, as robots can already sort the results however they please. Humans like things sorted "naturally": * https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/ A similar thing has been done to Grafana, which is also used by humans: * https://github.com/grafana/grafana/pull/78024 * https://github.com/grafana/grafana/pull/78494 Signed-off-by: Ivan Babrou <github@ivan.computer>
This commit is contained in:
parent
7153f61790
commit
a6b35ff304
|
@ -594,6 +594,8 @@ Same as `sort`, but sorts in descending order.
|
||||||
|
|
||||||
Please note that the sort by label functions only affect the results of instant queries, as range query results always have a fixed output ordering.
|
Please note that the sort by label functions only affect the results of instant queries, as range query results always have a fixed output ordering.
|
||||||
|
|
||||||
|
This function uses [natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order).
|
||||||
|
|
||||||
## `sort_by_label_desc()`
|
## `sort_by_label_desc()`
|
||||||
|
|
||||||
**This function has to be enabled via the [feature flag](../feature_flags/) `--enable-feature=promql-experimental-functions`.**
|
**This function has to be enabled via the [feature flag](../feature_flags/) `--enable-feature=promql-experimental-functions`.**
|
||||||
|
@ -602,6 +604,8 @@ Same as `sort_by_label`, but sorts in descending order.
|
||||||
|
|
||||||
Please note that the sort by label functions only affect the results of instant queries, as range query results always have a fixed output ordering.
|
Please note that the sort by label functions only affect the results of instant queries, as range query results always have a fixed output ordering.
|
||||||
|
|
||||||
|
This function uses [natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order).
|
||||||
|
|
||||||
## `sqrt()`
|
## `sqrt()`
|
||||||
|
|
||||||
`sqrt(v instant-vector)` calculates the square root of all elements in `v`.
|
`sqrt(v instant-vector)` calculates the square root of all elements in `v`.
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -19,6 +19,7 @@ require (
|
||||||
github.com/edsrzf/mmap-go v1.1.0
|
github.com/edsrzf/mmap-go v1.1.0
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1
|
github.com/envoyproxy/go-control-plane v0.11.1
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.2
|
github.com/envoyproxy/protoc-gen-validate v1.0.2
|
||||||
|
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/go-kit/log v0.2.1
|
github.com/go-kit/log v0.2.1
|
||||||
github.com/go-logfmt/logfmt v0.6.0
|
github.com/go-logfmt/logfmt v0.6.0
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -166,6 +166,8 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBF
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
|
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM=
|
||||||
|
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/facette/natsort"
|
||||||
"github.com/grafana/regexp"
|
"github.com/grafana/regexp"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
@ -380,15 +381,16 @@ func funcSortByLabel(vals []parser.Value, args parser.Expressions, enh *EvalNode
|
||||||
for _, label := range labels {
|
for _, label := range labels {
|
||||||
lv1 := a.Metric.Get(label)
|
lv1 := a.Metric.Get(label)
|
||||||
lv2 := b.Metric.Get(label)
|
lv2 := b.Metric.Get(label)
|
||||||
// 0 if a == b, -1 if a < b, and +1 if a > b.
|
|
||||||
switch strings.Compare(lv1, lv2) {
|
if lv1 == lv2 {
|
||||||
case -1:
|
|
||||||
return -1
|
|
||||||
case +1:
|
|
||||||
return +1
|
|
||||||
default:
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if natsort.Compare(lv1, lv2) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return +1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
@ -409,19 +411,16 @@ func funcSortByLabelDesc(vals []parser.Value, args parser.Expressions, enh *Eval
|
||||||
for _, label := range labels {
|
for _, label := range labels {
|
||||||
lv1 := a.Metric.Get(label)
|
lv1 := a.Metric.Get(label)
|
||||||
lv2 := b.Metric.Get(label)
|
lv2 := b.Metric.Get(label)
|
||||||
// If label values are the same, continue to the next label
|
|
||||||
if lv1 == lv2 {
|
if lv1 == lv2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// 0 if a == b, -1 if a < b, and +1 if a > b.
|
|
||||||
switch strings.Compare(lv1, lv2) {
|
if natsort.Compare(lv1, lv2) {
|
||||||
case -1:
|
|
||||||
return +1
|
return +1
|
||||||
case +1:
|
|
||||||
return -1
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
35
promql/testdata/functions.test
vendored
35
promql/testdata/functions.test
vendored
|
@ -482,6 +482,19 @@ load 5m
|
||||||
http_requests{job="app-server", instance="0", group="canary"} 0+70x10
|
http_requests{job="app-server", instance="0", group="canary"} 0+70x10
|
||||||
http_requests{job="app-server", instance="1", group="canary"} 0+80x10
|
http_requests{job="app-server", instance="1", group="canary"} 0+80x10
|
||||||
http_requests{job="api-server", instance="2", group="production"} 0+10x10
|
http_requests{job="api-server", instance="2", group="production"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="0"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="1"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="2"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="3"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="10"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="11"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="12"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="20"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="21"} 0+10x10
|
||||||
|
cpu_time_total{job="cpu", cpu="100"} 0+10x10
|
||||||
|
node_uname_info{job="node_exporter", instance="4m600", release="1.2.3"} 0+10x10
|
||||||
|
node_uname_info{job="node_exporter", instance="4m5", release="1.11.3"} 0+10x10
|
||||||
|
node_uname_info{job="node_exporter", instance="4m1000", release="1.111.3"} 0+10x10
|
||||||
|
|
||||||
eval_ordered instant at 50m sort_by_label(http_requests, "instance")
|
eval_ordered instant at 50m sort_by_label(http_requests, "instance")
|
||||||
http_requests{group="production", instance="0", job="api-server"} 100
|
http_requests{group="production", instance="0", job="api-server"} 100
|
||||||
|
@ -579,6 +592,28 @@ eval_ordered instant at 50m sort_by_label_desc(http_requests, "instance", "group
|
||||||
http_requests{group="canary", instance="0", job="app-server"} 700
|
http_requests{group="canary", instance="0", job="app-server"} 700
|
||||||
http_requests{group="canary", instance="0", job="api-server"} 300
|
http_requests{group="canary", instance="0", job="api-server"} 300
|
||||||
|
|
||||||
|
eval_ordered instant at 50m sort_by_label(cpu_time_total, "cpu")
|
||||||
|
cpu_time_total{job="cpu", cpu="0"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="1"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="2"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="3"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="10"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="11"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="12"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="20"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="21"} 100
|
||||||
|
cpu_time_total{job="cpu", cpu="100"} 100
|
||||||
|
|
||||||
|
eval_ordered instant at 50m sort_by_label(node_uname_info, "instance")
|
||||||
|
node_uname_info{job="node_exporter", instance="4m5", release="1.11.3"} 100
|
||||||
|
node_uname_info{job="node_exporter", instance="4m600", release="1.2.3"} 100
|
||||||
|
node_uname_info{job="node_exporter", instance="4m1000", release="1.111.3"} 100
|
||||||
|
|
||||||
|
eval_ordered instant at 50m sort_by_label(node_uname_info, "release")
|
||||||
|
node_uname_info{job="node_exporter", instance="4m600", release="1.2.3"} 100
|
||||||
|
node_uname_info{job="node_exporter", instance="4m5", release="1.11.3"} 100
|
||||||
|
node_uname_info{job="node_exporter", instance="4m1000", release="1.111.3"} 100
|
||||||
|
|
||||||
# Tests for holt_winters
|
# Tests for holt_winters
|
||||||
clear
|
clear
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue