From f71ec8d5d5adf5dd58d63ccf0f34747b33bab108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Mon, 17 Mar 2025 14:07:07 +0100 Subject: [PATCH 1/6] fix(scrape): skip native histogram series if ingestion is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to validate, track, add sample, add exemplar if series isn't going to be ingested. Basically this is the same as if this series was dropped by relabelling. Fixes #16217 Signed-off-by: György Krajcsovits --- scrape/scrape.go | 6 +- scrape/scrape_test.go | 176 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 178 insertions(+), 4 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index 518103d345..14c442fc25 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -1700,7 +1700,7 @@ loop: t = *parsedTimestamp } - if sl.cache.getDropped(met) { + if sl.cache.getDropped(met) || isHistogram && !sl.enableNativeHistogramIngestion { continue } ce, seriesCached, seriesAlreadyScraped := sl.cache.get(met) @@ -1748,7 +1748,7 @@ loop: } else { if sl.enableCTZeroIngestion { if ctMs := p.CreatedTimestamp(); ctMs != 0 { - if isHistogram && sl.enableNativeHistogramIngestion { + if isHistogram { if h != nil { ref, err = app.AppendHistogramCTZeroSample(ref, lset, t, ctMs, h, nil) } else { @@ -1765,7 +1765,7 @@ loop: } } - if isHistogram && sl.enableNativeHistogramIngestion { + if isHistogram { if h != nil { ref, err = app.AppendHistogram(ref, lset, t, h, nil) } else { diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index 9725d688a5..e38a3fc4a8 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -2395,7 +2395,7 @@ metric_total{n="2"} 2 # {t="2"} 2.0 20000 }, }, { - title: "Native histogram with three exemplars", + title: "Native histogram with three exemplars from classic buckets", enableNativeHistogramsIngestion: true, scrapeText: `name: "test_histogram" @@ -2644,6 +2644,180 @@ metric: < {Labels: labels.FromStrings("dummyID", "58215"), Value: -0.00019, Ts: 1625851055146, HasTs: true}, }, }, + { + title: "Native histogram with exemplars and no classic buckets", + contentType: "application/vnd.google.protobuf", + enableNativeHistogramsIngestion: true, + scrapeText: `name: "test_histogram" +help: "Test histogram." +type: HISTOGRAM +metric: < + histogram: < + sample_count: 175 + sample_sum: 0.0008280461746287094 + schema: 3 + zero_threshold: 2.938735877055719e-39 + zero_count: 2 + negative_span: < + offset: -162 + length: 1 + > + negative_span: < + offset: 23 + length: 4 + > + negative_delta: 1 + negative_delta: 3 + negative_delta: -2 + negative_delta: -1 + negative_delta: 1 + positive_span: < + offset: -161 + length: 1 + > + positive_span: < + offset: 8 + length: 3 + > + positive_delta: 1 + positive_delta: 2 + positive_delta: -1 + positive_delta: -1 + exemplars: < + label: < + name: "dummyID" + value: "59732" + > + value: -0.00039 + timestamp: < + seconds: 1625851155 + nanos: 146848499 + > + > + exemplars: < + label: < + name: "dummyID" + value: "58242" + > + value: -0.00019 + timestamp: < + seconds: 1625851055 + nanos: 146848599 + > + > + exemplars: < + label: < + name: "dummyID" + value: "5617" + > + value: -0.00029 + > + > + timestamp_ms: 1234568 +> + +`, + histograms: []histogramSample{{ + t: 1234568, + metric: labels.FromStrings("__name__", "test_histogram"), + h: &histogram.Histogram{ + Count: 175, + ZeroCount: 2, + Sum: 0.0008280461746287094, + ZeroThreshold: 2.938735877055719e-39, + Schema: 3, + PositiveSpans: []histogram.Span{ + {Offset: -161, Length: 1}, + {Offset: 8, Length: 3}, + }, + NegativeSpans: []histogram.Span{ + {Offset: -162, Length: 1}, + {Offset: 23, Length: 4}, + }, + PositiveBuckets: []int64{1, 2, -1, -1}, + NegativeBuckets: []int64{1, 3, -2, -1, 1}, + }, + }}, + exemplars: []exemplar.Exemplar{ + // Exemplars with missing timestamps are dropped for native histograms. + {Labels: labels.FromStrings("dummyID", "58242"), Value: -0.00019, Ts: 1625851055146, HasTs: true}, + {Labels: labels.FromStrings("dummyID", "59732"), Value: -0.00039, Ts: 1625851155146, HasTs: true}, + }, + }, + { + title: "Native histogram with exemplars but ingestion disabled", + contentType: "application/vnd.google.protobuf", + enableNativeHistogramsIngestion: false, + scrapeText: `name: "test_histogram" +help: "Test histogram." +type: HISTOGRAM +metric: < + histogram: < + sample_count: 175 + sample_sum: 0.0008280461746287094 + schema: 3 + zero_threshold: 2.938735877055719e-39 + zero_count: 2 + negative_span: < + offset: -162 + length: 1 + > + negative_span: < + offset: 23 + length: 4 + > + negative_delta: 1 + negative_delta: 3 + negative_delta: -2 + negative_delta: -1 + negative_delta: 1 + positive_span: < + offset: -161 + length: 1 + > + positive_span: < + offset: 8 + length: 3 + > + positive_delta: 1 + positive_delta: 2 + positive_delta: -1 + positive_delta: -1 + exemplars: < + label: < + name: "dummyID" + value: "59732" + > + value: -0.00039 + timestamp: < + seconds: 1625851155 + nanos: 146848499 + > + > + exemplars: < + label: < + name: "dummyID" + value: "58242" + > + value: -0.00019 + timestamp: < + seconds: 1625851055 + nanos: 146848599 + > + > + exemplars: < + label: < + name: "dummyID" + value: "5617" + > + value: -0.00029 + > + > + timestamp_ms: 1234568 +> + +`, + }, } for _, test := range tests { From b7fc01df0e42af214a2758d4e4c6cd95ebb94070 Mon Sep 17 00:00:00 2001 From: Mustafain Ali Khan Date: Thu, 13 Mar 2025 16:18:24 -0700 Subject: [PATCH 2/6] Fix rules UI to display correct value for 'keepFiringFor' Signed-off-by: Mustafain Ali Khan --- web/ui/mantine-ui/src/components/RuleDefinition.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ui/mantine-ui/src/components/RuleDefinition.tsx b/web/ui/mantine-ui/src/components/RuleDefinition.tsx index f3c4c88485..f428df46a8 100644 --- a/web/ui/mantine-ui/src/components/RuleDefinition.tsx +++ b/web/ui/mantine-ui/src/components/RuleDefinition.tsx @@ -85,7 +85,7 @@ const RuleDefinition: FC<{ rule: Rule }> = ({ rule }) => { styles={{ label: { textTransform: "none" } }} leftSection={} > - keep_firing_for: {formatPrometheusDuration(rule.duration * 1000)} + keep_firing_for: {formatPrometheusDuration(rule.keepFiringFor * 1000)} )} From a2aeb813afd45018d1de9569f90453940a0d918e Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Fri, 14 Mar 2025 01:06:17 +1100 Subject: [PATCH 3/6] promql: return NaN from `irate()` if second-last sample is NaN (#16199) promql: return NaN from `irate()` if either of last two samples is NaN Signed-off-by: Charles Korn --------- Signed-off-by: Charles Korn --- promql/functions.go | 5 +++-- promql/promqltest/testdata/functions.test | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/promql/functions.go b/promql/functions.go index 3f977af56a..3c79684b0f 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -367,10 +367,11 @@ func instantValue(vals []parser.Value, args parser.Expressions, out Vector, isRa } switch { case ss[1].H == nil && ss[0].H == nil: - if !isRate || ss[1].F >= ss[0].F { - // Gauge or counter without reset. + if !isRate || !(ss[1].F < ss[0].F) { + // Gauge, or counter without reset, or counter with NaN value. resultSample.F = ss[1].F - ss[0].F } + // In case of a counter reset, we leave resultSample at // its current value, which is already ss[1]. case ss[1].H != nil && ss[0].H != nil: diff --git a/promql/promqltest/testdata/functions.test b/promql/promqltest/testdata/functions.test index 04d844bef9..fafe2dda40 100644 --- a/promql/promqltest/testdata/functions.test +++ b/promql/promqltest/testdata/functions.test @@ -218,6 +218,7 @@ clear load 5m http_requests_total{path="/foo"} 0+10x10 http_requests_total{path="/bar"} 0+10x5 0+10x5 + http_requests_nan{} 1 NaN NaN 5 11 http_requests_histogram{path="/a"} {{sum:2 count:2}}+{{sum:3 count:3}}x5 http_requests_histogram{path="/b"} 0 0 {{sum:1 count:1}} {{sum:4 count:4}} http_requests_histogram{path="/c"} 0 0 {{sum:1 count:1}} {{sum:4 count:4 counter_reset_hint:gauge}} @@ -235,6 +236,9 @@ eval instant at 30m irate(http_requests_total[50m]) {path="/foo"} .03333333333333333333 {path="/bar"} 0 +eval range from 0 to 20m step 5m irate(http_requests_nan[15m1s]) + {} _ NaN NaN NaN 0.02 + eval instant at 20m irate(http_requests_histogram{path="/a"}[20m]) {path="/a"} {{sum:0.01 count:0.01 counter_reset_hint:gauge}} @@ -288,6 +292,7 @@ clear load 5m http_requests{path="/foo"} 0 50 100 150 http_requests{path="/bar"} 0 50 100 50 + http_requests_nan{} 1 NaN NaN 5 11 http_requests_histogram{path="/a"} {{sum:2 count:2 counter_reset_hint:gauge}}+{{sum:1 count:3 counter_reset_hint:gauge}}x5 http_requests_histogram{path="/b"} 0 0 {{sum:1 count:1 counter_reset_hint:gauge}} {{sum:2 count:2 counter_reset_hint:gauge}} http_requests_histogram{path="/c"} 0 0 {{sum:1 count:1}} {{sum:2 count:2 counter_reset_hint:gauge}} @@ -300,6 +305,9 @@ eval instant at 20m idelta(http_requests[20m]) {path="/foo"} 50 {path="/bar"} -50 +eval range from 0 to 20m step 5m idelta(http_requests_nan[15m1s]) + {} _ NaN NaN NaN 6 + eval instant at 20m idelta(http_requests_histogram{path="/a"}[20m]) {path="/a"} {{sum:1 count:3 counter_reset_hint:gauge}} From a82bb771780b03d39d7919841f25e2d9faa764e6 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 11 Mar 2025 10:49:51 +0000 Subject: [PATCH 4/6] [PERF] Remote-write: re-use memory to read WAL data (#16197) The `:=` causes new variables to be created, which means the outer slice stays at nil, and new memory is allocated every time round the loop. Extracted from https://github.com/prometheus/prometheus/pull/16182 Credit to @bwplotka. Signed-off-by: Bryan Boreham --- tsdb/wlog/watcher.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index ca74a9ceaf..f171a8bdc1 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -491,12 +491,13 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { metadata []record.RefMetadata ) for r.Next() && !isClosed(w.quit) { + var err error rec := r.Record() w.recordsReadMetric.WithLabelValues(dec.Type(rec).String()).Inc() switch dec.Type(rec) { case record.Series: - series, err := dec.Series(rec, series[:0]) + series, err = dec.Series(rec, series[:0]) if err != nil { w.recordDecodeFailsMetric.Inc() return err @@ -509,7 +510,7 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { if !tail { break } - samples, err := dec.Samples(rec, samples[:0]) + samples, err = dec.Samples(rec, samples[:0]) if err != nil { w.recordDecodeFailsMetric.Inc() return err @@ -539,7 +540,7 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { if !tail { break } - exemplars, err := dec.Exemplars(rec, exemplars[:0]) + exemplars, err = dec.Exemplars(rec, exemplars[:0]) if err != nil { w.recordDecodeFailsMetric.Inc() return err @@ -554,7 +555,7 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { if !tail { break } - histograms, err := dec.HistogramSamples(rec, histograms[:0]) + histograms, err = dec.HistogramSamples(rec, histograms[:0]) if err != nil { w.recordDecodeFailsMetric.Inc() return err @@ -582,7 +583,7 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { if !tail { break } - floatHistograms, err := dec.FloatHistogramSamples(rec, floatHistograms[:0]) + floatHistograms, err = dec.FloatHistogramSamples(rec, floatHistograms[:0]) if err != nil { w.recordDecodeFailsMetric.Inc() return err @@ -606,12 +607,12 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { if !w.sendMetadata { break } - meta, err := dec.Metadata(rec, metadata[:0]) + metadata, err = dec.Metadata(rec, metadata[:0]) if err != nil { w.recordDecodeFailsMetric.Inc() return err } - w.writer.StoreMetadata(meta) + w.writer.StoreMetadata(metadata) case record.Unknown: // Could be corruption, or reading from a WAL from a newer Prometheus. From fb880081d8abda65641b107a69659810188b7cbb Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Wed, 12 Mar 2025 12:22:33 +0100 Subject: [PATCH 5/6] golangci: Disable nolintlint due to known issues. (#16204) Fixes: https://github.com/prometheus/prometheus/issues/16203 Details: https://github.com/golangci/golangci-lint/issues/3228 Signed-off-by: bwplotka --- .golangci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 2dfe8e5f0c..8548774b76 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -17,7 +17,8 @@ linters: - loggercheck - misspell - nilnesserr - - nolintlint + # TODO(bwplotka): Enable once https://github.com/golangci/golangci-lint/issues/3228 is fixed. + # - nolintlint - perfsprint - predeclared - revive From 0ffad224772290ec553561861149011de04f3401 Mon Sep 17 00:00:00 2001 From: machine424 Date: Wed, 26 Mar 2025 15:15:10 +0100 Subject: [PATCH 6/6] Prepare release 3.3.0-rc.1 Signed-off-by: machine424 --- CHANGELOG.md | 7 +++++++ VERSION | 2 +- web/ui/mantine-ui/package.json | 4 ++-- web/ui/module/codemirror-promql/package.json | 4 ++-- web/ui/module/lezer-promql/package.json | 2 +- web/ui/package-lock.json | 14 +++++++------- web/ui/package.json | 2 +- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f0c8d91de..3fee14551d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## unreleased +## 3.3.0-rc.1 / 2025-04-02 + +* [BUGFIX] Remote-Write: Reduce memory footprint during WAL replay. #16197 +* [BUGFIX] Scraping: Skip native histograms series when ingestion is disabled. #16218 +* [BUGFIX] UI: Display the correct value of Alerting rules' `keep_firing_for`. #16211 +* [BUGFIX] PromQL: return NaN from `irate()` if second-last sample is NaN. #16199 #15853 + ## 3.3.0-rc.0 / 2025-03-11 * [FEATURE] PromQL: Implement `idelta()` and `irate()` for native histograms. #15853 diff --git a/VERSION b/VERSION index be789e37d0..0726a21ca1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3.0-rc.0 +3.3.0-rc.1 diff --git a/web/ui/mantine-ui/package.json b/web/ui/mantine-ui/package.json index 0eda852213..cb7f886433 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.303.0-rc.0", + "version": "0.303.0-rc.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.303.0-rc.0", + "@prometheus-io/codemirror-promql": "0.303.0-rc.1", "@reduxjs/toolkit": "^2.5.0", "@tabler/icons-react": "^3.28.1", "@tanstack/react-query": "^5.67.1", diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index 8ccdb93341..dc01dd0014 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.303.0-rc.0", + "version": "0.303.0-rc.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.303.0-rc.0", + "@prometheus-io/lezer-promql": "0.303.0-rc.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 35b6be9b75..cc38148f01 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.303.0-rc.0", + "version": "0.303.0-rc.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 b040d39895..4bf698586f 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.303.0-rc.0", + "version": "0.303.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.303.0-rc.0", + "version": "0.303.0-rc.1", "workspaces": [ "mantine-ui", "module/*" @@ -24,7 +24,7 @@ }, "mantine-ui": { "name": "@prometheus-io/mantine-ui", - "version": "0.303.0-rc.0", + "version": "0.303.0-rc.1", "dependencies": { "@codemirror/autocomplete": "^6.18.4", "@codemirror/language": "^6.10.8", @@ -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.303.0-rc.0", + "@prometheus-io/codemirror-promql": "0.303.0-rc.1", "@reduxjs/toolkit": "^2.5.0", "@tabler/icons-react": "^3.28.1", "@tanstack/react-query": "^5.67.1", @@ -156,10 +156,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.303.0-rc.0", + "version": "0.303.0-rc.1", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.303.0-rc.0", + "@prometheus-io/lezer-promql": "0.303.0-rc.1", "lru-cache": "^11.0.2" }, "devDependencies": { @@ -189,7 +189,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.303.0-rc.0", + "version": "0.303.0-rc.1", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.7.2", diff --git a/web/ui/package.json b/web/ui/package.json index aaacd5ef9d..ff42f000d1 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.303.0-rc.0", + "version": "0.303.0-rc.1", "private": true, "scripts": { "build": "bash build_ui.sh --all",