diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34255f9f6..fd82cad96 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,14 @@
* [CHANGE] Notifier: Increment the prometheus_notifications_errors_total metric by the number of affected alerts rather than by one per batch of affected alerts. #15428
* [ENHANCEMENT] OTLP receiver: Convert also metric metadata. #15416
+## 3.0.1 / 2024-11-28
+
+The first bug fix release for Prometheus 3.
+
+* [BUGFIX] Promql: Make subqueries left open. #15431
+* [BUGFIX] Fix memory leak when query log is enabled. #15434
+* [BUGFIX] Support utf8 names on /v1/label/:name/values endpoint. #15399
+
## 3.0.0 / 2024-11-14
This release includes new features such as a brand new UI and UTF-8 support enabled by default. As this marks the first new major version in seven years, several breaking changes are introduced. The breaking changes are mainly around the removal of deprecated feature flags and CLI arguments, and the full list can be found below. For users that want to upgrade we recommend to read through our [migration guide](https://prometheus.io/docs/prometheus/3.0/migration/).
diff --git a/VERSION b/VERSION
index 4a36342fc..cb2b00e4f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.0
+3.0.1
diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod
index 298236a8d..d2b15dbe5 100644
--- a/documentation/examples/remote_storage/go.mod
+++ b/documentation/examples/remote_storage/go.mod
@@ -1,6 +1,6 @@
module github.com/prometheus/prometheus/documentation/examples/remote_storage
-go 1.22.0
+go 1.22.7
require (
github.com/alecthomas/kingpin/v2 v2.4.0
@@ -8,8 +8,8 @@ require (
github.com/golang/snappy v0.0.4
github.com/influxdata/influxdb v1.11.8
github.com/prometheus/client_golang v1.20.5
- github.com/prometheus/common v0.60.1
- github.com/prometheus/prometheus v0.53.1
+ github.com/prometheus/common v0.61.0
+ github.com/prometheus/prometheus v1.99.0
github.com/stretchr/testify v1.10.0
)
@@ -55,15 +55,15 @@ require (
go.opentelemetry.io/otel/trace v1.27.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/crypto v0.27.0 // indirect
- golang.org/x/net v0.29.0 // indirect
- golang.org/x/oauth2 v0.23.0 // indirect
- golang.org/x/sys v0.25.0 // indirect
- golang.org/x/text v0.18.0 // indirect
+ golang.org/x/crypto v0.30.0 // indirect
+ golang.org/x/net v0.32.0 // indirect
+ golang.org/x/oauth2 v0.24.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/grpc v1.65.0 // indirect
- google.golang.org/protobuf v1.34.2 // indirect
+ google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.29.3 // indirect
diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum
index bd11b9d04..860b9a944 100644
--- a/documentation/examples/remote_storage/go.sum
+++ b/documentation/examples/remote_storage/go.sum
@@ -264,8 +264,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
-github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
-github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
+github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
+github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -323,8 +323,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
+golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -344,20 +344,20 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
+golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
-golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
+golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -373,17 +373,17 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
-golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -411,8 +411,8 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
+google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/go.mod b/go.mod
index fed63f945..4bdd3dcf0 100644
--- a/go.mod
+++ b/go.mod
@@ -1,8 +1,8 @@
module github.com/prometheus/prometheus
-go 1.22.0
+go 1.22.7
-toolchain go1.23.0
+toolchain go1.23.4
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
@@ -12,31 +12,31 @@ require (
github.com/Code-Hex/go-generics-cache v1.5.1
github.com/KimMachineGun/automemlimit v0.6.1
github.com/alecthomas/kingpin/v2 v2.4.0
- github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30
+ github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b
github.com/aws/aws-sdk-go v1.55.5
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3
github.com/cespare/xxhash/v2 v2.3.0
github.com/dennwc/varint v1.0.0
- github.com/digitalocean/godo v1.131.0
- github.com/docker/docker v27.3.1+incompatible
+ github.com/digitalocean/godo v1.132.0
+ github.com/docker/docker v27.4.1+incompatible
github.com/edsrzf/mmap-go v1.2.0
github.com/envoyproxy/go-control-plane v0.13.1
github.com/envoyproxy/protoc-gen-validate v1.1.0
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
- github.com/fsnotify/fsnotify v1.7.0
+ github.com/fsnotify/fsnotify v1.8.0
github.com/go-openapi/strfmt v0.23.0
github.com/go-zookeeper/zk v1.0.4
github.com/gogo/protobuf v1.3.2
github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.6.0
- github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da
+ github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad
github.com/google/uuid v1.6.0
github.com/gophercloud/gophercloud v1.14.1
github.com/grafana/regexp v0.0.0-20240607082908-2cb410fa05da
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/hashicorp/consul/api v1.30.0
- github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3
- github.com/hetznercloud/hcloud-go/v2 v2.17.0
+ github.com/hashicorp/nomad/api v0.0.0-20241218080744-e3ac00f30eec
+ github.com/hetznercloud/hcloud-go/v2 v2.17.1
github.com/ionos-cloud/sdk-go/v6 v6.3.0
github.com/json-iterator/go v1.1.12
github.com/klauspost/compress v1.17.11
@@ -54,22 +54,22 @@ require (
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.61.0
github.com/prometheus/common/assets v0.2.0
- github.com/prometheus/exporter-toolkit v0.13.1
+ github.com/prometheus/exporter-toolkit v0.13.2
github.com/prometheus/sigv4 v0.1.0
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c
github.com/stretchr/testify v1.10.0
github.com/vultr/govultr/v2 v2.17.2
- go.opentelemetry.io/collector/pdata v1.20.0
- go.opentelemetry.io/collector/semconv v0.114.0
- go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0
- go.opentelemetry.io/otel v1.32.0
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0
- go.opentelemetry.io/otel/sdk v1.32.0
- go.opentelemetry.io/otel/trace v1.32.0
+ go.opentelemetry.io/collector/pdata v1.22.0
+ go.opentelemetry.io/collector/semconv v0.116.0
+ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0
+ go.opentelemetry.io/otel v1.33.0
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0
+ go.opentelemetry.io/otel/sdk v1.33.0
+ go.opentelemetry.io/otel/trace v1.33.0
go.uber.org/atomic v1.11.0
go.uber.org/automaxprocs v1.6.0
go.uber.org/goleak v1.3.0
@@ -79,10 +79,10 @@ require (
golang.org/x/sys v0.28.0
golang.org/x/text v0.21.0
golang.org/x/tools v0.28.0
- google.golang.org/api v0.209.0
- google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28
- google.golang.org/grpc v1.68.1
- google.golang.org/protobuf v1.35.2
+ google.golang.org/api v0.213.0
+ google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484
+ google.golang.org/grpc v1.69.0
+ google.golang.org/protobuf v1.36.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.31.3
@@ -93,9 +93,9 @@ require (
)
require (
- cloud.google.com/go/auth v0.10.2 // indirect
- cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect
- cloud.google.com/go/compute/metadata v0.5.2 // indirect
+ cloud.google.com/go/auth v0.13.0 // indirect
+ cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
+ cloud.google.com/go/compute/metadata v0.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/DmitriyVTitov/size v1.5.0
@@ -124,17 +124,16 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.22.2 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
- github.com/go-openapi/jsonpointer v0.20.2 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/loads v0.21.5 // indirect
github.com/go-openapi/spec v0.20.14 // indirect
- github.com/go-openapi/swag v0.22.9 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/validate v0.23.0 // indirect
github.com/go-resty/resty/v2 v2.15.3 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/glog v1.2.2 // indirect
- github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-querystring v1.1.0 // indirect
@@ -143,7 +142,7 @@ require (
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/hashicorp/cronexpr v1.1.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -154,7 +153,7 @@ require (
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
- github.com/imdario/mergo v0.3.16 // indirect
+ github.com/imdario/mergo v0.3.6 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
@@ -187,16 +186,16 @@ require (
github.com/x448/float16 v0.8.4 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
- go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/otel/metric v1.32.0 // indirect
- go.opentelemetry.io/proto/otlp v1.3.1 // indirect
- golang.org/x/crypto v0.30.0 // indirect
+ go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+ go.opentelemetry.io/otel/metric v1.33.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.4.0 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.32.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/time v0.8.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
@@ -221,3 +220,6 @@ exclude (
// + https://github.com/go-yaml/yaml/pull/691
// + https://github.com/go-yaml/yaml/pull/876
replace gopkg.in/yaml.v3 => github.com/colega/go-yaml-yaml v0.0.0-20220720105220-255a8d16d094
+
+// Pin until https://github.com/fsnotify/fsnotify/issues/656 is resolved.
+replace github.com/fsnotify/fsnotify v1.8.0 => github.com/fsnotify/fsnotify v1.7.0
diff --git a/go.sum b/go.sum
index 302ecbfcb..74e208ed0 100644
--- a/go.sum
+++ b/go.sum
@@ -1,11 +1,11 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go/auth v0.10.2 h1:oKF7rgBfSHdp/kuhXtqU/tNDr0mZqhYbEh+6SiqzkKo=
-cloud.google.com/go/auth v0.10.2/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
-cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk=
-cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
-cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
-cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
+cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs=
+cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
+cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU=
+cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
+cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
+cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
@@ -44,8 +44,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg=
-github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
+github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
+github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -99,14 +99,14 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/digitalocean/godo v1.131.0 h1:0WHymufAV5avpodT0h5/pucUVfO4v7biquOIqhLeROY=
-github.com/digitalocean/godo v1.131.0/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
+github.com/digitalocean/godo v1.132.0 h1:n0x6+ZkwbyQBtIU1wwBhv26EINqHg0wWQiBXlwYg/HQ=
+github.com/digitalocean/godo v1.132.0/go.mod h1:PU8JB6I1XYkQIdHFop8lLAY9ojp6M0XcU0TWaQSxbrc=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
-github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
-github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v27.4.1+incompatible h1:ZJvcY7gfwHn1JF48PfbyXg7Jyt9ZCWDW+GGXOIxEwp4=
+github.com/docker/docker v27.4.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -156,8 +156,8 @@ github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE
github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo=
github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
-github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
-github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRzT0=
@@ -166,8 +166,8 @@ github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
-github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
-github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/validate v0.23.0 h1:2l7PJLzCis4YUGEoW6eoQw3WhyM65WSIcjX6SQnlfDw=
github.com/go-openapi/validate v0.23.0/go.mod h1:EeiAZ5bmpSIOJV1WLfyYF9qp/B1ZgSaEpHTJHtN5cbE=
github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8=
@@ -187,7 +187,6 @@ github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -195,13 +194,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@@ -215,9 +207,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -226,8 +216,8 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da h1:xRmpO92tb8y+Z85iUOMOicpCfaYcv7o3Cg3wKrIpg8g=
-github.com/google/pprof v0.0.0-20240711041743-f6c9dda6c6da/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -245,8 +235,8 @@ github.com/grafana/regexp v0.0.0-20240607082908-2cb410fa05da h1:BML5sNe+bw2uO8t8
github.com/grafana/regexp v0.0.0-20240607082908-2cb410fa05da/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/hashicorp/consul/api v1.30.0 h1:ArHVMMILb1nQv8vZSGIwwQd2gtc+oSQZ6CalyiyH2XQ=
github.com/hashicorp/consul/api v1.30.0/go.mod h1:B2uGchvaXVW2JhFoS8nqTxMD5PBykr4ebY4JWHTTeLM=
github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=
@@ -293,14 +283,14 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
-github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3 h1:fgVfQ4AC1avVOnu2cfms8VAiD8lUq3vWI8mTocOXN/w=
-github.com/hashicorp/nomad/api v0.0.0-20240717122358-3d93bd3778f3/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
+github.com/hashicorp/nomad/api v0.0.0-20241218080744-e3ac00f30eec h1:+YBzb977VrmffaCX/OBm17dEVJUcWn5dW+eqs3aIJ/A=
+github.com/hashicorp/nomad/api v0.0.0-20241218080744-e3ac00f30eec/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
-github.com/hetznercloud/hcloud-go/v2 v2.17.0 h1:ge0w2piey9SV6XGyU/wQ6HBR24QyMbJ3wLzezplqR68=
-github.com/hetznercloud/hcloud-go/v2 v2.17.0/go.mod h1:zfyZ4Orx+mPpYDzWAxXR7DHGL50nnlZ5Edzgs1o6f/s=
-github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
-github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/hetznercloud/hcloud-go/v2 v2.17.1 h1:DPi019dv0WCiECEmtcuTgc//hBvnxESb6QlJnAb4a04=
+github.com/hetznercloud/hcloud-go/v2 v2.17.1/go.mod h1:6ygmBba+FdawR2lLp/d9uJljY2k0dTYthprrI8usdLw=
+github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
+github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/ionos-cloud/sdk-go/v6 v6.3.0 h1:/lTieTH9Mo/CWm3cTlFLnK10jgxjUGkAqRffGqvPteY=
github.com/ionos-cloud/sdk-go/v6 v6.3.0/go.mod h1:SXrO9OGyWjd2rZhAhEpdYN6VUAODzzqRdqA9BCviQtI=
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
@@ -452,8 +442,8 @@ github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFS
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM=
github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI=
-github.com/prometheus/exporter-toolkit v0.13.1 h1:Evsh0gWQo2bdOHlnz9+0Nm7/OFfIwhE2Ws4A2jIlR04=
-github.com/prometheus/exporter-toolkit v0.13.1/go.mod h1:ujdv2YIOxtdFxxqtloLpbqmxd5J0Le6IITUvIRSWjj0=
+github.com/prometheus/exporter-toolkit v0.13.2 h1:Z02fYtbqTMy2i/f+xZ+UK5jy/bl1Ex3ndzh06T/Q9DQ=
+github.com/prometheus/exporter-toolkit v0.13.2/go.mod h1:tCqnfx21q6qN1KA4U3Bfb8uWzXfijIrJz3/kTIqMV7g=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
@@ -495,7 +485,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
@@ -511,32 +500,34 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
-go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
-go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/collector/pdata v1.20.0 h1:ePcwt4bdtISP0loHaE+C9xYoU2ZkIvWv89Fob16o9SM=
-go.opentelemetry.io/collector/pdata v1.20.0/go.mod h1:Ox1YVLe87cZDB/TL30i4SUz1cA5s6AM6SpFMfY61ICs=
-go.opentelemetry.io/collector/semconv v0.114.0 h1:/eKcCJwZepQUtEuFuxa0thx2XIOvhFpaf214ZG1a11k=
-go.opentelemetry.io/collector/semconv v0.114.0/go.mod h1:zCJ5njhWpejR+A40kiEoeFm1xq1uzyZwMnRNX6/D82A=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 h1:7F3XCD6WYzDkwbi8I8N+oYJWquPVScnRosKGgqjsR8c=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0/go.mod h1:Dk3C0BfIlZDZ5c6eVS7TYiH2vssuyUU3vUsgbrR+5V4=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
-go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
-go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI=
-go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
-go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
-go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
-go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
-go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
-go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
-go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
-go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/collector/pdata v1.22.0 h1:3yhjL46NLdTMoP8rkkcE9B0pzjf2973crn0KKhX5UrI=
+go.opentelemetry.io/collector/pdata v1.22.0/go.mod h1:nLLf6uDg8Kn5g3WNZwGyu8+kf77SwOqQvMTb5AXEbEY=
+go.opentelemetry.io/collector/semconv v0.116.0 h1:63xCZomsKJAWmKGWD3lnORiE3WKW6AO4LjnzcHzGx3Y=
+go.opentelemetry.io/collector/semconv v0.116.0/go.mod h1:N6XE8Q0JKgBN2fAhkUQtqK9LT7rEGR6+Wu/Rtbal1iI=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0 h1:xwH3QJv6zL4u+gkPUu59NeT1Gyw9nScWT8FQpKLUJJI=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.58.0/go.mod h1:uosvgpqTcTXtcPQORTbEkZNDQTCDOgTz1fe6aLSyqrQ=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
+go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
+go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
+go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
+go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
+go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
+go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
+go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
+go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
+go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
+go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
+go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
+go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
@@ -551,8 +542,8 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
-golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
@@ -576,7 +567,6 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -655,37 +645,26 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.209.0 h1:Ja2OXNlyRlWCWu8o+GgI4yUn/wz9h/5ZfFbKz+dQX+w=
-google.golang.org/api v0.209.0/go.mod h1:I53S168Yr/PNDNMi5yPnDc0/LGRZO6o7PoEbl/HY3CM=
+google.golang.org/api v0.213.0 h1:KmF6KaDyFqB417T68tMPbVmmwtIXs2VB60OJKIHB0xQ=
+google.golang.org/api v0.213.0/go.mod h1:V0T5ZhNUUNpYAlL306gFZPFt5F5D/IeyLoktduYYnvQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
-google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
+google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
+google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
-google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
-google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI=
+google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
+google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
+google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/model/histogram/test_utils.go b/model/histogram/test_utils.go
index 9e9a711c2..e6b33863b 100644
--- a/model/histogram/test_utils.go
+++ b/model/histogram/test_utils.go
@@ -19,12 +19,12 @@ func GenerateBigTestHistograms(numHistograms, numBuckets int) []*Histogram {
bucketsPerSide := numBuckets / 2
spanLength := uint32(bucketsPerSide / numSpans)
// Given all bucket deltas are 1, sum bucketsPerSide + 1.
- observationCount := bucketsPerSide * (1 + bucketsPerSide)
+ observationCount := uint64(bucketsPerSide) * (1 + uint64(bucketsPerSide))
var histograms []*Histogram
for i := 0; i < numHistograms; i++ {
h := &Histogram{
- Count: uint64(i + observationCount),
+ Count: uint64(i) + observationCount,
ZeroCount: uint64(i),
ZeroThreshold: 1e-128,
Sum: 18.4 * float64(i+1),
diff --git a/promql/engine.go b/promql/engine.go
index 3f336188e..8e65063bc 100644
--- a/promql/engine.go
+++ b/promql/engine.go
@@ -1353,7 +1353,7 @@ func (ev *evaluator) rangeEvalAgg(ctx context.Context, aggExpr *parser.Aggregate
}
groups := make([]groupedAggregation, groupCount)
- var k int
+ var k int64
var ratio float64
var seriess map[uint64]Series
switch aggExpr.Op {
@@ -1361,9 +1361,9 @@ func (ev *evaluator) rangeEvalAgg(ctx context.Context, aggExpr *parser.Aggregate
if !convertibleToInt64(param) {
ev.errorf("Scalar value %v overflows int64", param)
}
- k = int(param)
- if k > len(inputMatrix) {
- k = len(inputMatrix)
+ k = int64(param)
+ if k > int64(len(inputMatrix)) {
+ k = int64(len(inputMatrix))
}
if k < 1 {
return nil, warnings
@@ -3173,7 +3173,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix
// seriesToResult maps inputMatrix indexes to groups indexes.
// For an instant query, returns a Matrix in descending order for topk or ascending for bottomk, or without any order for limitk / limit_ratio.
// For a range query, aggregates output in the seriess map.
-func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, r float64, inputMatrix Matrix, seriesToResult []int, groups []groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) {
+func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int64, r float64, inputMatrix Matrix, seriesToResult []int, groups []groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) {
op := e.Op
var s Sample
var annos annotations.Annotations
@@ -3244,7 +3244,7 @@ seriesLoop:
case s.H != nil:
// Ignore histogram sample and add info annotation.
annos.Add(annotations.NewHistogramIgnoredInAggregationInfo("topk", e.PosRange))
- case len(group.heap) < k:
+ case int64(len(group.heap)) < k:
heap.Push(&group.heap, &s)
case group.heap[0].F < s.F || (math.IsNaN(group.heap[0].F) && !math.IsNaN(s.F)):
// This new element is bigger than the previous smallest element - overwrite that.
@@ -3260,7 +3260,7 @@ seriesLoop:
case s.H != nil:
// Ignore histogram sample and add info annotation.
annos.Add(annotations.NewHistogramIgnoredInAggregationInfo("bottomk", e.PosRange))
- case len(group.heap) < k:
+ case int64(len(group.heap)) < k:
heap.Push((*vectorByReverseValueHeap)(&group.heap), &s)
case group.heap[0].F > s.F || (math.IsNaN(group.heap[0].F) && !math.IsNaN(s.F)):
// This new element is smaller than the previous biggest element - overwrite that.
@@ -3271,13 +3271,13 @@ seriesLoop:
}
case parser.LIMITK:
- if len(group.heap) < k {
+ if int64(len(group.heap)) < k {
heap.Push(&group.heap, &s)
}
// LIMITK optimization: early break if we've added K elem to _every_ group,
// especially useful for large timeseries where the user is exploring labels via e.g.
// limitk(10, my_metric)
- if !group.groupAggrComplete && len(group.heap) == k {
+ if !group.groupAggrComplete && int64(len(group.heap)) == k {
group.groupAggrComplete = true
groupsRemaining--
if groupsRemaining == 0 {
diff --git a/promql/functions.go b/promql/functions.go
index da1821fd1..5f31a3db1 100644
--- a/promql/functions.go
+++ b/promql/functions.go
@@ -355,7 +355,7 @@ func calcTrendValue(i int, tf, s0, s1, b float64) float64 {
// https://en.wikipedia.org/wiki/Exponential_smoothing .
func funcDoubleExponentialSmoothing(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
samples := vals[0].(Matrix)[0]
-
+ metricName := samples.Metric.Get(labels.MetricName)
// The smoothing factor argument.
sf := vals[1].(Vector)[0].F
@@ -374,6 +374,10 @@ func funcDoubleExponentialSmoothing(vals []parser.Value, args parser.Expressions
// Can't do the smoothing operation with less than two points.
if l < 2 {
+ // Annotate mix of float and histogram.
+ if l == 1 && len(samples.Histograms) > 0 {
+ return enh.Out, annotations.New().Add(annotations.NewHistogramIgnoredInMixedRangeInfo(metricName, args[0].PositionRange()))
+ }
return enh.Out, nil
}
@@ -394,7 +398,9 @@ func funcDoubleExponentialSmoothing(vals []parser.Value, args parser.Expressions
s0, s1 = s1, x+y
}
-
+ if len(samples.Histograms) > 0 {
+ return append(enh.Out, Sample{F: s1}), annotations.New().Add(annotations.NewHistogramIgnoredInMixedRangeInfo(metricName, args[0].PositionRange()))
+ }
return append(enh.Out, Sample{F: s1}), nil
}
@@ -1110,10 +1116,15 @@ func linearRegression(samples []FPoint, interceptTime int64) (slope, intercept f
// === deriv(node parser.ValueTypeMatrix) (Vector, Annotations) ===
func funcDeriv(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
samples := vals[0].(Matrix)[0]
+ metricName := samples.Metric.Get(labels.MetricName)
- // No sense in trying to compute a derivative without at least two points.
+ // No sense in trying to compute a derivative without at least two float points.
// Drop this Vector element.
if len(samples.Floats) < 2 {
+ // Annotate mix of float and histogram.
+ if len(samples.Floats) == 1 && len(samples.Histograms) > 0 {
+ return enh.Out, annotations.New().Add(annotations.NewHistogramIgnoredInMixedRangeInfo(metricName, args[0].PositionRange()))
+ }
return enh.Out, nil
}
@@ -1121,6 +1132,9 @@ func funcDeriv(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
// to avoid floating point accuracy issues, see
// https://github.com/prometheus/prometheus/issues/2674
slope, _ := linearRegression(samples.Floats, samples.Floats[0].T)
+ if len(samples.Histograms) > 0 {
+ return append(enh.Out, Sample{F: slope}), annotations.New().Add(annotations.NewHistogramIgnoredInMixedRangeInfo(metricName, args[0].PositionRange()))
+ }
return append(enh.Out, Sample{F: slope}), nil
}
@@ -1128,13 +1142,22 @@ func funcDeriv(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
func funcPredictLinear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
samples := vals[0].(Matrix)[0]
duration := vals[1].(Vector)[0].F
- // No sense in trying to predict anything without at least two points.
+ metricName := samples.Metric.Get(labels.MetricName)
+
+ // No sense in trying to predict anything without at least two float points.
// Drop this Vector element.
if len(samples.Floats) < 2 {
+ // Annotate mix of float and histogram.
+ if len(samples.Floats) == 1 && len(samples.Histograms) > 0 {
+ return enh.Out, annotations.New().Add(annotations.NewHistogramIgnoredInMixedRangeInfo(metricName, args[0].PositionRange()))
+ }
return enh.Out, nil
}
- slope, intercept := linearRegression(samples.Floats, enh.Ts)
+ slope, intercept := linearRegression(samples.Floats, enh.Ts)
+ if len(samples.Histograms) > 0 {
+ return append(enh.Out, Sample{F: slope*duration + intercept}), annotations.New().Add(annotations.NewHistogramIgnoredInMixedRangeInfo(metricName, args[0].PositionRange()))
+ }
return append(enh.Out, Sample{F: slope*duration + intercept}), nil
}
diff --git a/promql/promqltest/testdata/functions.test b/promql/promqltest/testdata/functions.test
index a00ed8a3e..6d2ade3ab 100644
--- a/promql/promqltest/testdata/functions.test
+++ b/promql/promqltest/testdata/functions.test
@@ -234,11 +234,25 @@ clear
load 5m
http_requests{path="/foo"} 0 50 100 150 200
http_requests{path="/bar"} 200 150 100 50 0
+ http_requests_gauge{path="/foo"} {{schema:0 sum:0 count:0 buckets:[0 0 0] counter_reset_hint:gauge}}+{{schema:0 sum:1 count:2 buckets:[1 1 1] counter_reset_hint:gauge}}x5
+ http_requests_counter{path="/foo"} {{schema:0 sum:0 count:0 buckets:[0 0 0]}}+{{schema:0 sum:1 count:2 buckets:[1 1 1]}}x5
+ http_requests_mix{path="/foo"} 0 50 100 {{schema:0 sum:0 count:0 buckets:[0 0 0] counter_reset_hint:gauge}} {{schema:0 sum:1 count:2 buckets:[1 1 1] counter_reset_hint:gauge}}
eval instant at 20m delta(http_requests[20m])
{path="/foo"} 200
{path="/bar"} -200
+eval instant at 20m delta(http_requests_gauge[20m])
+ {path="/foo"} {{schema:0 sum:4 count:8 buckets:[4 4 4]}}
+
+# delta emits warn annotation for non-gauge histogram types.
+eval_warn instant at 20m delta(http_requests_counter[20m])
+ {path="/foo"} {{schema:0 sum:4 count:8 buckets:[4 4 4]}}
+
+# delta emits warn annotation for mix of histogram and floats.
+eval_warn instant at 20m delta(http_requests_mix[20m])
+ #empty
+
clear
# Tests for idelta().
@@ -258,7 +272,8 @@ load 5m
http_requests_total{job="app-server", instance="1", group="canary"} 0+80x10
testcounter_reset_middle_mix 0+10x4 0+10x5 {{schema:0 sum:1 count:1}} {{schema:1 sum:2 count:2}}
http_requests_mix{job="app-server", instance="1", group="canary"} 0+80x10 {{schema:0 sum:1 count:1}}
- http_requests_histogram{job="app-server", instance="1", group="canary"} {{schema:0 sum:1 count:2}}x10
+ http_requests_histogram{job="app-server", instance="1", group="canary"} {{schema:0 sum:1 count:2}}x10
+ http_requests_inf{job="app-server", instance="1", group="canary"} -Inf 0+80x10 Inf
# deriv should return the same as rate in simple cases.
eval instant at 50m rate(http_requests_total{group="canary", instance="1", job="app-server"}[50m])
@@ -271,15 +286,20 @@ eval instant at 50m deriv(http_requests_total{group="canary", instance="1", job=
eval instant at 50m deriv(testcounter_reset_middle_total[100m])
{} 0.010606060606060607
-# deriv should ignore histograms.
-eval instant at 110m deriv(http_requests_mix{group="canary", instance="1", job="app-server"}[110m])
+# deriv should ignore histograms in a mixed range of floats and histograms, flagged by an info annotation.
+eval_info instant at 110m deriv(http_requests_mix{group="canary", instance="1", job="app-server"}[110m])
{group="canary", instance="1", job="app-server"} 0.26666666666666666
-eval instant at 100m deriv(testcounter_reset_middle_mix[110m])
+eval_info instant at 100m deriv(testcounter_reset_middle_mix[110m])
{} 0.010606060606060607
+# deriv should silently ignore ranges consisting only of histograms.
eval instant at 50m deriv(http_requests_histogram[60m])
- #empty
+ #empty
+
+# deriv should return NaN in case of +Inf or -Inf found.
+eval instant at 100m deriv(http_requests_inf[100m])
+ {job="app-server", instance="1", group="canary"} NaN
# predict_linear should return correct result.
# X/s = [ 0, 300, 600, 900,1200,1500,1800,2100,2400,2700,3000]
@@ -316,6 +336,21 @@ eval instant at 10m predict_linear(testcounter_reset_middle_total[55m] @ 3000, 3
eval instant at 70m predict_linear(testcounter_reset_middle_total[55m] @ 3000, 3600)
{} 89.54545454545455
+# predict_linear should ignore histograms in a mixed range of floats and histograms, flagged by an info annotation.
+eval_info instant at 60m predict_linear(testcounter_reset_middle_mix[60m], 3000)
+ {} 70
+
+eval_info instant at 60m predict_linear(testcounter_reset_middle_mix[60m], 50m)
+ {} 70
+
+# predict_linear should silently ignore ranges consisting only of histograms.
+eval instant at 60m predict_linear(http_requests_histogram[60m], 50m)
+ #empty
+
+# predict_linear should return NaN in case of +Inf or -Inf found.
+eval instant at 100m predict_linear(http_requests_inf[100m], 6000)
+ {job="app-server", instance="1", group="canary"} NaN
+
# With http_requests_total, there is a sample value exactly at the end of
# the range, and it has exactly the predicted value, so predict_linear
# can be emulated with deriv.
@@ -719,6 +754,11 @@ load 10s
http_requests{job="api-server", instance="1", group="production"} 0+20x1000 200+30x1000
http_requests{job="api-server", instance="0", group="canary"} 0+30x1000 300+80x1000
http_requests{job="api-server", instance="1", group="canary"} 0+40x2000
+ http_requests_mix{job="api-server", instance="0", group="production"} 0+10x1000 100+30x1000 {{schema:0 count:1 sum:2}}x1000
+ http_requests_mix{job="api-server", instance="1", group="production"} 0+20x1000 200+30x1000 {{schema:0 count:1 sum:2}}x1000
+ http_requests_mix{job="api-server", instance="0", group="canary"} 0+30x1000 300+80x1000 {{schema:0 count:1 sum:2}}x1000
+ http_requests_mix{job="api-server", instance="1", group="canary"} 0+40x2000 {{schema:0 count:1 sum:2}}x1000
+ http_requests_histogram{job="api-server", instance="1", group="canary"} {{schema:0 count:1 sum:2}}x1000
eval instant at 8000s double_exponential_smoothing(http_requests[1m], 0.01, 0.1)
{job="api-server", instance="0", group="production"} 8000
@@ -726,6 +766,17 @@ eval instant at 8000s double_exponential_smoothing(http_requests[1m], 0.01, 0.1)
{job="api-server", instance="0", group="canary"} 24000
{job="api-server", instance="1", group="canary"} 32000
+# double_exponential_smoothing should ignore histograms in a mixed range of floats and histograms, flagged by an info annotation.
+eval_info instant at 20010s double_exponential_smoothing(http_requests_mix[1m], 0.01, 0.1)
+ {job="api-server", instance="0", group="production"} 30100
+ {job="api-server", instance="1", group="production"} 30200
+ {job="api-server", instance="0", group="canary"} 80300
+ {job="api-server", instance="1", group="canary"} 80000
+
+# double_exponential_smoothing should silently ignore ranges consisting only of histograms.
+eval instant at 10000s double_exponential_smoothing(http_requests_histogram[1m], 0.01, 0.1)
+ #empty
+
# negative trends
clear
load 10s
diff --git a/rules/group.go b/rules/group.go
index 8ad8958f8..0965dc276 100644
--- a/rules/group.go
+++ b/rules/group.go
@@ -23,6 +23,9 @@ import (
"sync"
"time"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
"go.uber.org/atomic"
"github.com/prometheus/prometheus/promql/parser"
@@ -30,9 +33,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/model"
"github.com/prometheus/common/promslog"
- "go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/codes"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/timestamp"
@@ -523,154 +523,152 @@ func (g *Group) CopyState(from *Group) {
// Rules can be evaluated concurrently if the `concurrent-rule-eval` feature flag is enabled.
func (g *Group) Eval(ctx context.Context, ts time.Time) {
var (
- samplesTotal atomic.Float64
- wg sync.WaitGroup
-
+ samplesTotal atomic.Float64
ruleQueryOffset = g.QueryOffset()
)
-
- for i, rule := range g.rules {
- select {
- case <-g.done:
- // There's a chance that the group is asked to return early. In that case, we should
- // wait for any in-flight rules to finish evaluating before returning so that we can preserve the same semantics.
- // At the time of writing, the main reason for this was to make sure we don't clear seriesInPreviousEval before we're done using it.
- wg.Wait()
- return
- default:
+ eval := func(i int, rule Rule, cleanup func()) {
+ if cleanup != nil {
+ defer cleanup()
}
- eval := func(i int, rule Rule, cleanup func()) {
- if cleanup != nil {
- defer cleanup()
- }
+ logger := g.logger.With("name", rule.Name(), "index", i)
+ ctx, sp := otel.Tracer("").Start(ctx, "rule")
+ sp.SetAttributes(attribute.String("name", rule.Name()))
+ defer func(t time.Time) {
+ sp.End()
- logger := g.logger.With("name", rule.Name(), "index", i)
- ctx, sp := otel.Tracer("").Start(ctx, "rule")
- sp.SetAttributes(attribute.String("name", rule.Name()))
- defer func(t time.Time) {
- sp.End()
+ since := time.Since(t)
+ g.metrics.EvalDuration.Observe(since.Seconds())
+ rule.SetEvaluationDuration(since)
+ rule.SetEvaluationTimestamp(t)
+ }(time.Now())
- since := time.Since(t)
- g.metrics.EvalDuration.Observe(since.Seconds())
- rule.SetEvaluationDuration(since)
- rule.SetEvaluationTimestamp(t)
- }(time.Now())
+ if sp.SpanContext().IsSampled() && sp.SpanContext().HasTraceID() {
+ logger = logger.With("trace_id", sp.SpanContext().TraceID())
+ }
+
+ g.metrics.EvalTotal.WithLabelValues(GroupKey(g.File(), g.Name())).Inc()
- if sp.SpanContext().IsSampled() && sp.SpanContext().HasTraceID() {
- logger = logger.With("trace_id", sp.SpanContext().TraceID())
+ vector, err := rule.Eval(ctx, ruleQueryOffset, ts, g.opts.QueryFunc, g.opts.ExternalURL, g.Limit())
+ if err != nil {
+ rule.SetHealth(HealthBad)
+ rule.SetLastError(err)
+ sp.SetStatus(codes.Error, err.Error())
+ g.metrics.EvalFailures.WithLabelValues(GroupKey(g.File(), g.Name())).Inc()
+
+ // Canceled queries are intentional termination of queries. This normally
+ // happens on shutdown and thus we skip logging of any errors here.
+ var eqc promql.ErrQueryCanceled
+ if !errors.As(err, &eqc) {
+ logger.Warn("Evaluating rule failed", "rule", rule, "err", err)
}
+ return
+ }
+ rule.SetHealth(HealthGood)
+ rule.SetLastError(nil)
+ samplesTotal.Add(float64(len(vector)))
- g.metrics.EvalTotal.WithLabelValues(GroupKey(g.File(), g.Name())).Inc()
+ if ar, ok := rule.(*AlertingRule); ok {
+ ar.sendAlerts(ctx, ts, g.opts.ResendDelay, g.interval, g.opts.NotifyFunc)
+ }
+ var (
+ numOutOfOrder = 0
+ numTooOld = 0
+ numDuplicates = 0
+ )
- vector, err := rule.Eval(ctx, ruleQueryOffset, ts, g.opts.QueryFunc, g.opts.ExternalURL, g.Limit())
- if err != nil {
+ app := g.opts.Appendable.Appender(ctx)
+ seriesReturned := make(map[string]labels.Labels, len(g.seriesInPreviousEval[i]))
+ defer func() {
+ if err := app.Commit(); err != nil {
rule.SetHealth(HealthBad)
rule.SetLastError(err)
sp.SetStatus(codes.Error, err.Error())
g.metrics.EvalFailures.WithLabelValues(GroupKey(g.File(), g.Name())).Inc()
- // Canceled queries are intentional termination of queries. This normally
- // happens on shutdown and thus we skip logging of any errors here.
- var eqc promql.ErrQueryCanceled
- if !errors.As(err, &eqc) {
- logger.Warn("Evaluating rule failed", "rule", rule, "err", err)
- }
+ logger.Warn("Rule sample appending failed", "err", err)
return
}
- rule.SetHealth(HealthGood)
- rule.SetLastError(nil)
- samplesTotal.Add(float64(len(vector)))
-
- if ar, ok := rule.(*AlertingRule); ok {
- ar.sendAlerts(ctx, ts, g.opts.ResendDelay, g.interval, g.opts.NotifyFunc)
+ g.seriesInPreviousEval[i] = seriesReturned
+ }()
+
+ for _, s := range vector {
+ if s.H != nil {
+ _, err = app.AppendHistogram(0, s.Metric, s.T, nil, s.H)
+ } else {
+ app.SetOptions(g.appOpts)
+ _, err = app.Append(0, s.Metric, s.T, s.F)
}
- var (
- numOutOfOrder = 0
- numTooOld = 0
- numDuplicates = 0
- )
- app := g.opts.Appendable.Appender(ctx)
- seriesReturned := make(map[string]labels.Labels, len(g.seriesInPreviousEval[i]))
- defer func() {
- if err := app.Commit(); err != nil {
- rule.SetHealth(HealthBad)
- rule.SetLastError(err)
- sp.SetStatus(codes.Error, err.Error())
- g.metrics.EvalFailures.WithLabelValues(GroupKey(g.File(), g.Name())).Inc()
-
- logger.Warn("Rule sample appending failed", "err", err)
- return
- }
- g.seriesInPreviousEval[i] = seriesReturned
- }()
-
- for _, s := range vector {
- if s.H != nil {
- _, err = app.AppendHistogram(0, s.Metric, s.T, nil, s.H)
- } else {
- app.SetOptions(g.appOpts)
- _, err = app.Append(0, s.Metric, s.T, s.F)
+ if err != nil {
+ rule.SetHealth(HealthBad)
+ rule.SetLastError(err)
+ sp.SetStatus(codes.Error, err.Error())
+ unwrappedErr := errors.Unwrap(err)
+ if unwrappedErr == nil {
+ unwrappedErr = err
}
-
- if err != nil {
- rule.SetHealth(HealthBad)
- rule.SetLastError(err)
- sp.SetStatus(codes.Error, err.Error())
- unwrappedErr := errors.Unwrap(err)
- if unwrappedErr == nil {
- unwrappedErr = err
- }
- switch {
- case errors.Is(unwrappedErr, storage.ErrOutOfOrderSample):
- numOutOfOrder++
- logger.Warn("Rule evaluation result discarded", "err", err, "sample", s)
- case errors.Is(unwrappedErr, storage.ErrTooOldSample):
- numTooOld++
- logger.Warn("Rule evaluation result discarded", "err", err, "sample", s)
- case errors.Is(unwrappedErr, storage.ErrDuplicateSampleForTimestamp):
- numDuplicates++
- logger.Warn("Rule evaluation result discarded", "err", err, "sample", s)
- default:
- logger.Warn("Rule evaluation result discarded", "err", err, "sample", s)
- }
- } else {
- buf := [1024]byte{}
- seriesReturned[string(s.Metric.Bytes(buf[:]))] = s.Metric
+ switch {
+ case errors.Is(unwrappedErr, storage.ErrOutOfOrderSample):
+ numOutOfOrder++
+ logger.Debug("Rule evaluation result discarded", "err", err, "sample", s)
+ case errors.Is(unwrappedErr, storage.ErrTooOldSample):
+ numTooOld++
+ logger.Debug("Rule evaluation result discarded", "err", err, "sample", s)
+ case errors.Is(unwrappedErr, storage.ErrDuplicateSampleForTimestamp):
+ numDuplicates++
+ logger.Debug("Rule evaluation result discarded", "err", err, "sample", s)
+ default:
+ logger.Warn("Rule evaluation result discarded", "err", err, "sample", s)
}
+ } else {
+ buf := [1024]byte{}
+ seriesReturned[string(s.Metric.Bytes(buf[:]))] = s.Metric
}
- if numOutOfOrder > 0 {
- logger.Warn("Error on ingesting out-of-order result from rule evaluation", "num_dropped", numOutOfOrder)
- }
- if numTooOld > 0 {
- logger.Warn("Error on ingesting too old result from rule evaluation", "num_dropped", numTooOld)
- }
- if numDuplicates > 0 {
- logger.Warn("Error on ingesting results from rule evaluation with different value but same timestamp", "num_dropped", numDuplicates)
- }
+ }
+ if numOutOfOrder > 0 {
+ logger.Warn("Error on ingesting out-of-order result from rule evaluation", "num_dropped", numOutOfOrder)
+ }
+ if numTooOld > 0 {
+ logger.Warn("Error on ingesting too old result from rule evaluation", "num_dropped", numTooOld)
+ }
+ if numDuplicates > 0 {
+ logger.Warn("Error on ingesting results from rule evaluation with different value but same timestamp", "num_dropped", numDuplicates)
+ }
- for metric, lset := range g.seriesInPreviousEval[i] {
- if _, ok := seriesReturned[metric]; !ok {
- // Series no longer exposed, mark it stale.
- _, err = app.Append(0, lset, timestamp.FromTime(ts.Add(-ruleQueryOffset)), math.Float64frombits(value.StaleNaN))
- unwrappedErr := errors.Unwrap(err)
- if unwrappedErr == nil {
- unwrappedErr = err
- }
- switch {
- case unwrappedErr == nil:
- case errors.Is(unwrappedErr, storage.ErrOutOfOrderSample),
- errors.Is(unwrappedErr, storage.ErrTooOldSample),
- errors.Is(unwrappedErr, storage.ErrDuplicateSampleForTimestamp):
- // Do not count these in logging, as this is expected if series
- // is exposed from a different rule.
- default:
- logger.Warn("Adding stale sample failed", "sample", lset.String(), "err", err)
- }
+ for metric, lset := range g.seriesInPreviousEval[i] {
+ if _, ok := seriesReturned[metric]; !ok {
+ // Series no longer exposed, mark it stale.
+ _, err = app.Append(0, lset, timestamp.FromTime(ts.Add(-ruleQueryOffset)), math.Float64frombits(value.StaleNaN))
+ unwrappedErr := errors.Unwrap(err)
+ if unwrappedErr == nil {
+ unwrappedErr = err
+ }
+ switch {
+ case unwrappedErr == nil:
+ case errors.Is(unwrappedErr, storage.ErrOutOfOrderSample),
+ errors.Is(unwrappedErr, storage.ErrTooOldSample),
+ errors.Is(unwrappedErr, storage.ErrDuplicateSampleForTimestamp):
+ // Do not count these in logging, as this is expected if series
+ // is exposed from a different rule.
+ default:
+ logger.Warn("Adding stale sample failed", "sample", lset.String(), "err", err)
}
}
}
+ }
+
+ var wg sync.WaitGroup
+ for i, rule := range g.rules {
+ select {
+ case <-g.done:
+ // There's a chance that the group is asked to return early. In that case, we should
+ // wait for any in-flight rules to finish evaluating before returning so that we can preserve the same semantics.
+ // At the time of writing, the main reason for this was to make sure we don't clear seriesInPreviousEval before we're done using it.
+ wg.Wait()
+ return
+ default:
+ }
if ctrl := g.concurrencyController; ctrl.Allow(ctx, g, rule) {
wg.Add(1)
@@ -683,7 +681,6 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) {
eval(i, rule, nil)
}
}
-
wg.Wait()
g.metrics.GroupSamples.WithLabelValues(GroupKey(g.File(), g.Name())).Set(samplesTotal.Load())
diff --git a/scrape/manager_test.go b/scrape/manager_test.go
index 0f1b9fe69..b9c6f4c40 100644
--- a/scrape/manager_test.go
+++ b/scrape/manager_test.go
@@ -894,7 +894,7 @@ func findSamplesForMetric(floats []floatSample, metricName string) (ret []floatS
// generateTestHistogram generates the same thing as tsdbutil.GenerateTestHistogram,
// but in the form of dto.Histogram.
func generateTestHistogram(i int) *dto.Histogram {
- helper := tsdbutil.GenerateTestHistogram(i)
+ helper := tsdbutil.GenerateTestHistogram(int64(i))
h := &dto.Histogram{}
h.SampleCount = proto.Uint64(helper.Count)
h.SampleSum = proto.Float64(helper.Sum)
diff --git a/storage/merge_test.go b/storage/merge_test.go
index cf151993f..eaf061064 100644
--- a/storage/merge_test.go
+++ b/storage/merge_test.go
@@ -385,13 +385,13 @@ func TestMergeChunkQuerierWithNoVerticalChunkSeriesMerger(t *testing.T) {
}
func histogramSample(ts int64, hint histogram.CounterResetHint) hSample {
- h := tsdbutil.GenerateTestHistogram(int(ts + 1))
+ h := tsdbutil.GenerateTestHistogram(ts + 1)
h.CounterResetHint = hint
return hSample{t: ts, h: h}
}
func floatHistogramSample(ts int64, hint histogram.CounterResetHint) fhSample {
- fh := tsdbutil.GenerateTestFloatHistogram(int(ts + 1))
+ fh := tsdbutil.GenerateTestFloatHistogram(ts + 1)
fh.CounterResetHint = hint
return fhSample{t: ts, fh: fh}
}
diff --git a/storage/remote/queue_manager_test.go b/storage/remote/queue_manager_test.go
index 8369da3f1..202c71c34 100644
--- a/storage/remote/queue_manager_test.go
+++ b/storage/remote/queue_manager_test.go
@@ -2077,7 +2077,7 @@ func createTimeseriesWithOldSamples(numSamples, numSeries int, extraLabels ...la
for j := 0; j < numSamples/2; j++ {
sample := record.RefSample{
Ref: chunks.HeadSeriesRef(i),
- T: int64(int(time.Now().UnixMilli()) + j),
+ T: time.Now().UnixMilli() + int64(j),
V: float64(i),
}
samples = append(samples, sample)
diff --git a/tsdb/db_test.go b/tsdb/db_test.go
index 3aa9dc873..0fa7b8083 100644
--- a/tsdb/db_test.go
+++ b/tsdb/db_test.go
@@ -4114,7 +4114,7 @@ func TestOOOWALWrite(t *testing.T) {
},
"integer histogram": {
appendSample: func(app storage.Appender, l labels.Labels, mins int64) (storage.SeriesRef, error) {
- seriesRef, err := app.AppendHistogram(0, l, minutes(mins), tsdbutil.GenerateTestHistogram(int(mins)), nil)
+ seriesRef, err := app.AppendHistogram(0, l, minutes(mins), tsdbutil.GenerateTestHistogram(mins), nil)
require.NoError(t, err)
return seriesRef, nil
},
@@ -4205,7 +4205,7 @@ func TestOOOWALWrite(t *testing.T) {
},
"float histogram": {
appendSample: func(app storage.Appender, l labels.Labels, mins int64) (storage.SeriesRef, error) {
- seriesRef, err := app.AppendHistogram(0, l, minutes(mins), nil, tsdbutil.GenerateTestFloatHistogram(int(mins)))
+ seriesRef, err := app.AppendHistogram(0, l, minutes(mins), nil, tsdbutil.GenerateTestFloatHistogram(mins))
require.NoError(t, err)
return seriesRef, nil
},
@@ -4749,12 +4749,12 @@ func TestMultipleEncodingsCommitOrder(t *testing.T) {
return sample{t: ts, f: float64(ts)}
}
if valType == chunkenc.ValHistogram {
- h := tsdbutil.GenerateTestHistogram(int(ts))
+ h := tsdbutil.GenerateTestHistogram(ts)
_, err := app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, h, nil)
require.NoError(t, err)
return sample{t: ts, h: h}
}
- fh := tsdbutil.GenerateTestFloatHistogram(int(ts))
+ fh := tsdbutil.GenerateTestFloatHistogram(ts)
_, err := app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, nil, fh)
require.NoError(t, err)
return sample{t: ts, fh: fh}
@@ -5440,37 +5440,37 @@ func TestQuerierOOOQuery(t *testing.T) {
},
"integer histogram": {
appendFunc: func(app storage.Appender, ts int64, counterReset bool) (storage.SeriesRef, error) {
- h := tsdbutil.GenerateTestHistogram(int(ts))
+ h := tsdbutil.GenerateTestHistogram(ts)
if counterReset {
h.CounterResetHint = histogram.CounterReset
}
return app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, h, nil)
},
sampleFunc: func(ts int64) chunks.Sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(ts))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(ts)}
},
},
"float histogram": {
appendFunc: func(app storage.Appender, ts int64, counterReset bool) (storage.SeriesRef, error) {
- fh := tsdbutil.GenerateTestFloatHistogram(int(ts))
+ fh := tsdbutil.GenerateTestFloatHistogram(ts)
if counterReset {
fh.CounterResetHint = histogram.CounterReset
}
return app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, nil, fh)
},
sampleFunc: func(ts int64) chunks.Sample {
- return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(int(ts))}
+ return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(ts)}
},
},
"integer histogram counter resets": {
// Adding counter reset to all histograms means each histogram will have its own chunk.
appendFunc: func(app storage.Appender, ts int64, counterReset bool) (storage.SeriesRef, error) {
- h := tsdbutil.GenerateTestHistogram(int(ts))
+ h := tsdbutil.GenerateTestHistogram(ts)
h.CounterResetHint = histogram.CounterReset // For this scenario, ignore the counterReset argument.
return app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, h, nil)
},
sampleFunc: func(ts int64) chunks.Sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(ts))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(ts)}
},
},
}
@@ -5756,37 +5756,37 @@ func TestChunkQuerierOOOQuery(t *testing.T) {
},
"integer histogram": {
appendFunc: func(app storage.Appender, ts int64, counterReset bool) (storage.SeriesRef, error) {
- h := tsdbutil.GenerateTestHistogram(int(ts))
+ h := tsdbutil.GenerateTestHistogram(ts)
if counterReset {
h.CounterResetHint = histogram.CounterReset
}
return app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, h, nil)
},
sampleFunc: func(ts int64) chunks.Sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(ts))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(ts)}
},
},
"float histogram": {
appendFunc: func(app storage.Appender, ts int64, counterReset bool) (storage.SeriesRef, error) {
- fh := tsdbutil.GenerateTestFloatHistogram(int(ts))
+ fh := tsdbutil.GenerateTestFloatHistogram(ts)
if counterReset {
fh.CounterResetHint = histogram.CounterReset
}
return app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, nil, fh)
},
sampleFunc: func(ts int64) chunks.Sample {
- return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(int(ts))}
+ return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(ts)}
},
},
"integer histogram counter resets": {
// Adding counter reset to all histograms means each histogram will have its own chunk.
appendFunc: func(app storage.Appender, ts int64, counterReset bool) (storage.SeriesRef, error) {
- h := tsdbutil.GenerateTestHistogram(int(ts))
+ h := tsdbutil.GenerateTestHistogram(ts)
h.CounterResetHint = histogram.CounterReset // For this scenario, ignore the counterReset argument.
return app.AppendHistogram(0, labels.FromStrings("foo", "bar1"), ts, h, nil)
},
sampleFunc: func(ts int64) chunks.Sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(ts))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(ts)}
},
},
"integer histogram with recode": {
@@ -6921,7 +6921,7 @@ func TestOOOHistogramCompactionWithCounterResets(t *testing.T) {
app := db.Appender(context.Background())
tsMs := ts * time.Minute.Milliseconds()
if floatHistogram {
- h := tsdbutil.GenerateTestFloatHistogram(val)
+ h := tsdbutil.GenerateTestFloatHistogram(int64(val))
h.CounterResetHint = hint
_, err = app.AppendHistogram(0, l, tsMs, nil, h)
require.NoError(t, err)
@@ -6929,7 +6929,7 @@ func TestOOOHistogramCompactionWithCounterResets(t *testing.T) {
return sample{t: tsMs, fh: h.Copy()}
}
- h := tsdbutil.GenerateTestHistogram(val)
+ h := tsdbutil.GenerateTestHistogram(int64(val))
h.CounterResetHint = hint
_, err = app.AppendHistogram(0, l, tsMs, h, nil)
require.NoError(t, err)
@@ -7280,14 +7280,14 @@ func TestInterleavedInOrderAndOOOHistogramCompactionWithCounterResets(t *testing
app := db.Appender(context.Background())
tsMs := ts
if floatHistogram {
- h := tsdbutil.GenerateTestFloatHistogram(val)
+ h := tsdbutil.GenerateTestFloatHistogram(int64(val))
_, err = app.AppendHistogram(0, l, tsMs, nil, h)
require.NoError(t, err)
require.NoError(t, app.Commit())
return sample{t: tsMs, fh: h.Copy()}
}
- h := tsdbutil.GenerateTestHistogram(val)
+ h := tsdbutil.GenerateTestHistogram(int64(val))
_, err = app.AppendHistogram(0, l, tsMs, h, nil)
require.NoError(t, err)
require.NoError(t, app.Commit())
diff --git a/tsdb/head_test.go b/tsdb/head_test.go
index dc229a6b5..c1ff2aac7 100644
--- a/tsdb/head_test.go
+++ b/tsdb/head_test.go
@@ -4794,7 +4794,7 @@ func TestOOOHistogramCounterResetHeaders(t *testing.T) {
// OOO histogram
for i := 1; i <= 5; i++ {
- appendHistogram(100+int64(i), tsdbutil.GenerateTestHistogram(1000+i))
+ appendHistogram(100+int64(i), tsdbutil.GenerateTestHistogram(1000+int64(i)))
}
// Nothing mmapped yet.
checkOOOExpCounterResetHeader()
@@ -4882,7 +4882,7 @@ func TestOOOHistogramCounterResetHeaders(t *testing.T) {
appendHistogram(300, tsdbutil.SetHistogramCounterReset(tsdbutil.GenerateTestHistogram(3000)))
for i := 1; i <= 4; i++ {
- appendHistogram(300+int64(i), tsdbutil.GenerateTestHistogram(3000+i))
+ appendHistogram(300+int64(i), tsdbutil.GenerateTestHistogram(3000+int64(i)))
}
// One mmapped chunk with (ts, val) [(300, 3000), (301, 3001), (302, 3002), (303, 3003), (350, 4000)].
diff --git a/tsdb/ooo_head_test.go b/tsdb/ooo_head_test.go
index 37a46e76d..203330fcd 100644
--- a/tsdb/ooo_head_test.go
+++ b/tsdb/ooo_head_test.go
@@ -54,12 +54,12 @@ func TestOOOInsert(t *testing.T) {
},
"integer histogram": {
sampleFunc: func(ts int64) sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(ts))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(ts)}
},
},
"float histogram": {
sampleFunc: func(ts int64) sample {
- return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(int(ts))}
+ return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(ts)}
},
},
}
@@ -118,12 +118,12 @@ func TestOOOInsertDuplicate(t *testing.T) {
},
"integer histogram": {
sampleFunc: func(ts int64) sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(ts))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(ts)}
},
},
"float histogram": {
sampleFunc: func(ts int64) sample {
- return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(int(ts))}
+ return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(ts)}
},
},
}
diff --git a/tsdb/querier_test.go b/tsdb/querier_test.go
index 40ec7e460..740692d8c 100644
--- a/tsdb/querier_test.go
+++ b/tsdb/querier_test.go
@@ -1866,12 +1866,12 @@ func checkCurrVal(t *testing.T, valType chunkenc.ValueType, it *populateWithDelS
ts, h := it.AtHistogram(nil)
require.Equal(t, int64(expectedTs), ts)
h.CounterResetHint = histogram.UnknownCounterReset
- require.Equal(t, tsdbutil.GenerateTestHistogram(expectedValue), h)
+ require.Equal(t, tsdbutil.GenerateTestHistogram(int64(expectedValue)), h)
case chunkenc.ValFloatHistogram:
ts, h := it.AtFloatHistogram(nil)
require.Equal(t, int64(expectedTs), ts)
h.CounterResetHint = histogram.UnknownCounterReset
- require.Equal(t, tsdbutil.GenerateTestFloatHistogram(expectedValue), h)
+ require.Equal(t, tsdbutil.GenerateTestFloatHistogram(int64(expectedValue)), h)
default:
panic("unexpected value type")
}
@@ -3661,16 +3661,16 @@ func TestQueryWithDeletedHistograms(t *testing.T) {
ctx := context.Background()
testcases := map[string]func(int) (*histogram.Histogram, *histogram.FloatHistogram){
"intCounter": func(i int) (*histogram.Histogram, *histogram.FloatHistogram) {
- return tsdbutil.GenerateTestHistogram(i), nil
+ return tsdbutil.GenerateTestHistogram(int64(i)), nil
},
"intgauge": func(i int) (*histogram.Histogram, *histogram.FloatHistogram) {
- return tsdbutil.GenerateTestGaugeHistogram(rand.Int() % 1000), nil
+ return tsdbutil.GenerateTestGaugeHistogram(rand.Int63() % 1000), nil
},
"floatCounter": func(i int) (*histogram.Histogram, *histogram.FloatHistogram) {
- return nil, tsdbutil.GenerateTestFloatHistogram(i)
+ return nil, tsdbutil.GenerateTestFloatHistogram(int64(i))
},
"floatGauge": func(i int) (*histogram.Histogram, *histogram.FloatHistogram) {
- return nil, tsdbutil.GenerateTestGaugeFloatHistogram(rand.Int() % 1000)
+ return nil, tsdbutil.GenerateTestGaugeFloatHistogram(rand.Int63() % 1000)
},
}
diff --git a/tsdb/testutil.go b/tsdb/testutil.go
index c39eb133c..57516c627 100644
--- a/tsdb/testutil.go
+++ b/tsdb/testutil.go
@@ -63,45 +63,45 @@ var sampleTypeScenarios = map[string]sampleTypeScenario{
intHistogram: {
sampleType: sampleMetricTypeHistogram,
appendFunc: func(appender storage.Appender, lbls labels.Labels, ts, value int64) (storage.SeriesRef, sample, error) {
- s := sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(value))}
+ s := sample{t: ts, h: tsdbutil.GenerateTestHistogram(value)}
ref, err := appender.AppendHistogram(0, lbls, ts, s.h, nil)
return ref, s, err
},
sampleFunc: func(ts, value int64) sample {
- return sample{t: ts, h: tsdbutil.GenerateTestHistogram(int(value))}
+ return sample{t: ts, h: tsdbutil.GenerateTestHistogram(value)}
},
},
floatHistogram: {
sampleType: sampleMetricTypeHistogram,
appendFunc: func(appender storage.Appender, lbls labels.Labels, ts, value int64) (storage.SeriesRef, sample, error) {
- s := sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(int(value))}
+ s := sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(value)}
ref, err := appender.AppendHistogram(0, lbls, ts, nil, s.fh)
return ref, s, err
},
sampleFunc: func(ts, value int64) sample {
- return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(int(value))}
+ return sample{t: ts, fh: tsdbutil.GenerateTestFloatHistogram(value)}
},
},
gaugeIntHistogram: {
sampleType: sampleMetricTypeHistogram,
appendFunc: func(appender storage.Appender, lbls labels.Labels, ts, value int64) (storage.SeriesRef, sample, error) {
- s := sample{t: ts, h: tsdbutil.GenerateTestGaugeHistogram(int(value))}
+ s := sample{t: ts, h: tsdbutil.GenerateTestGaugeHistogram(value)}
ref, err := appender.AppendHistogram(0, lbls, ts, s.h, nil)
return ref, s, err
},
sampleFunc: func(ts, value int64) sample {
- return sample{t: ts, h: tsdbutil.GenerateTestGaugeHistogram(int(value))}
+ return sample{t: ts, h: tsdbutil.GenerateTestGaugeHistogram(value)}
},
},
gaugeFloatHistogram: {
sampleType: sampleMetricTypeHistogram,
appendFunc: func(appender storage.Appender, lbls labels.Labels, ts, value int64) (storage.SeriesRef, sample, error) {
- s := sample{t: ts, fh: tsdbutil.GenerateTestGaugeFloatHistogram(int(value))}
+ s := sample{t: ts, fh: tsdbutil.GenerateTestGaugeFloatHistogram(value)}
ref, err := appender.AppendHistogram(0, lbls, ts, nil, s.fh)
return ref, s, err
},
sampleFunc: func(ts, value int64) sample {
- return sample{t: ts, fh: tsdbutil.GenerateTestGaugeFloatHistogram(int(value))}
+ return sample{t: ts, fh: tsdbutil.GenerateTestGaugeFloatHistogram(value)}
},
},
}
diff --git a/tsdb/tsdbutil/histogram.go b/tsdb/tsdbutil/histogram.go
index ce934a638..60c3e5f72 100644
--- a/tsdb/tsdbutil/histogram.go
+++ b/tsdb/tsdbutil/histogram.go
@@ -21,7 +21,7 @@ import (
func GenerateTestHistograms(n int) (r []*histogram.Histogram) {
for i := 0; i < n; i++ {
- h := GenerateTestHistogram(i)
+ h := GenerateTestHistogram(int64(i))
if i > 0 {
h.CounterResetHint = histogram.NotCounterReset
}
@@ -31,13 +31,13 @@ func GenerateTestHistograms(n int) (r []*histogram.Histogram) {
}
func GenerateTestHistogramWithHint(n int, hint histogram.CounterResetHint) *histogram.Histogram {
- h := GenerateTestHistogram(n)
+ h := GenerateTestHistogram(int64(n))
h.CounterResetHint = hint
return h
}
// GenerateTestHistogram but it is up to the user to set any known counter reset hint.
-func GenerateTestHistogram(i int) *histogram.Histogram {
+func GenerateTestHistogram(i int64) *histogram.Histogram {
return &histogram.Histogram{
Count: 12 + uint64(i*9),
ZeroCount: 2 + uint64(i),
@@ -48,16 +48,16 @@ func GenerateTestHistogram(i int) *histogram.Histogram {
{Offset: 0, Length: 2},
{Offset: 1, Length: 2},
},
- PositiveBuckets: []int64{int64(i + 1), 1, -1, 0},
+ PositiveBuckets: []int64{i + 1, 1, -1, 0},
NegativeSpans: []histogram.Span{
{Offset: 0, Length: 2},
{Offset: 1, Length: 2},
},
- NegativeBuckets: []int64{int64(i + 1), 1, -1, 0},
+ NegativeBuckets: []int64{i + 1, 1, -1, 0},
}
}
-func GenerateTestCustomBucketsHistogram(i int) *histogram.Histogram {
+func GenerateTestCustomBucketsHistogram(i int64) *histogram.Histogram {
return &histogram.Histogram{
Count: 5 + uint64(i*4),
Sum: 18.4 * float64(i+1),
@@ -66,20 +66,20 @@ func GenerateTestCustomBucketsHistogram(i int) *histogram.Histogram {
{Offset: 0, Length: 2},
{Offset: 1, Length: 2},
},
- PositiveBuckets: []int64{int64(i + 1), 1, -1, 0},
+ PositiveBuckets: []int64{i + 1, 1, -1, 0},
CustomValues: []float64{0, 1, 2, 3, 4},
}
}
func GenerateTestGaugeHistograms(n int) (r []*histogram.Histogram) {
for x := 0; x < n; x++ {
- i := int(math.Sin(float64(x))*100) + 100
+ i := int64(math.Sin(float64(x))*100) + 100
r = append(r, GenerateTestGaugeHistogram(i))
}
return r
}
-func GenerateTestGaugeHistogram(i int) *histogram.Histogram {
+func GenerateTestGaugeHistogram(i int64) *histogram.Histogram {
h := GenerateTestHistogram(i)
h.CounterResetHint = histogram.GaugeType
return h
@@ -87,7 +87,7 @@ func GenerateTestGaugeHistogram(i int) *histogram.Histogram {
func GenerateTestFloatHistograms(n int) (r []*histogram.FloatHistogram) {
for i := 0; i < n; i++ {
- h := GenerateTestFloatHistogram(i)
+ h := GenerateTestFloatHistogram(int64(i))
if i > 0 {
h.CounterResetHint = histogram.NotCounterReset
}
@@ -97,7 +97,7 @@ func GenerateTestFloatHistograms(n int) (r []*histogram.FloatHistogram) {
}
// GenerateTestFloatHistogram but it is up to the user to set any known counter reset hint.
-func GenerateTestFloatHistogram(i int) *histogram.FloatHistogram {
+func GenerateTestFloatHistogram(i int64) *histogram.FloatHistogram {
return &histogram.FloatHistogram{
Count: 12 + float64(i*9),
ZeroCount: 2 + float64(i),
@@ -117,7 +117,7 @@ func GenerateTestFloatHistogram(i int) *histogram.FloatHistogram {
}
}
-func GenerateTestCustomBucketsFloatHistogram(i int) *histogram.FloatHistogram {
+func GenerateTestCustomBucketsFloatHistogram(i int64) *histogram.FloatHistogram {
return &histogram.FloatHistogram{
Count: 5 + float64(i*4),
Sum: 18.4 * float64(i+1),
@@ -133,13 +133,13 @@ func GenerateTestCustomBucketsFloatHistogram(i int) *histogram.FloatHistogram {
func GenerateTestGaugeFloatHistograms(n int) (r []*histogram.FloatHistogram) {
for x := 0; x < n; x++ {
- i := int(math.Sin(float64(x))*100) + 100
+ i := int64(math.Sin(float64(x))*100) + 100
r = append(r, GenerateTestGaugeFloatHistogram(i))
}
return r
}
-func GenerateTestGaugeFloatHistogram(i int) *histogram.FloatHistogram {
+func GenerateTestGaugeFloatHistogram(i int64) *histogram.FloatHistogram {
h := GenerateTestFloatHistogram(i)
h.CounterResetHint = histogram.GaugeType
return h
diff --git a/util/annotations/annotations.go b/util/annotations/annotations.go
index 1b743f705..5b2fde152 100644
--- a/util/annotations/annotations.go
+++ b/util/annotations/annotations.go
@@ -148,6 +148,7 @@ var (
HistogramQuantileForcedMonotonicityInfo = fmt.Errorf("%w: input to histogram_quantile needed to be fixed for monotonicity (see https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile) for metric name", PromQLInfo)
IncompatibleTypesInBinOpInfo = fmt.Errorf("%w: incompatible sample types encountered for binary operator", PromQLInfo)
HistogramIgnoredInAggregationInfo = fmt.Errorf("%w: ignored histogram in", PromQLInfo)
+ HistogramIgnoredInMixedRangeInfo = fmt.Errorf("%w: ignored histograms in a range containing both floats and histograms for metric name", PromQLInfo)
)
type annoErr struct {
@@ -293,3 +294,10 @@ func NewHistogramIgnoredInAggregationInfo(aggregation string, pos posrange.Posit
Err: fmt.Errorf("%w %s aggregation", HistogramIgnoredInAggregationInfo, aggregation),
}
}
+
+func NewHistogramIgnoredInMixedRangeInfo(metricName string, pos posrange.PositionRange) error {
+ return annoErr{
+ PositionRange: pos,
+ Err: fmt.Errorf("%w %q", HistogramIgnoredInMixedRangeInfo, metricName),
+ }
+}
diff --git a/util/testutil/context.go b/util/testutil/context.go
index 0c9e0f6f6..ea4b0e374 100644
--- a/util/testutil/context.go
+++ b/util/testutil/context.go
@@ -49,8 +49,8 @@ func (c *MockContext) Value(interface{}) interface{} {
// MockContextErrAfter is a MockContext that will return an error after a certain
// number of calls to Err().
type MockContextErrAfter struct {
+ count atomic.Uint64
MockContext
- count atomic.Uint64
FailAfter uint64
}
diff --git a/web/ui/mantine-ui/package.json b/web/ui/mantine-ui/package.json
index 4e4b0d181..a8c7ebd41 100644
--- a/web/ui/mantine-ui/package.json
+++ b/web/ui/mantine-ui/package.json
@@ -1,7 +1,7 @@
{
"name": "@prometheus-io/mantine-ui",
"private": true,
- "version": "0.300.0",
+ "version": "0.300.1",
"type": "module",
"scripts": {
"start": "vite",
@@ -28,7 +28,7 @@
"@microsoft/fetch-event-source": "^2.0.1",
"@nexucis/fuzzy": "^0.5.1",
"@nexucis/kvsearch": "^0.9.1",
- "@prometheus-io/codemirror-promql": "0.300.0",
+ "@prometheus-io/codemirror-promql": "0.300.1",
"@reduxjs/toolkit": "^2.5.0",
"@tabler/icons-react": "^3.24.0",
"@tanstack/react-query": "^5.62.7",
diff --git a/web/ui/mantine-ui/src/components/SettingsMenu.tsx b/web/ui/mantine-ui/src/components/SettingsMenu.tsx
index ada252d57..aae38909d 100644
--- a/web/ui/mantine-ui/src/components/SettingsMenu.tsx
+++ b/web/ui/mantine-ui/src/components/SettingsMenu.tsx
@@ -1,4 +1,12 @@
-import { Popover, ActionIcon, Fieldset, Checkbox, Stack } from "@mantine/core";
+import {
+ Popover,
+ ActionIcon,
+ Fieldset,
+ Checkbox,
+ Stack,
+ Group,
+ NumberInput,
+} from "@mantine/core";
import { IconSettings } from "@tabler/icons-react";
import { FC } from "react";
import { useAppDispatch } from "../state/hooks";
@@ -13,6 +21,8 @@ const SettingsMenu: FC = () => {
enableSyntaxHighlighting,
enableLinter,
showAnnotations,
+ ruleGroupsPerPage,
+ alertGroupsPerPage,
} = useSettings();
const dispatch = useAppDispatch();
@@ -29,82 +39,126 @@ const SettingsMenu: FC = () => {
-
-
-
-
-
-
-
- dispatch(
- updateSettings({
- showAnnotations: event.currentTarget.checked,
- })
- )
- }
- />
-
-
+
+
+
);
diff --git a/web/ui/mantine-ui/src/pages/AlertsPage.tsx b/web/ui/mantine-ui/src/pages/AlertsPage.tsx
index 1513f73d5..3143f0b41 100644
--- a/web/ui/mantine-ui/src/pages/AlertsPage.tsx
+++ b/web/ui/mantine-ui/src/pages/AlertsPage.tsx
@@ -11,6 +11,7 @@ import {
Alert,
TextInput,
Anchor,
+ Pagination,
} from "@mantine/core";
import { useSuspenseAPIQuery } from "../api/api";
import { AlertingRule, AlertingRulesResult } from "../api/responseTypes/rules";
@@ -18,7 +19,7 @@ import badgeClasses from "../Badge.module.css";
import panelClasses from "../Panel.module.css";
import RuleDefinition from "../components/RuleDefinition";
import { humanizeDurationRelative, now } from "../lib/formatTime";
-import { Fragment, useMemo } from "react";
+import { Fragment, useEffect, useMemo } from "react";
import { StateMultiSelect } from "../components/StateMultiSelect";
import { IconInfoCircle, IconSearch } from "@tabler/icons-react";
import { LabelBadges } from "../components/LabelBadges";
@@ -26,6 +27,7 @@ import { useSettings } from "../state/settingsSlice";
import {
ArrayParam,
BooleanParam,
+ NumberParam,
StringParam,
useQueryParam,
withDefault,
@@ -33,6 +35,7 @@ import {
import { useDebouncedValue } from "@mantine/hooks";
import { KVSearch } from "@nexucis/kvsearch";
import { inputIconStyle } from "../styles";
+import CustomInfiniteScroll from "../components/CustomInfiniteScroll";
type AlertsPageData = {
// How many rules are in each state across all groups.
@@ -132,6 +135,12 @@ const buildAlertsPageData = (
return pageData;
};
+// Should be defined as a constant here instead of inline as a value
+// to avoid unnecessary re-renders. Otherwise the empty array has
+// a different reference on each render and causes subsequent memoized
+// computations to re-run as long as no state filter is selected.
+const emptyStateFilter: string[] = [];
+
export default function AlertsPage() {
// Fetch the alerting rules data.
const { data } = useSuspenseAPIQuery({
@@ -146,7 +155,7 @@ export default function AlertsPage() {
// Define URL query params.
const [stateFilter, setStateFilter] = useQueryParam(
"state",
- withDefault(ArrayParam, [])
+ withDefault(ArrayParam, emptyStateFilter)
);
const [searchFilter, setSearchFilter] = useQueryParam(
"search",
@@ -158,132 +167,117 @@ export default function AlertsPage() {
withDefault(BooleanParam, true)
);
+ const { alertGroupsPerPage } = useSettings();
+ const [activePage, setActivePage] = useQueryParam(
+ "page",
+ withDefault(NumberParam, 1)
+ );
+
// Update the page data whenever the fetched data or filters change.
const alertsPageData: AlertsPageData = useMemo(
() => buildAlertsPageData(data.data, debouncedSearch, stateFilter),
[data, stateFilter, debouncedSearch]
);
- const shownGroups = showEmptyGroups
- ? alertsPageData.groups
- : alertsPageData.groups.filter((g) => g.rules.length > 0);
+ const shownGroups = useMemo(
+ () =>
+ showEmptyGroups
+ ? alertsPageData.groups
+ : alertsPageData.groups.filter((g) => g.rules.length > 0),
+ [alertsPageData.groups, showEmptyGroups]
+ );
- return (
-
-
-
- o === "inactive"
- ? badgeClasses.healthOk
- : o === "pending"
- ? badgeClasses.healthWarn
- : badgeClasses.healthErr
- }
- optionCount={(o) =>
- alertsPageData.globalCounts[
- o as keyof typeof alertsPageData.globalCounts
- ]
- }
- placeholder="Filter by rule state"
- values={(stateFilter?.filter((v) => v !== null) as string[]) || []}
- onChange={(values) => setStateFilter(values)}
- />
- }
- placeholder="Filter by rule name or labels"
- value={searchFilter || ""}
- onChange={(event) =>
- setSearchFilter(event.currentTarget.value || null)
- }
- >
-
- {alertsPageData.groups.length === 0 ? (
- }>
- No rules found.
-
- ) : (
- !showEmptyGroups &&
- alertsPageData.groups.length !== shownGroups.length && (
- }
- >
- Hiding {alertsPageData.groups.length - shownGroups.length} empty
- groups due to filters or no rules.
- setShowEmptyGroups(true)}>
- Show empty groups
-
-
- )
- )}
-
- {shownGroups.map((g, i) => {
- return (
-
-
-
-
- {g.name}
-
-
- {g.file}
-
-
-
- {g.counts.firing > 0 && (
-
- firing ({g.counts.firing})
-
- )}
- {g.counts.pending > 0 && (
-
- pending ({g.counts.pending})
-
- )}
- {g.counts.inactive > 0 && (
-
- inactive ({g.counts.inactive})
-
- )}
-
-
- {g.counts.total === 0 ? (
- }>
- No rules in this group.
- setShowEmptyGroups(false)}
- >
- Hide empty groups
-
-
- ) : g.rules.length === 0 ? (
- }>
- No rules in this group match your filter criteria (omitted{" "}
- {g.counts.total} filtered rules).
- setShowEmptyGroups(false)}
- >
- Hide empty groups
-
-
- ) : (
+ // If we were e.g. on page 10 and the number of total pages decreases to 5 (due to filtering
+ // or changing the max number of items per page), go to the largest possible page.
+ const totalPageCount = Math.ceil(shownGroups.length / alertGroupsPerPage);
+ const effectiveActivePage = Math.max(1, Math.min(activePage, totalPageCount));
+
+ useEffect(() => {
+ if (effectiveActivePage !== activePage) {
+ setActivePage(effectiveActivePage);
+ }
+ }, [effectiveActivePage, activePage, setActivePage]);
+
+ const currentPageGroups = useMemo(
+ () =>
+ shownGroups.slice(
+ (effectiveActivePage - 1) * alertGroupsPerPage,
+ effectiveActivePage * alertGroupsPerPage
+ ),
+ [shownGroups, effectiveActivePage, alertGroupsPerPage]
+ );
+
+ // We memoize the actual rendering of the page items to avoid re-rendering
+ // them on every state change. This is especially important when the user
+ // types into the search box, as the search filter changes on every keystroke,
+ // even before debouncing takes place (extracting the filters and results list
+ // into separate components would be an alternative to this, but it's kinda
+ // convenient to have in the same file IMO).
+ const renderedPageItems = useMemo(
+ () =>
+ currentPageGroups.map((g, i) => (
+
+
+
+
+ {g.name}
+
+
+ {g.file}
+
+
+
+ {g.counts.firing > 0 && (
+
+ firing ({g.counts.firing})
+
+ )}
+ {g.counts.pending > 0 && (
+
+ pending ({g.counts.pending})
+
+ )}
+ {g.counts.inactive > 0 && (
+
+ inactive ({g.counts.inactive})
+
+ )}
+
+
+ {g.counts.total === 0 ? (
+ }>
+ No rules in this group.
+ setShowEmptyGroups(false)}
+ >
+ Hide empty groups
+
+
+ ) : g.rules.length === 0 ? (
+ }>
+ No rules in this group match your filter criteria (omitted{" "}
+ {g.counts.total} filtered rules).
+ setShowEmptyGroups(false)}
+ >
+ Hide empty groups
+
+
+ ) : (
+ (
- {g.rules.map((r, j) => {
+ {items.map((r, j) => {
return (
0 && (
-
+
Alert labels
State
Active Since
@@ -405,9 +399,71 @@ export default function AlertsPage() {
})}
)}
-
- );
- })}
+ />
+ )}
+
+ )),
+ [currentPageGroups, showAnnotations, setShowEmptyGroups]
+ );
+
+ return (
+
+
+
+ o === "inactive"
+ ? badgeClasses.healthOk
+ : o === "pending"
+ ? badgeClasses.healthWarn
+ : badgeClasses.healthErr
+ }
+ optionCount={(o) =>
+ alertsPageData.globalCounts[
+ o as keyof typeof alertsPageData.globalCounts
+ ]
+ }
+ placeholder="Filter by rule state"
+ values={(stateFilter?.filter((v) => v !== null) as string[]) || []}
+ onChange={(values) => setStateFilter(values)}
+ />
+ }
+ placeholder="Filter by rule name or labels"
+ value={searchFilter || ""}
+ onChange={(event) =>
+ setSearchFilter(event.currentTarget.value || null)
+ }
+ >
+
+ {alertsPageData.groups.length === 0 ? (
+ }>
+ No rules found.
+
+ ) : (
+ !showEmptyGroups &&
+ alertsPageData.groups.length !== shownGroups.length && (
+ }
+ >
+ Hiding {alertsPageData.groups.length - shownGroups.length} empty
+ groups due to filters or no rules.
+ setShowEmptyGroups(true)}>
+ Show empty groups
+
+
+ )
+ )}
+
+
+ {renderedPageItems}
);
diff --git a/web/ui/mantine-ui/src/pages/RulesPage.tsx b/web/ui/mantine-ui/src/pages/RulesPage.tsx
index a4ed44e7c..0888fe473 100644
--- a/web/ui/mantine-ui/src/pages/RulesPage.tsx
+++ b/web/ui/mantine-ui/src/pages/RulesPage.tsx
@@ -4,6 +4,7 @@ import {
Badge,
Card,
Group,
+ Pagination,
rem,
Stack,
Text,
@@ -29,6 +30,10 @@ import { RulesResult } from "../api/responseTypes/rules";
import badgeClasses from "../Badge.module.css";
import RuleDefinition from "../components/RuleDefinition";
import { badgeIconStyle } from "../styles";
+import { NumberParam, useQueryParam, withDefault } from "use-query-params";
+import { useSettings } from "../state/settingsSlice";
+import { useEffect } from "react";
+import CustomInfiniteScroll from "../components/CustomInfiniteScroll";
const healthBadgeClass = (state: string) => {
switch (state) {
@@ -45,6 +50,23 @@ const healthBadgeClass = (state: string) => {
export default function RulesPage() {
const { data } = useSuspenseAPIQuery({ path: `/rules` });
+ const { ruleGroupsPerPage } = useSettings();
+
+ const [activePage, setActivePage] = useQueryParam(
+ "page",
+ withDefault(NumberParam, 1)
+ );
+
+ // If we were e.g. on page 10 and the number of total pages decreases to 5 (due
+ // changing the max number of items per page), go to the largest possible page.
+ const totalPageCount = Math.ceil(data.data.groups.length / ruleGroupsPerPage);
+ const effectiveActivePage = Math.max(1, Math.min(activePage, totalPageCount));
+
+ useEffect(() => {
+ if (effectiveActivePage !== activePage) {
+ setActivePage(effectiveActivePage);
+ }
+ }, [effectiveActivePage, activePage, setActivePage]);
return (
@@ -53,157 +75,178 @@ export default function RulesPage() {
No rule groups configured.
)}
- {data.data.groups.map((g, i) => (
-
-
-
-
- {g.name}
-
-
- {g.file}
-
-
-
-
- }
- >
- last run {humanizeDurationRelative(g.lastEvaluation, now())}
-
-
-
- }
- >
- took {humanizeDuration(parseFloat(g.evaluationTime) * 1000)}
-
-
-
- }
- >
- every {humanizeDuration(parseFloat(g.interval) * 1000)}{" "}
-
-
+
+ {data.data.groups
+ .slice(
+ (effectiveActivePage - 1) * ruleGroupsPerPage,
+ effectiveActivePage * ruleGroupsPerPage
+ )
+ .map((g, i) => (
+
+
+
+
+ {g.name}
+
+
+ {g.file}
+
+
+
+
+ }
+ >
+ last run {humanizeDurationRelative(g.lastEvaluation, now())}
+
+
+
+ }
+ >
+ took {humanizeDuration(parseFloat(g.evaluationTime) * 1000)}
+
+
+
+ }
+ >
+ every {humanizeDuration(parseFloat(g.interval) * 1000)}{" "}
+
+
+
-
- {g.rules.length === 0 && (
- }>
- No rules in rule group.
-
- )}
-
- {g.rules.map((r, j) => (
-
-
-
-
- {r.type === "alerting" ? (
-
-
-
- ) : (
-
-
-
- )}
- {r.name}
-
-
-
-
- }
- >
- {humanizeDurationRelative(r.lastEvaluation, now())}
-
-
+ {g.rules.length === 0 && (
+ }>
+ No rules in rule group.
+
+ )}
+ (
+
+ {items.map((r, j) => (
+
+
+
+
+ {r.type === "alerting" ? (
+
+
+
+ ) : (
+
+
+
+ )}
+ {r.name}
+
+
+
+
+
+ }
+ >
+ {humanizeDurationRelative(
+ r.lastEvaluation,
+ now()
+ )}
+
+
-
-
- }
+
+
+ }
+ >
+ {humanizeDuration(
+ parseFloat(r.evaluationTime) * 1000
+ )}
+
+
+
+
+ {r.health}
+
+
+
+
+
+
+ {r.lastError && (
+ }
>
- {humanizeDuration(
- parseFloat(r.evaluationTime) * 1000
- )}
-
-
-
-
- {r.health}
-
-
-
-
-
-
- {r.lastError && (
- }
- >
- Error: {r.lastError}
-
- )}
-
-
- ))}
-
-
- ))}
+ Error: {r.lastError}
+
+ )}
+
+
+ ))}
+
+ )}
+ />
+
+ ))}
);
}
diff --git a/web/ui/mantine-ui/src/promql/tools/go.mod b/web/ui/mantine-ui/src/promql/tools/go.mod
index aac6e019a..40a7876a0 100644
--- a/web/ui/mantine-ui/src/promql/tools/go.mod
+++ b/web/ui/mantine-ui/src/promql/tools/go.mod
@@ -1,6 +1,6 @@
module github.com/prometheus/prometheus/web/ui/mantine-ui/src/promql/tools
-go 1.22.0
+go 1.22.7
require (
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc
diff --git a/web/ui/mantine-ui/src/state/localStorageMiddleware.ts b/web/ui/mantine-ui/src/state/localStorageMiddleware.ts
index 93eae950e..79baa5ac6 100644
--- a/web/ui/mantine-ui/src/state/localStorageMiddleware.ts
+++ b/web/ui/mantine-ui/src/state/localStorageMiddleware.ts
@@ -63,6 +63,7 @@ startAppListening({
case "enableSyntaxHighlighting":
case "enableLinter":
case "showAnnotations":
+ case "ruleGroupsPerPage":
return persistToLocalStorage(`settings.${key}`, value);
}
});
diff --git a/web/ui/mantine-ui/src/state/settingsSlice.ts b/web/ui/mantine-ui/src/state/settingsSlice.ts
index ea744e014..c4154b725 100644
--- a/web/ui/mantine-ui/src/state/settingsSlice.ts
+++ b/web/ui/mantine-ui/src/state/settingsSlice.ts
@@ -14,6 +14,8 @@ interface Settings {
enableSyntaxHighlighting: boolean;
enableLinter: boolean;
showAnnotations: boolean;
+ ruleGroupsPerPage: number;
+ alertGroupsPerPage: number;
}
// Declared/defined in public/index.html, value replaced by Prometheus when serving bundle.
@@ -29,6 +31,8 @@ export const localStorageKeyEnableSyntaxHighlighting =
"settings.enableSyntaxHighlighting";
export const localStorageKeyEnableLinter = "settings.enableLinter";
export const localStorageKeyShowAnnotations = "settings.showAnnotations";
+export const localStorageKeyRuleGroupsPerPage = "settings.ruleGroupsPerPage";
+export const localStorageKeyAlertGroupsPerPage = "settings.alertGroupsPerPage";
// This dynamically/generically determines the pathPrefix by stripping the first known
// endpoint suffix from the window location path. It works out of the box for both direct
@@ -95,6 +99,14 @@ export const initialState: Settings = {
localStorageKeyShowAnnotations,
true
),
+ ruleGroupsPerPage: initializeFromLocalStorage(
+ localStorageKeyRuleGroupsPerPage,
+ 10
+ ),
+ alertGroupsPerPage: initializeFromLocalStorage(
+ localStorageKeyAlertGroupsPerPage,
+ 10
+ ),
};
export const settingsSlice = createSlice({
diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json
index 5136d036c..c10ebf611 100644
--- a/web/ui/module/codemirror-promql/package.json
+++ b/web/ui/module/codemirror-promql/package.json
@@ -1,6 +1,6 @@
{
"name": "@prometheus-io/codemirror-promql",
- "version": "0.300.0",
+ "version": "0.300.1",
"description": "a CodeMirror mode for the PromQL language",
"types": "dist/esm/index.d.ts",
"module": "dist/esm/index.js",
@@ -29,7 +29,7 @@
},
"homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/codemirror-promql/README.md",
"dependencies": {
- "@prometheus-io/lezer-promql": "0.300.0",
+ "@prometheus-io/lezer-promql": "0.300.1",
"lru-cache": "^11.0.2"
},
"devDependencies": {
diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json
index 5f35e621c..bb7af294d 100644
--- a/web/ui/module/lezer-promql/package.json
+++ b/web/ui/module/lezer-promql/package.json
@@ -1,6 +1,6 @@
{
"name": "@prometheus-io/lezer-promql",
- "version": "0.300.0",
+ "version": "0.300.1",
"description": "lezer-based PromQL grammar",
"main": "dist/index.cjs",
"type": "module",
diff --git a/web/ui/package-lock.json b/web/ui/package-lock.json
index 88feb75eb..a73f55a49 100644
--- a/web/ui/package-lock.json
+++ b/web/ui/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "prometheus-io",
- "version": "0.300.0",
+ "version": "0.300.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "prometheus-io",
- "version": "0.300.0",
+ "version": "0.300.1",
"workspaces": [
"mantine-ui",
"module/*"
@@ -24,7 +24,7 @@
},
"mantine-ui": {
"name": "@prometheus-io/mantine-ui",
- "version": "0.300.0",
+ "version": "0.300.1",
"dependencies": {
"@codemirror/autocomplete": "^6.18.3",
"@codemirror/language": "^6.10.6",
@@ -42,7 +42,7 @@
"@microsoft/fetch-event-source": "^2.0.1",
"@nexucis/fuzzy": "^0.5.1",
"@nexucis/kvsearch": "^0.9.1",
- "@prometheus-io/codemirror-promql": "0.300.0",
+ "@prometheus-io/codemirror-promql": "0.300.1",
"@reduxjs/toolkit": "^2.5.0",
"@tabler/icons-react": "^3.24.0",
"@tanstack/react-query": "^5.62.7",
@@ -147,10 +147,10 @@
},
"module/codemirror-promql": {
"name": "@prometheus-io/codemirror-promql",
- "version": "0.300.0",
+ "version": "0.300.1",
"license": "Apache-2.0",
"dependencies": {
- "@prometheus-io/lezer-promql": "0.300.0",
+ "@prometheus-io/lezer-promql": "0.300.1",
"lru-cache": "^11.0.2"
},
"devDependencies": {
@@ -180,7 +180,7 @@
},
"module/lezer-promql": {
"name": "@prometheus-io/lezer-promql",
- "version": "0.300.0",
+ "version": "0.300.1",
"license": "Apache-2.0",
"devDependencies": {
"@lezer/generator": "^1.7.2",
diff --git a/web/ui/package.json b/web/ui/package.json
index ad531e67a..bfebd64bd 100644
--- a/web/ui/package.json
+++ b/web/ui/package.json
@@ -1,7 +1,7 @@
{
"name": "prometheus-io",
"description": "Monorepo for the Prometheus UI",
- "version": "0.300.0",
+ "version": "0.300.1",
"private": true,
"scripts": {
"build": "bash build_ui.sh --all",
diff --git a/web/ui/react-app/package-lock.json b/web/ui/react-app/package-lock.json
index 284a55edf..6dec47616 100644
--- a/web/ui/react-app/package-lock.json
+++ b/web/ui/react-app/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@prometheus-io/app",
- "version": "0.300.0",
+ "version": "0.300.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@prometheus-io/app",
- "version": "0.300.0",
+ "version": "0.300.1",
"dependencies": {
"@codemirror/autocomplete": "^6.18.3",
"@codemirror/commands": "^6.7.1",
diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json
index 928ae33ee..a801be62d 100644
--- a/web/ui/react-app/package.json
+++ b/web/ui/react-app/package.json
@@ -1,6 +1,6 @@
{
"name": "@prometheus-io/app",
- "version": "0.300.0",
+ "version": "0.300.1",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.18.3",