Merge branch 'main' into release-3.0-beta.0

Conflicts:
	scrape/scrape_test.go
          Pick both changes.
This commit is contained in:
Jan Fajerski 2024-09-10 20:51:20 +02:00
commit 91608c002f
21 changed files with 423 additions and 170 deletions

View file

@ -12,13 +12,9 @@ jobs:
# Whenever the Go version is updated here, .promu.yml # Whenever the Go version is updated here, .promu.yml
# should also be updated. # should also be updated.
image: quay.io/prometheus/golang-builder:1.23-base image: quay.io/prometheus/golang-builder:1.23-base
env:
# Preliminary fix to make Go tests with race detector not use too much memory,
# see https://github.com/prometheus/prometheus/issues/14858.
GOMEMLIMIT: 10GiB
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/setup_environment - uses: ./.github/promci/actions/setup_environment
with: with:
enable_npm: true enable_npm: true
@ -34,7 +30,7 @@ jobs:
image: quay.io/prometheus/golang-builder:1.23-base image: quay.io/prometheus/golang-builder:1.23-base
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/setup_environment - uses: ./.github/promci/actions/setup_environment
- run: go test --tags=dedupelabels ./... - run: go test --tags=dedupelabels ./...
- run: GOARCH=386 go test ./cmd/prometheus - run: GOARCH=386 go test ./cmd/prometheus
@ -67,7 +63,7 @@ jobs:
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/setup_environment - uses: ./.github/promci/actions/setup_environment
with: with:
enable_go: false enable_go: false
@ -126,7 +122,7 @@ jobs:
thread: [ 0, 1, 2 ] thread: [ 0, 1, 2 ]
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/build - uses: ./.github/promci/actions/build
with: with:
promu_opts: "-p linux/amd64 -p windows/amd64 -p linux/arm64 -p darwin/amd64 -p darwin/arm64 -p linux/386" promu_opts: "-p linux/amd64 -p windows/amd64 -p linux/arm64 -p darwin/amd64 -p darwin/arm64 -p linux/386"
@ -151,7 +147,7 @@ jobs:
# should also be updated. # should also be updated.
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/build - uses: ./.github/promci/actions/build
with: with:
parallelism: 12 parallelism: 12
@ -213,7 +209,7 @@ jobs:
if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' if: github.event_name == 'push' && github.event.ref == 'refs/heads/main'
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/publish_main - uses: ./.github/promci/actions/publish_main
with: with:
docker_hub_login: ${{ secrets.docker_hub_login }} docker_hub_login: ${{ secrets.docker_hub_login }}
@ -230,7 +226,7 @@ jobs:
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v3.')) (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v3.'))
steps: steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- uses: ./.github/promci/actions/publish_release - uses: ./.github/promci/actions/publish_release
with: with:
docker_hub_login: ${{ secrets.docker_hub_login }} docker_hub_login: ${{ secrets.docker_hub_login }}
@ -245,7 +241,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: prometheus/promci@45166329da36d74895901808f1c8c97efafc7f84 # v0.3.0 - uses: prometheus/promci@468927c440349ab56c4a1aafd453b312841503c2 # v0.4.4
- name: Install nodejs - name: Install nodejs
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
with: with:

View file

@ -13,13 +13,12 @@ Maintainers for specific parts of the codebase:
* `k8s`: Frederic Branczyk (<fbranczyk@gmail.com> / @brancz) * `k8s`: Frederic Branczyk (<fbranczyk@gmail.com> / @brancz)
* `documentation` * `documentation`
* `prometheus-mixin`: Matthias Loibl (<mail@matthiasloibl.com> / @metalmatze) * `prometheus-mixin`: Matthias Loibl (<mail@matthiasloibl.com> / @metalmatze)
* `model/histogram` and other code related to native histograms: Björn Rabenstein (<beorn@grafana.com> / @beorn7), * `model/histogram` and other code related to native histograms: Björn Rabenstein (<beorn@grafana.com> / @beorn7),
George Krajcsovits (<gyorgy.krajcsovits@grafana.com> / @krajorama) George Krajcsovits (<gyorgy.krajcsovits@grafana.com> / @krajorama)
* `storage` * `storage`
* `remote`: Callum Styan (<callumstyan@gmail.com> / @cstyan), Bartłomiej Płotka (<bwplotka@gmail.com> / @bwplotka), Tom Wilkie (tom.wilkie@gmail.com / @tomwilkie), Nicolás Pazos ( <npazosmendez@gmail.com> / @npazosmendez), Alex Greenbank ( <alex.greenbank@grafana.com> / @alexgreenbank) * `remote`: Callum Styan (<callumstyan@gmail.com> / @cstyan), Bartłomiej Płotka (<bwplotka@gmail.com> / @bwplotka), Tom Wilkie (tom.wilkie@gmail.com / @tomwilkie), Nicolás Pazos ( <npazosmendez@gmail.com> / @npazosmendez), Alex Greenbank ( <alex.greenbank@grafana.com> / @alexgreenbank)
* `otlptranslator`: Arve Knudsen (<arve.knudsen@gmail.com> / @aknuds1), Jesús Vázquez (<jesus.vazquez@grafana.com> / @jesusvazquez) * `otlptranslator`: Arve Knudsen (<arve.knudsen@gmail.com> / @aknuds1), Jesús Vázquez (<jesus.vazquez@grafana.com> / @jesusvazquez)
* `tsdb`: Ganesh Vernekar (<ganesh@grafana.com> / @codesome), Bartłomiej Płotka (<bwplotka@gmail.com> / @bwplotka), Jesús Vázquez (<jesus.vazquez@grafana.com> / @jesusvazquez) * `tsdb`: Ganesh Vernekar (<ganesh@grafana.com> / @codesome), Bartłomiej Płotka (<bwplotka@gmail.com> / @bwplotka), Jesús Vázquez (<jesus.vazquez@grafana.com> / @jesusvazquez)
* `agent`: Robert Fratto (<robert.fratto@grafana.com> / @rfratto)
* `web` * `web`
* `ui`: Julius Volz (<julius.volz@gmail.com> / @juliusv) * `ui`: Julius Volz (<julius.volz@gmail.com> / @juliusv)
* `module`: Augustin Husson (<husson.augustin@gmail.com> @nexucis) * `module`: Augustin Husson (<husson.augustin@gmail.com> @nexucis)

4
go.mod
View file

@ -64,7 +64,7 @@ require (
github.com/vultr/govultr/v2 v2.17.2 github.com/vultr/govultr/v2 v2.17.2
go.opentelemetry.io/collector/pdata v1.14.1 go.opentelemetry.io/collector/pdata v1.14.1
go.opentelemetry.io/collector/semconv v0.108.1 go.opentelemetry.io/collector/semconv v0.108.1
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0
go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel v1.29.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0
@ -81,7 +81,7 @@ require (
golang.org/x/text v0.18.0 golang.org/x/text v0.18.0
golang.org/x/time v0.6.0 golang.org/x/time v0.6.0
golang.org/x/tools v0.24.0 golang.org/x/tools v0.24.0
google.golang.org/api v0.196.0 google.golang.org/api v0.195.0
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed
google.golang.org/grpc v1.66.0 google.golang.org/grpc v1.66.0
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2

8
go.sum
View file

@ -736,8 +736,8 @@ go.opentelemetry.io/collector/pdata v1.14.1 h1:wXZjtQA7Vy5HFqco+yA95ENyMQU5heBB1
go.opentelemetry.io/collector/pdata v1.14.1/go.mod h1:z1dTjwwtcoXxZx2/nkHysjxMeaxe9pEmYTEr4SMNIx8= go.opentelemetry.io/collector/pdata v1.14.1/go.mod h1:z1dTjwwtcoXxZx2/nkHysjxMeaxe9pEmYTEr4SMNIx8=
go.opentelemetry.io/collector/semconv v0.108.1 h1:Txk9tauUnamZaxS5vlf1O0uZ4VD6nioRBR0nX8L/fU4= go.opentelemetry.io/collector/semconv v0.108.1 h1:Txk9tauUnamZaxS5vlf1O0uZ4VD6nioRBR0nX8L/fU4=
go.opentelemetry.io/collector/semconv v0.108.1/go.mod h1:zCJ5njhWpejR+A40kiEoeFm1xq1uzyZwMnRNX6/D82A= go.opentelemetry.io/collector/semconv v0.108.1/go.mod h1:zCJ5njhWpejR+A40kiEoeFm1xq1uzyZwMnRNX6/D82A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
@ -1056,8 +1056,8 @@ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.196.0 h1:k/RafYqebaIJBO3+SMnfEGtFVlvp5vSgqTUF54UN/zg= google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

View file

@ -131,6 +131,54 @@ func TestFloatHistogramMul(t *testing.T) {
NegativeBuckets: []float64{9, 3, 15, 18}, NegativeBuckets: []float64{9, 3, 15, 18},
}, },
}, },
{
"negation",
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: 11,
Count: 30,
Sum: 23,
PositiveSpans: []Span{{-2, 2}, {1, 3}},
PositiveBuckets: []float64{1, 0, 3, 4, 7},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{3, 1, 5, 6},
},
-1,
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: -11,
Count: -30,
Sum: -23,
PositiveSpans: []Span{{-2, 2}, {1, 3}},
PositiveBuckets: []float64{-1, 0, -3, -4, -7},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{-3, -1, -5, -6},
},
},
{
"negative multiplier",
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: 11,
Count: 30,
Sum: 23,
PositiveSpans: []Span{{-2, 2}, {1, 3}},
PositiveBuckets: []float64{1, 0, 3, 4, 7},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{3, 1, 5, 6},
},
-2,
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: -22,
Count: -60,
Sum: -46,
PositiveSpans: []Span{{-2, 2}, {1, 3}},
PositiveBuckets: []float64{-2, 0, -6, -8, -14},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{-6, -2, -10, -12},
},
},
{ {
"no-op with custom buckets", "no-op with custom buckets",
&FloatHistogram{ &FloatHistogram{
@ -409,6 +457,54 @@ func TestFloatHistogramDiv(t *testing.T) {
NegativeBuckets: []float64{1.5, 0.5, 2.5, 3}, NegativeBuckets: []float64{1.5, 0.5, 2.5, 3},
}, },
}, },
{
"negation",
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: 5.5,
Count: 3493.3,
Sum: 2349209.324,
PositiveSpans: []Span{{-2, 1}, {2, 3}},
PositiveBuckets: []float64{1, 3.3, 4.2, 0.1},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{3.1, 3, 1.234e5, 1000},
},
-1,
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: -5.5,
Count: -3493.3,
Sum: -2349209.324,
PositiveSpans: []Span{{-2, 1}, {2, 3}},
PositiveBuckets: []float64{-1, -3.3, -4.2, -0.1},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{-3.1, -3, -1.234e5, -1000},
},
},
{
"negative half",
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: 11,
Count: 30,
Sum: 23,
PositiveSpans: []Span{{-2, 2}, {1, 3}},
PositiveBuckets: []float64{1, 0, 3, 4, 7},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{3, 1, 5, 6},
},
-2,
&FloatHistogram{
ZeroThreshold: 0.01,
ZeroCount: -5.5,
Count: -15,
Sum: -11.5,
PositiveSpans: []Span{{-2, 2}, {1, 3}},
PositiveBuckets: []float64{-0.5, 0, -1.5, -2, -3.5},
NegativeSpans: []Span{{3, 2}, {3, 2}},
NegativeBuckets: []float64{-1.5, -0.5, -2.5, -3},
},
},
{ {
"no-op with custom buckets", "no-op with custom buckets",
&FloatHistogram{ &FloatHistogram{

View file

@ -1821,6 +1821,9 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,
for j := range mat[i].Floats { for j := range mat[i].Floats {
mat[i].Floats[j].F = -mat[i].Floats[j].F mat[i].Floats[j].F = -mat[i].Floats[j].F
} }
for j := range mat[i].Histograms {
mat[i].Histograms[j].H = mat[i].Histograms[j].H.Copy().Mul(-1)
}
} }
if !ev.enableDelayedNameRemoval && mat.ContainsSameLabelset() { if !ev.enableDelayedNameRemoval && mat.ContainsSameLabelset() {
ev.errorf("vector cannot contain metrics with the same labelset") ev.errorf("vector cannot contain metrics with the same labelset")

View file

@ -818,12 +818,12 @@ histogram_desc_item
$$ = yylex.(*parser).newMap() $$ = yylex.(*parser).newMap()
$$["sum"] = $3 $$["sum"] = $3
} }
| COUNT_DESC COLON number | COUNT_DESC COLON signed_or_unsigned_number
{ {
$$ = yylex.(*parser).newMap() $$ = yylex.(*parser).newMap()
$$["count"] = $3 $$["count"] = $3
} }
| ZERO_BUCKET_DESC COLON number | ZERO_BUCKET_DESC COLON signed_or_unsigned_number
{ {
$$ = yylex.(*parser).newMap() $$ = yylex.(*parser).newMap()
$$["z_bucket"] = $3 $$["z_bucket"] = $3
@ -875,11 +875,11 @@ bucket_set : LEFT_BRACKET bucket_set_list SPACE RIGHT_BRACKET
} }
; ;
bucket_set_list : bucket_set_list SPACE number bucket_set_list : bucket_set_list SPACE signed_or_unsigned_number
{ {
$$ = append($1, $3) $$ = append($1, $3)
} }
| number | signed_or_unsigned_number
{ {
$$ = []float64{$1} $$ = []float64{$1}
} }

View file

@ -410,55 +410,55 @@ const yyPrivate = 57344
const yyLast = 799 const yyLast = 799
var yyAct = [...]int16{ var yyAct = [...]int16{
155, 334, 332, 276, 339, 152, 226, 39, 192, 44, 152, 334, 332, 155, 339, 226, 39, 192, 276, 44,
291, 290, 156, 118, 82, 178, 229, 107, 106, 346, 291, 290, 118, 82, 178, 229, 107, 106, 346, 347,
347, 348, 349, 109, 108, 198, 239, 199, 133, 110, 348, 349, 109, 108, 198, 239, 199, 156, 110, 105,
105, 60, 245, 121, 6, 329, 325, 111, 328, 228, 6, 245, 200, 201, 133, 325, 111, 329, 228, 60,
200, 201, 160, 119, 304, 267, 293, 128, 260, 160, 357, 293, 328, 304, 267, 160, 266, 128, 55, 151,
151, 261, 159, 302, 358, 311, 122, 55, 89, 159, 302, 311, 302, 196, 340, 159, 55, 89, 54, 356,
196, 241, 242, 259, 113, 243, 114, 54, 98, 99, 241, 242, 355, 113, 243, 114, 54, 98, 99, 265,
302, 112, 101, 256, 104, 88, 230, 232, 234, 235, 112, 101, 256, 104, 88, 230, 232, 234, 235, 236,
244, 246, 249, 250, 251, 252, 253, 257, 258, 105,
333, 231, 233, 237, 238, 240, 247, 248, 103, 115,
109, 254, 255, 324, 150, 218, 110, 264, 111, 270,
77, 35, 7, 149, 188, 163, 322, 321, 173, 320,
167, 170, 323, 165, 271, 166, 2, 3, 4, 5,
263, 101, 194, 104, 180, 184, 197, 187, 186, 319,
272, 202, 203, 204, 205, 206, 207, 208, 209, 210,
211, 212, 213, 214, 215, 216, 195, 299, 103, 318,
217, 36, 298, 1, 190, 219, 220, 317, 160, 160,
316, 193, 160, 154, 182, 196, 229, 297, 159, 159,
160, 358, 159, 268, 181, 183, 239, 260, 296, 262,
159, 315, 245, 129, 314, 55, 225, 313, 161, 228,
161, 161, 259, 312, 161, 54, 86, 295, 310, 288,
289, 8, 161, 292, 162, 37, 162, 162, 49, 269,
162, 241, 242, 309, 179, 243, 180, 127, 162, 126,
308, 223, 294, 256, 48, 222, 230, 232, 234, 235,
236, 244, 246, 249, 250, 251, 252, 253, 257, 258, 236, 244, 246, 249, 250, 251, 252, 253, 257, 258,
160, 115, 231, 233, 237, 238, 240, 247, 248, 103, 221, 169, 231, 233, 237, 238, 240, 247, 248, 157,
159, 109, 254, 255, 324, 150, 357, 110, 333, 218, 158, 164, 254, 255, 168, 10, 182, 300, 55, 301,
111, 340, 310, 149, 77, 163, 7, 105, 35, 173, 303, 47, 305, 46, 132, 79, 181, 183, 54, 306,
167, 170, 161, 323, 165, 356, 166, 309, 355, 194, 307, 45, 134, 135, 136, 137, 138, 139, 140, 141,
2, 3, 4, 5, 308, 322, 184, 197, 162, 186, 142, 143, 144, 145, 146, 147, 148, 43, 59, 50,
321, 195, 202, 203, 204, 205, 206, 207, 208, 209, 84, 9, 9, 121, 326, 78, 327, 130, 171, 121,
210, 211, 212, 213, 214, 215, 216, 229, 129, 101, 83, 42, 131, 119, 335, 336, 337, 331, 185, 119,
217, 104, 219, 220, 190, 266, 270, 239, 160, 121, 338, 261, 342, 341, 344, 343, 122, 117, 41, 177,
268, 193, 264, 245, 55, 196, 154, 225, 159, 119, 350, 351, 122, 55, 176, 352, 53, 77, 40, 56,
228, 271, 188, 160, 54, 161, 103, 117, 265, 84, 125, 354, 22, 54, 84, 124, 172, 175, 51, 57,
262, 299, 122, 159, 320, 263, 298, 272, 10, 83, 191, 353, 273, 85, 83, 189, 359, 224, 123, 80,
161, 162, 241, 242, 269, 187, 243, 185, 79, 288, 345, 120, 81, 153, 58, 75, 227, 52, 116, 0,
289, 297, 319, 292, 256, 161, 162, 230, 232, 234, 0, 18, 19, 0, 0, 20, 0, 0, 0, 0,
235, 236, 244, 246, 249, 250, 251, 252, 253, 257,
258, 162, 294, 231, 233, 237, 238, 240, 247, 248,
318, 317, 316, 254, 255, 180, 315, 134, 135, 136,
137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
147, 148, 157, 158, 169, 105, 314, 296, 300, 301,
303, 223, 305, 313, 55, 222, 179, 168, 180, 84,
306, 307, 177, 125, 54, 182, 295, 176, 124, 83,
221, 312, 87, 89, 8, 181, 183, 81, 37, 86,
175, 123, 36, 98, 99, 326, 327, 101, 102, 104,
88, 127, 331, 126, 50, 336, 337, 338, 182, 335,
78, 1, 342, 341, 344, 343, 49, 48, 181, 183,
350, 351, 47, 55, 103, 352, 53, 77, 164, 56,
46, 354, 22, 54, 59, 55, 172, 9, 9, 57,
132, 45, 43, 130, 171, 54, 359, 42, 131, 41,
40, 51, 191, 353, 273, 75, 85, 189, 224, 80,
345, 18, 19, 120, 153, 20, 58, 227, 52, 116,
0, 76, 0, 0, 0, 0, 61, 62, 63, 64, 0, 76, 0, 0, 0, 0, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
0, 0, 0, 13, 0, 0, 0, 24, 0, 30, 0, 0, 0, 13, 0, 0, 0, 24, 0, 30,
0, 0, 31, 32, 55, 38, 0, 53, 77, 0, 0, 0, 31, 32, 55, 38, 105, 53, 77, 0,
56, 275, 0, 22, 54, 0, 0, 0, 274, 0, 56, 275, 0, 22, 54, 0, 0, 0, 274, 0,
57, 0, 278, 279, 277, 284, 286, 283, 285, 280, 57, 0, 278, 279, 277, 284, 286, 283, 285, 280,
281, 282, 287, 0, 0, 0, 75, 0, 0, 0, 281, 282, 287, 87, 89, 0, 75, 0, 0, 0,
0, 0, 18, 19, 0, 0, 20, 0, 0, 0, 0, 0, 18, 19, 98, 99, 20, 0, 101, 102,
0, 0, 76, 0, 0, 0, 0, 61, 62, 63, 104, 88, 76, 0, 0, 0, 0, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 0, 0, 0, 13, 0, 0, 0, 24, 0, 74, 0, 0, 0, 13, 103, 0, 0, 24, 0,
30, 0, 55, 31, 32, 53, 77, 0, 56, 330, 30, 0, 55, 31, 32, 53, 77, 0, 56, 330,
0, 22, 54, 0, 0, 0, 0, 0, 57, 0, 0, 22, 54, 0, 0, 0, 0, 0, 57, 0,
278, 279, 277, 284, 286, 283, 285, 280, 281, 282, 278, 279, 277, 284, 286, 283, 285, 280, 281, 282,
@ -493,51 +493,51 @@ var yyAct = [...]int16{
} }
var yyPact = [...]int16{ var yyPact = [...]int16{
32, 106, 569, 569, 405, 526, -1000, -1000, -1000, 105, 28, 102, 569, 569, 405, 526, -1000, -1000, -1000, 98,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, 277, -1000, 297, -1000, 650, -1000, -1000, -1000, -1000, -1000, 342, -1000, 204, -1000, 650,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, 22, 95, -1000, -1000, 483, -1000, 483, 101, -1000, -1000, 21, 93, -1000, -1000, 483, -1000, 483, 97,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, 167, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 307, -1000, -1000,
281, -1000, -1000, 309, -1000, 23, -1000, -50, -50, -50, 338, -1000, -1000, 225, -1000, 23, -1000, -44, -44, -44,
-50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-50, -50, -50, 48, 174, 336, 95, -56, -1000, 262, -44, -44, -44, 47, 171, 259, 93, -57, -1000, 249,
262, 324, -1000, 631, 103, -1000, 280, -1000, -1000, 274, 249, 324, -1000, 631, 75, -1000, 327, -1000, -1000, 222,
241, -1000, -1000, -1000, 187, -1000, 180, -1000, 159, 483, 130, -1000, -1000, -1000, 298, -1000, 112, -1000, 159, 483,
-1000, -57, -40, -1000, 483, 483, 483, 483, 483, 483, -1000, -58, -48, -1000, 483, 483, 483, 483, 483, 483,
483, 483, 483, 483, 483, 483, 483, 483, 483, -1000, 483, 483, 483, 483, 483, 483, 483, 483, 483, -1000,
165, -1000, -1000, 94, -1000, -1000, -1000, -1000, -1000, -1000, 39, -1000, -1000, 90, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, 40, 40, 269, -1000, -1000, -1000, -1000, 155, -1000, -1000, 36, 36, 229, -1000, -1000, -1000, -1000, 174, -1000,
-1000, 41, -1000, 650, -1000, -1000, 31, -1000, 170, -1000, -1000, 180, -1000, 650, -1000, -1000, 301, -1000, 105, -1000,
-1000, -1000, -1000, -1000, 163, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 44, -1000, -1000, -1000, -1000, -1000,
19, 144, 140, -1000, -1000, -1000, 404, 16, 262, 262, 18, 157, 83, -1000, -1000, -1000, 404, 15, 249, 249,
262, 262, 103, 103, 251, 251, 251, 715, 696, 251, 249, 249, 75, 75, 402, 402, 402, 715, 696, 402,
251, 715, 103, 103, 251, 103, 16, -1000, 24, -1000, 402, 715, 75, 75, 402, 75, 15, -1000, 19, -1000,
-1000, -1000, 265, -1000, 189, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 186, -1000, 155, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
483, -1000, -1000, -1000, -1000, -1000, -1000, 34, 34, 18, 483, -1000, -1000, -1000, -1000, -1000, -1000, 31, 31, 17,
34, 44, 44, 110, 38, -1000, -1000, 285, 267, 260, 31, 37, 37, 206, 34, -1000, -1000, 197, 191, 188,
240, 236, 235, 234, 206, 188, 134, 129, -1000, -1000, 185, 164, 161, 153, 133, 113, 111, 110, -1000, -1000,
-1000, -1000, -1000, -1000, 102, -1000, -1000, -1000, 14, -1000, -1000, -1000, -1000, -1000, 101, -1000, -1000, -1000, 13, -1000,
650, -1000, -1000, -1000, 34, -1000, 12, 9, 482, -1000, 650, -1000, -1000, -1000, 31, -1000, 16, 11, 482, -1000,
-1000, -1000, 51, 81, 40, 40, 40, 97, 97, 51, -1000, -1000, 33, 163, 163, 163, 36, 40, 40, 33,
97, 51, -73, -1000, -1000, -1000, -1000, -1000, 34, 34, 40, 33, -74, -1000, -1000, -1000, -1000, -1000, 31, 31,
-1000, -1000, -1000, 34, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 31, -1000, -1000, -1000, -1000, -1000, -1000,
40, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 163, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, 104, -1000, 33, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 38, -1000, 160, -1000, -1000, -1000, -1000,
} }
var yyPgo = [...]int16{ var yyPgo = [...]int16{
0, 379, 13, 378, 6, 15, 377, 344, 376, 374, 0, 368, 12, 367, 5, 14, 366, 298, 364, 363,
373, 370, 198, 294, 369, 14, 368, 10, 11, 367, 361, 360, 265, 211, 359, 13, 357, 10, 11, 355,
366, 8, 364, 3, 4, 363, 2, 1, 0, 362, 353, 7, 352, 8, 4, 351, 2, 1, 3, 350,
12, 5, 361, 360, 18, 158, 359, 358, 7, 357, 27, 0, 348, 338, 17, 193, 328, 312, 6, 311,
354, 17, 353, 31, 352, 9, 351, 350, 340, 332, 308, 16, 307, 39, 297, 9, 281, 274, 273, 271,
327, 326, 314, 321, 302, 234, 218, 299, 163, 161,
} }
var yyR1 = [...]int8{ var yyR1 = [...]int8{
@ -630,9 +630,9 @@ var yyChk = [...]int16{
-38, -27, 19, -27, 26, -27, -21, -21, 24, 17, -38, -27, 19, -27, 26, -27, -21, -21, 24, 17,
2, 17, 6, 6, 6, 6, 6, 6, 6, 6, 2, 17, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 21, 2, 22, -4, -27, 26, 26, 6, 6, 6, 21, 2, 22, -4, -27, 26, 26,
17, -23, -26, 57, -27, -31, -28, -28, -28, -24, 17, -23, -26, 57, -27, -31, -31, -31, -28, -24,
14, -24, -26, -24, -26, -11, 92, 93, 94, 95, 14, -24, -26, -24, -26, -11, 92, 93, 94, 95,
-27, -27, -27, -25, -28, 24, 21, 2, 21, -28, -27, -27, -27, -25, -31, 24, 21, 2, 21, -31,
} }
var yyDef = [...]int16{ var yyDef = [...]int16{

View file

@ -610,6 +610,9 @@ func lexBuckets(l *Lexer) stateFn {
case isSpace(r): case isSpace(r):
l.emit(SPACE) l.emit(SPACE)
return lexSpace return lexSpace
case r == '-':
l.emit(SUB)
return lexNumber
case isDigit(r): case isDigit(r):
l.backup() l.backup()
return lexNumber return lexNumber

View file

@ -4084,17 +4084,17 @@ func TestParseHistogramSeries(t *testing.T) {
}, },
{ {
name: "all properties used", name: "all properties used",
input: `{} {{schema:1 sum:-0.3 count:3.1 z_bucket:7.1 z_bucket_w:0.05 buckets:[5.1 10 7] offset:-3 n_buckets:[4.1 5] n_offset:-5 counter_reset_hint:gauge}}`, input: `{} {{schema:1 sum:0.3 count:3.1 z_bucket:7.1 z_bucket_w:0.05 buckets:[5.1 10 7] offset:3 n_buckets:[4.1 5] n_offset:5 counter_reset_hint:gauge}}`,
expected: []histogram.FloatHistogram{{ expected: []histogram.FloatHistogram{{
Schema: 1, Schema: 1,
Sum: -0.3, Sum: 0.3,
Count: 3.1, Count: 3.1,
ZeroCount: 7.1, ZeroCount: 7.1,
ZeroThreshold: 0.05, ZeroThreshold: 0.05,
PositiveBuckets: []float64{5.1, 10, 7}, PositiveBuckets: []float64{5.1, 10, 7},
PositiveSpans: []histogram.Span{{Offset: -3, Length: 3}}, PositiveSpans: []histogram.Span{{Offset: 3, Length: 3}},
NegativeBuckets: []float64{4.1, 5}, NegativeBuckets: []float64{4.1, 5},
NegativeSpans: []histogram.Span{{Offset: -5, Length: 2}}, NegativeSpans: []histogram.Span{{Offset: 5, Length: 2}},
CounterResetHint: histogram.GaugeType, CounterResetHint: histogram.GaugeType,
}}, }},
}, },
@ -4114,6 +4114,22 @@ func TestParseHistogramSeries(t *testing.T) {
CounterResetHint: histogram.GaugeType, CounterResetHint: histogram.GaugeType,
}}, }},
}, },
{
name: "all properties used, with negative values where supported",
input: `{} {{schema:1 sum:-0.3 count:-3.1 z_bucket:-7.1 z_bucket_w:0.05 buckets:[-5.1 -10 -7] offset:-3 n_buckets:[-4.1 -5] n_offset:-5 counter_reset_hint:gauge}}`,
expected: []histogram.FloatHistogram{{
Schema: 1,
Sum: -0.3,
Count: -3.1,
ZeroCount: -7.1,
ZeroThreshold: 0.05,
PositiveBuckets: []float64{-5.1, -10, -7},
PositiveSpans: []histogram.Span{{Offset: -3, Length: 3}},
NegativeBuckets: []float64{-4.1, -5},
NegativeSpans: []histogram.Span{{Offset: -5, Length: 2}},
CounterResetHint: histogram.GaugeType,
}},
},
{ {
name: "static series", name: "static series",
input: `{} {{buckets:[5 10 7] schema:1}}x2`, input: `{} {{buckets:[5 10 7] schema:1}}x2`,

View file

@ -752,27 +752,39 @@ eval instant at 10m histogram_sum(scalar(histogram_fraction(-Inf, +Inf, sum(hist
# Apply multiplication and division operator to histogram. # Apply multiplication and division operator to histogram.
load 10m load 10m
histogram_mul_div {{schema:0 count:21 sum:33 z_bucket:3 z_bucket_w:0.001 buckets:[3 3 3] n_buckets:[3 3 3]}}x1 histogram_mul_div {{schema:0 count:30 sum:33 z_bucket:3 z_bucket_w:0.001 buckets:[3 3 3] n_buckets:[6 6 6]}}x1
float_series_3 3+0x1 float_series_3 3+0x1
float_series_0 0+0x1 float_series_0 0+0x1
eval instant at 10m histogram_mul_div*3 eval instant at 10m histogram_mul_div*3
{} {{schema:0 count:63 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[9 9 9]}} {} {{schema:0 count:90 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[18 18 18]}}
eval instant at 10m histogram_mul_div*-1
{} {{schema:0 count:-30 sum:-33 z_bucket:-3 z_bucket_w:0.001 buckets:[-3 -3 -3] n_buckets:[-6 -6 -6]}}
eval instant at 10m -histogram_mul_div
{} {{schema:0 count:-30 sum:-33 z_bucket:-3 z_bucket_w:0.001 buckets:[-3 -3 -3] n_buckets:[-6 -6 -6]}}
eval instant at 10m histogram_mul_div*-3
{} {{schema:0 count:-90 sum:-99 z_bucket:-9 z_bucket_w:0.001 buckets:[-9 -9 -9] n_buckets:[-18 -18 -18]}}
eval instant at 10m 3*histogram_mul_div eval instant at 10m 3*histogram_mul_div
{} {{schema:0 count:63 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[9 9 9]}} {} {{schema:0 count:90 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[18 18 18]}}
eval instant at 10m histogram_mul_div*float_series_3 eval instant at 10m histogram_mul_div*float_series_3
{} {{schema:0 count:63 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[9 9 9]}} {} {{schema:0 count:90 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[18 18 18]}}
eval instant at 10m float_series_3*histogram_mul_div eval instant at 10m float_series_3*histogram_mul_div
{} {{schema:0 count:63 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[9 9 9]}} {} {{schema:0 count:90 sum:99 z_bucket:9 z_bucket_w:0.001 buckets:[9 9 9] n_buckets:[18 18 18]}}
eval instant at 10m histogram_mul_div/3 eval instant at 10m histogram_mul_div/3
{} {{schema:0 count:7 sum:11 z_bucket:1 z_bucket_w:0.001 buckets:[1 1 1] n_buckets:[1 1 1]}} {} {{schema:0 count:10 sum:11 z_bucket:1 z_bucket_w:0.001 buckets:[1 1 1] n_buckets:[2 2 2]}}
eval instant at 10m histogram_mul_div/-3
{} {{schema:0 count:-10 sum:-11 z_bucket:-1 z_bucket_w:0.001 buckets:[-1 -1 -1] n_buckets:[-2 -2 -2]}}
eval instant at 10m histogram_mul_div/float_series_3 eval instant at 10m histogram_mul_div/float_series_3
{} {{schema:0 count:7 sum:11 z_bucket:1 z_bucket_w:0.001 buckets:[1 1 1] n_buckets:[1 1 1]}} {} {{schema:0 count:10 sum:11 z_bucket:1 z_bucket_w:0.001 buckets:[1 1 1] n_buckets:[2 2 2]}}
eval instant at 10m histogram_mul_div*0 eval instant at 10m histogram_mul_div*0
{} {{schema:0 count:0 sum:0 z_bucket:0 z_bucket_w:0.001 buckets:[0 0 0] n_buckets:[0 0 0]}} {} {{schema:0 count:0 sum:0 z_bucket:0 z_bucket_w:0.001 buckets:[0 0 0] n_buckets:[0 0 0]}}

View file

@ -524,6 +524,7 @@ func (sp *scrapePool) sync(targets []*Target) {
interval: interval, interval: interval,
timeout: timeout, timeout: timeout,
scrapeClassicHistograms: scrapeClassicHistograms, scrapeClassicHistograms: scrapeClassicHistograms,
validationScheme: validationScheme,
}) })
if err != nil { if err != nil {
l.setForcedError(err) l.setForcedError(err)

View file

@ -34,6 +34,7 @@ import (
"github.com/go-kit/log" "github.com/go-kit/log"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/grafana/regexp"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" prom_testutil "github.com/prometheus/client_golang/prometheus/testutil"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
@ -2380,8 +2381,11 @@ func TestTargetScraperScrapeOK(t *testing.T) {
expectedTimeout = "1.5" expectedTimeout = "1.5"
) )
var protobufParsing bool var (
var allowUTF8 bool protobufParsing bool
allowUTF8 bool
qValuePattern = regexp.MustCompile(`q=([0-9]+(\.\d+)?)`)
)
server := httptest.NewServer( server := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -2394,6 +2398,17 @@ func TestTargetScraperScrapeOK(t *testing.T) {
"Expected Accept header to prefer application/vnd.google.protobuf.") "Expected Accept header to prefer application/vnd.google.protobuf.")
} }
contentTypes := strings.Split(accept, ",")
for _, ct := range contentTypes {
match := qValuePattern.FindStringSubmatch(ct)
require.Len(t, match, 3)
qValue, err := strconv.ParseFloat(match[1], 64)
require.NoError(t, err, "Error parsing q value")
require.GreaterOrEqual(t, qValue, float64(0))
require.LessOrEqual(t, qValue, float64(1))
require.LessOrEqual(t, len(strings.Split(match[1], ".")[1]), 3, "q value should have at most 3 decimal places")
}
timeout := r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds") timeout := r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds")
require.Equal(t, expectedTimeout, timeout, "Expected scrape timeout header.") require.Equal(t, expectedTimeout, timeout, "Expected scrape timeout header.")
@ -3115,18 +3130,7 @@ func TestScrapeReportLimit(t *testing.T) {
ScrapeTimeout: model.Duration(100 * time.Millisecond), ScrapeTimeout: model.Duration(100 * time.Millisecond),
} }
var ( ts, scrapedTwice := newScrapableServer("metric_a 44\nmetric_b 44\nmetric_c 44\nmetric_d 44\n")
scrapes int
scrapedTwice = make(chan bool)
)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "metric_a 44\nmetric_b 44\nmetric_c 44\nmetric_d 44\n")
scrapes++
if scrapes == 2 {
close(scrapedTwice)
}
}))
defer ts.Close() defer ts.Close()
sp, err := newScrapePool(cfg, s, 0, nil, nil, &Options{}, newTestScrapeMetrics(t)) sp, err := newScrapePool(cfg, s, 0, nil, nil, &Options{}, newTestScrapeMetrics(t))
@ -3169,6 +3173,52 @@ func TestScrapeReportLimit(t *testing.T) {
require.True(t, found) require.True(t, found)
} }
func TestScrapeUTF8(t *testing.T) {
s := teststorage.New(t)
defer s.Close()
model.NameValidationScheme = model.UTF8Validation
t.Cleanup(func() { model.NameValidationScheme = model.LegacyValidation })
cfg := &config.ScrapeConfig{
JobName: "test",
Scheme: "http",
ScrapeInterval: model.Duration(100 * time.Millisecond),
ScrapeTimeout: model.Duration(100 * time.Millisecond),
MetricNameValidationScheme: config.UTF8ValidationConfig,
}
ts, scrapedTwice := newScrapableServer("{\"with.dots\"} 42\n")
defer ts.Close()
sp, err := newScrapePool(cfg, s, 0, nil, nil, &Options{}, newTestScrapeMetrics(t))
require.NoError(t, err)
defer sp.stop()
testURL, err := url.Parse(ts.URL)
require.NoError(t, err)
sp.Sync([]*targetgroup.Group{
{
Targets: []model.LabelSet{{model.AddressLabel: model.LabelValue(testURL.Host)}},
},
})
select {
case <-time.After(5 * time.Second):
t.Fatalf("target was not scraped twice")
case <-scrapedTwice:
// If the target has been scraped twice, report samples from the first
// scrape have been inserted in the database.
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
q, err := s.Querier(time.Time{}.UnixNano(), time.Now().UnixNano())
require.NoError(t, err)
defer q.Close()
series := q.Select(ctx, false, nil, labels.MustNewMatcher(labels.MatchRegexp, "__name__", "with.dots"))
require.True(t, series.Next(), "series not found in tsdb")
}
func TestScrapeLoopLabelLimit(t *testing.T) { func TestScrapeLoopLabelLimit(t *testing.T) {
tests := []struct { tests := []struct {
title string title string
@ -3365,16 +3415,7 @@ test_summary_count 199
// The expected "quantile" values do not have the trailing ".0". // The expected "quantile" values do not have the trailing ".0".
expectedQuantileValues := []string{"0.5", "0.9", "0.95", "0.99", "1"} expectedQuantileValues := []string{"0.5", "0.9", "0.95", "0.99", "1"}
scrapeCount := 0 ts, scrapedTwice := newScrapableServer(metricsText)
scraped := make(chan bool)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, metricsText)
scrapeCount++
if scrapeCount > 2 {
close(scraped)
}
}))
defer ts.Close() defer ts.Close()
sp, err := newScrapePool(config, simpleStorage, 0, nil, nil, &Options{}, newTestScrapeMetrics(t)) sp, err := newScrapePool(config, simpleStorage, 0, nil, nil, &Options{}, newTestScrapeMetrics(t))
@ -3393,7 +3434,7 @@ test_summary_count 199
select { select {
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
t.Fatalf("target was not scraped") t.Fatalf("target was not scraped")
case <-scraped: case <-scrapedTwice:
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@ -4001,3 +4042,16 @@ func TestTargetScrapeConfigWithLabels(t *testing.T) {
}) })
} }
} }
func newScrapableServer(scrapeText string) (s *httptest.Server, scrapedTwice chan bool) {
var scrapes int
scrapedTwice = make(chan bool)
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, scrapeText)
scrapes++
if scrapes == 2 {
close(scrapedTwice)
}
})), scrapedTwice
}

View file

@ -7,19 +7,21 @@
<!-- <!--
Placeholders replaced by Prometheus during serving: Placeholders replaced by Prometheus during serving:
- GLOBAL_CONSOLES_LINK is replaced and set to the consoles link if it exists. - CONSOLES_LINK_PLACEHOLDER is replaced and set to the consoles link if it exists.
It will render a "Consoles" link in the navbar when it is non-empty. It will render a "Consoles" link in the navbar when it is non-empty.
- PROMETHEUS_AGENT_MODE is replaced by a boolean indicating if Prometheus is running in agent mode. - AGENT_MODE_PLACEHOLDER is replaced by a boolean indicating if Prometheus is running in agent mode.
It true, it will disable querying capacities in the UI and generally adapt the UI to the agent mode. It true, it will disable querying capacities in the UI and generally adapt the UI to the agent mode.
It has to be represented as a string, because booleans can be mangled to !1 in production builds. It has to be represented as a string, because booleans can be mangled to !1 in production builds.
- PROMETHEUS_READY is replaced by a boolean indicating whether Prometheus was ready at the time the - READY_PLACEHOLDER is replaced by a boolean indicating whether Prometheus was ready at the time the
web app was served. It has to be represented as a string, because booleans can be mangled to !1 in web app was served. It has to be represented as a string, because booleans can be mangled to !1 in
production builds. production builds.
- LOOKBACKDELTA_PLACEHOLDER is replaced by the default lookback delta duration used for queries.
--> -->
<script> <script>
const GLOBAL_CONSOLES_LINK='CONSOLES_LINK_PLACEHOLDER'; const GLOBAL_CONSOLES_LINK='CONSOLES_LINK_PLACEHOLDER';
const GLOBAL_AGENT_MODE='AGENT_MODE_PLACEHOLDER'; const GLOBAL_AGENT_MODE='AGENT_MODE_PLACEHOLDER';
const GLOBAL_READY='READY_PLACEHOLDER'; const GLOBAL_READY='READY_PLACEHOLDER';
const GLOBAL_LOOKBACKDELTA='LOOKBACKDELTA_PLACEHOLDER';
</script> </script>
<!-- <!--

View file

@ -6,6 +6,7 @@ import classes from "./App.module.css";
import PrometheusLogo from "./images/prometheus-logo.svg"; import PrometheusLogo from "./images/prometheus-logo.svg";
import { import {
ActionIcon,
AppShell, AppShell,
Box, Box,
Burger, Burger,
@ -22,6 +23,7 @@ import { useDisclosure } from "@mantine/hooks";
import { import {
IconBell, IconBell,
IconBellFilled, IconBellFilled,
IconBook,
IconChevronDown, IconChevronDown,
IconChevronRight, IconChevronRight,
IconCloudDataConnection, IconCloudDataConnection,
@ -109,13 +111,6 @@ const monitoringStatusPages = [
element: <ServiceDiscoveryPage />, element: <ServiceDiscoveryPage />,
inAgentMode: true, inAgentMode: true,
}, },
{
title: "Alertmanager discovery",
path: "/discovered-alertmanagers",
icon: <IconBell style={navIconStyle} />,
element: <AlertmanagerDiscoveryPage />,
inAgentMode: false,
},
]; ];
const serverStatusPages = [ const serverStatusPages = [
@ -147,6 +142,13 @@ const serverStatusPages = [
element: <ConfigPage />, element: <ConfigPage />,
inAgentMode: true, inAgentMode: true,
}, },
{
title: "Alertmanager discovery",
path: "/alertmanager-discovery",
icon: <IconBell style={navIconStyle} />,
element: <AlertmanagerDiscoveryPage />,
inAgentMode: false,
},
]; ];
const allStatusPages = [...monitoringStatusPages, ...serverStatusPages]; const allStatusPages = [...monitoringStatusPages, ...serverStatusPages];
@ -306,17 +308,24 @@ function App() {
))} ))}
</Menu.Dropdown> </Menu.Dropdown>
</Menu> </Menu>
</>
);
{/* <Button const navActionIcons = (
<>
<ThemeSelector />
<SettingsMenu />
<ActionIcon
component="a" component="a"
href="https://prometheus.io/docs/prometheus/latest/getting_started/" href="https://prometheus.io/docs/prometheus/latest/getting_started/"
className={classes.link}
leftSection={<IconHelp style={navIconStyle} />}
target="_blank" target="_blank"
px={navLinkXPadding} color="gray"
title="Documentation"
aria-label="Documentation"
size={32}
> >
Help <IconBook size={20} />
</Button> */} </ActionIcon>
</> </>
); );
@ -359,9 +368,8 @@ function App() {
{navLinks} {navLinks}
</Group> </Group>
</Group> </Group>
<Group visibleFrom="xs" wrap="nowrap"> <Group visibleFrom="xs" wrap="nowrap" gap="xs">
<ThemeSelector /> {navActionIcons}
<SettingsMenu />
</Group> </Group>
</Group> </Group>
<Burger <Burger
@ -377,8 +385,7 @@ function App() {
<AppShell.Navbar py="md" px={4} bg="rgb(65, 73, 81)" c="#fff"> <AppShell.Navbar py="md" px={4} bg="rgb(65, 73, 81)" c="#fff">
{navLinks} {navLinks}
<Group mt="md" hiddenFrom="xs" justify="center"> <Group mt="md" hiddenFrom="xs" justify="center">
<ThemeSelector /> {navActionIcons}
<SettingsMenu />
</Group> </Group>
</AppShell.Navbar> </AppShell.Navbar>

View file

@ -18,7 +18,12 @@ const SettingsMenu: FC = () => {
return ( return (
<Popover position="bottom" withArrow shadow="md"> <Popover position="bottom" withArrow shadow="md">
<Popover.Target> <Popover.Target>
<ActionIcon color="gray" aria-label="Settings" size={32}> <ActionIcon
color="gray"
title="Settings"
aria-label="Settings"
size={32}
>
<IconSettings size={20} /> <IconSettings size={20} />
</ActionIcon> </ActionIcon>
</Popover.Target> </Popover.Target>

View file

@ -45,9 +45,37 @@ const describeAggregationType = (
</> </>
); );
case "bottomk": case "bottomk":
return "returns the bottom K series by value"; if (param === null || param.type !== "numberLiteral") {
return (
<>
returns the bottom{" "}
<span className="promql-code promql-number">K</span> series by value
</>
);
}
return (
<>
returns the bottom{" "}
<span className="promql-code promql-number">{param.val}</span> series
by value
</>
);
case "topk": case "topk":
return "returns the top K series by value"; if (param === null || param.type !== "numberLiteral") {
return (
<>
returns the top <span className="promql-code promql-number">K</span>{" "}
series by value
</>
);
}
return (
<>
returns the top{" "}
<span className="promql-code promql-number">{param.val}</span> series
by value
</>
);
case "quantile": case "quantile":
if (param === null) { if (param === null) {
throw new Error( throw new Error(
@ -62,9 +90,31 @@ const describeAggregationType = (
return "calculates a quantile over the sample values of the input series"; return "calculates a quantile over the sample values of the input series";
case "limitk": case "limitk":
return "limits the output to K series"; if (param === null || param.type !== "numberLiteral") {
return (
<>
limits the output to{" "}
<span className="promql-code promql-number">K</span> series
</>
);
}
return (
<>
limits the output to{" "}
<span className="promql-code promql-number">{param.val}</span> series
</>
);
case "limit_ratio": case "limit_ratio":
return "limits the output to a ratio of the input series"; if (param === null || param.type !== "numberLiteral") {
return "limits the output to a ratio of the input series";
}
return (
<>
limits the output to a ratio of{" "}
<span className="promql-code promql-number">{param.val}</span> (
{parsePrometheusFloat(param.val) * 100}%) of the input series
</>
);
default: default:
throw new Error(`invalid aggregation type ${aggrType}`); throw new Error(`invalid aggregation type ${aggrType}`);
} }

View file

@ -11,6 +11,7 @@ import { useSuspenseAPIQuery } from "../../../api/api";
import { Card, Text, Divider, List } from "@mantine/core"; import { Card, Text, Divider, List } from "@mantine/core";
import { MetadataResult } from "../../../api/responseTypes/metadata"; import { MetadataResult } from "../../../api/responseTypes/metadata";
import { formatPrometheusDuration } from "../../../lib/formatTime"; import { formatPrometheusDuration } from "../../../lib/formatTime";
import { useSettings } from "../../../state/settingsSlice";
interface SelectorExplainViewProps { interface SelectorExplainViewProps {
node: VectorSelector | MatrixSelector; node: VectorSelector | MatrixSelector;
@ -126,6 +127,7 @@ const matchingCriteriaList = (
const SelectorExplainView: FC<SelectorExplainViewProps> = ({ node }) => { const SelectorExplainView: FC<SelectorExplainViewProps> = ({ node }) => {
const baseMetricName = node.name.replace(/(_count|_sum|_bucket)$/, ""); const baseMetricName = node.name.replace(/(_count|_sum|_bucket)$/, "");
const { lookbackDelta } = useSettings();
const { data: metricMeta } = useSuspenseAPIQuery<MetadataResult>({ const { data: metricMeta } = useSuspenseAPIQuery<MetadataResult>({
path: `/metadata`, path: `/metadata`,
params: { params: {
@ -159,7 +161,7 @@ const SelectorExplainView: FC<SelectorExplainViewProps> = ({ node }) => {
{node.type === nodeType.vectorSelector ? ( {node.type === nodeType.vectorSelector ? (
<> <>
This node selects the latest (non-stale) sample value within the This node selects the latest (non-stale) sample value within the
last <span className="promql-code promql-duration">5m</span> last <span className="promql-code promql-duration">{lookbackDelta}</span>
</> </>
) : ( ) : (
<> <>
@ -208,7 +210,7 @@ const SelectorExplainView: FC<SelectorExplainViewProps> = ({ node }) => {
If a series has no values in the last{" "} If a series has no values in the last{" "}
<span className="promql-code promql-duration"> <span className="promql-code promql-duration">
{node.type === nodeType.vectorSelector {node.type === nodeType.vectorSelector
? "5m" ? lookbackDelta
: formatPrometheusDuration(node.range)} : formatPrometheusDuration(node.range)}
</span> </span>
{node.offset > 0 && ( {node.offset > 0 && (

View file

@ -4,6 +4,7 @@ import { initializeFromLocalStorage } from "./initializeFromLocalStorage";
interface Settings { interface Settings {
consolesLink: string | null; consolesLink: string | null;
lookbackDelta: string,
agentMode: boolean; agentMode: boolean;
ready: boolean; ready: boolean;
pathPrefix: string; pathPrefix: string;
@ -19,6 +20,7 @@ interface Settings {
declare const GLOBAL_CONSOLES_LINK: string; declare const GLOBAL_CONSOLES_LINK: string;
declare const GLOBAL_AGENT_MODE: string; declare const GLOBAL_AGENT_MODE: string;
declare const GLOBAL_READY: string; declare const GLOBAL_READY: string;
declare const GLOBAL_LOOKBACKDELTA: string;
export const localStorageKeyUseLocalTime = "settings.useLocalTime"; export const localStorageKeyUseLocalTime = "settings.useLocalTime";
export const localStorageKeyEnableQueryHistory = "settings.enableQueryHistory"; export const localStorageKeyEnableQueryHistory = "settings.enableQueryHistory";
@ -37,6 +39,11 @@ export const initialState: Settings = {
: GLOBAL_CONSOLES_LINK, : GLOBAL_CONSOLES_LINK,
agentMode: GLOBAL_AGENT_MODE === "true", agentMode: GLOBAL_AGENT_MODE === "true",
ready: GLOBAL_READY === "true", ready: GLOBAL_READY === "true",
lookbackDelta:
GLOBAL_LOOKBACKDELTA === "LOOKBACKDELTA_PLACEHOLDER" ||
GLOBAL_LOOKBACKDELTA === null
? ""
: GLOBAL_LOOKBACKDELTA,
pathPrefix: "", pathPrefix: "",
useLocalTime: initializeFromLocalStorage<boolean>( useLocalTime: initializeFromLocalStorage<boolean>(
localStorageKeyUseLocalTime, localStorageKeyUseLocalTime,

View file

@ -2971,11 +2971,10 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.5.2", "version": "22.5.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
"integrity": "sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg==", "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.19.2" "undici-types": "~6.19.2"
} }

View file

@ -444,6 +444,7 @@ func New(logger log.Logger, o *Options) *Handler {
replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("TITLE_PLACEHOLDER"), []byte(h.options.PageTitle)) replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("TITLE_PLACEHOLDER"), []byte(h.options.PageTitle))
replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("AGENT_MODE_PLACEHOLDER"), []byte(strconv.FormatBool(h.options.IsAgent))) replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("AGENT_MODE_PLACEHOLDER"), []byte(strconv.FormatBool(h.options.IsAgent)))
replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("READY_PLACEHOLDER"), []byte(strconv.FormatBool(h.isReady()))) replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("READY_PLACEHOLDER"), []byte(strconv.FormatBool(h.isReady())))
replacedIdx = bytes.ReplaceAll(replacedIdx, []byte("LOOKBACKDELTA_PLACEHOLDER"), []byte(model.Duration(h.options.LookbackDelta).String()))
w.Write(replacedIdx) w.Write(replacedIdx)
} }