From 39d008f94fe44b3b2efe2ac9bbd2a1198e67cdf8 Mon Sep 17 00:00:00 2001 From: "m.nabokikh" Date: Tue, 11 Jul 2023 23:44:23 +0200 Subject: [PATCH 001/253] Route different alerts to different alertmanagers Signed-off-by: m.nabokikh --- config/config.go | 8 ++ notifier/notifier.go | 44 +++++++---- notifier/notifier_test.go | 157 +++++++++++++++++++++++++++++--------- 3 files changed, 158 insertions(+), 51 deletions(-) diff --git a/config/config.go b/config/config.go index d32fcc33c9..b77bbd6917 100644 --- a/config/config.go +++ b/config/config.go @@ -823,6 +823,8 @@ type AlertmanagerConfig struct { // List of Alertmanager relabel configurations. RelabelConfigs []*relabel.Config `yaml:"relabel_configs,omitempty"` + // Relabel alerts before sending to the specific alertmanager. + AlertRelabelConfigs []*relabel.Config `yaml:"alert_relabel_configs,omitempty"` } // SetDirectory joins any relative file paths with dir. @@ -858,6 +860,12 @@ func (c *AlertmanagerConfig) UnmarshalYAML(unmarshal func(interface{}) error) er } } + for _, rlcfg := range c.AlertRelabelConfigs { + if rlcfg == nil { + return errors.New("empty or null Alertmanager alert relabeling rule") + } + } + return nil } diff --git a/notifier/notifier.go b/notifier/notifier.go index 891372c43e..630cbdf1e5 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -349,7 +349,7 @@ func (n *Manager) Send(alerts ...*Alert) { n.mtx.Lock() defer n.mtx.Unlock() - alerts = n.relabelAlerts(alerts) + alerts = relabelAlerts(n.opts.RelabelConfigs, n.opts.ExternalLabels, alerts) if len(alerts) == 0 { return } @@ -377,20 +377,21 @@ func (n *Manager) Send(alerts ...*Alert) { n.setMore() } -// Attach external labels and process relabelling rules. -func (n *Manager) relabelAlerts(alerts []*Alert) []*Alert { +func relabelAlerts(relabelConfigs []*relabel.Config, externalLabels labels.Labels, alerts []*Alert) []*Alert { lb := labels.NewBuilder(labels.EmptyLabels()) var relabeledAlerts []*Alert for _, a := range alerts { lb.Reset(a.Labels) - n.opts.ExternalLabels.Range(func(l labels.Label) { - if a.Labels.Get(l.Name) == "" { - lb.Set(l.Name, l.Value) - } - }) + if externalLabels.Len() > 0 { + externalLabels.Range(func(l labels.Label) { + if a.Labels.Get(l.Name) == "" { + lb.Set(l.Name, l.Value) + } + }) + } - keep := relabel.ProcessBuilder(lb, n.opts.RelabelConfigs...) + keep := relabel.ProcessBuilder(lb, relabelConfigs...) if !keep { continue } @@ -472,17 +473,30 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { ) for _, ams := range amSets { var ( - payload []byte - err error + payload []byte + err error + amAlerts = alerts ) ams.mtx.RLock() + if len(ams.cfg.AlertRelabelConfigs) > 0 { + amAlerts = relabelAlerts(ams.cfg.AlertRelabelConfigs, labels.Labels{}, alerts) + // TODO(nabokihms): figure out the right way to cache marshalled alerts. + // Now it works well only for happy cases. + v1Payload = nil + v2Payload = nil + + if len(amAlerts) == 0 { + continue + } + } + switch ams.cfg.APIVersion { case config.AlertmanagerAPIVersionV1: { if v1Payload == nil { - v1Payload, err = json.Marshal(alerts) + v1Payload, err = json.Marshal(amAlerts) if err != nil { level.Error(n.logger).Log("msg", "Encoding alerts for Alertmanager API v1 failed", "err", err) ams.mtx.RUnlock() @@ -495,7 +509,7 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { case config.AlertmanagerAPIVersionV2: { if v2Payload == nil { - openAPIAlerts := alertsToOpenAPIAlerts(alerts) + openAPIAlerts := alertsToOpenAPIAlerts(amAlerts) v2Payload, err = json.Marshal(openAPIAlerts) if err != nil { @@ -526,13 +540,13 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { go func(client *http.Client, url string) { if err := n.sendOne(ctx, client, url, payload); err != nil { - level.Error(n.logger).Log("alertmanager", url, "count", len(alerts), "msg", "Error sending alert", "err", err) + level.Error(n.logger).Log("alertmanager", url, "count", len(amAlerts), "msg", "Error sending alert", "err", err) n.metrics.errors.WithLabelValues(url).Inc() } else { numSuccess.Inc() } n.metrics.latency.WithLabelValues(url).Observe(time.Since(begin).Seconds()) - n.metrics.sent.WithLabelValues(url).Add(float64(len(alerts))) + n.metrics.sent.WithLabelValues(url).Add(float64(len(amAlerts))) wg.Done() }(ams.client, am.url().String()) diff --git a/notifier/notifier_test.go b/notifier/notifier_test.go index 66ee45c6e8..79a3157d79 100644 --- a/notifier/notifier_test.go +++ b/notifier/notifier_test.go @@ -98,6 +98,41 @@ func alertsEqual(a, b []*Alert) error { return nil } +func newTestHTTPServerBuilder(expected *[]*Alert, errc chan<- error, u, p string, status *atomic.Int32) *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var err error + defer func() { + if err == nil { + return + } + select { + case errc <- err: + default: + } + }() + user, pass, _ := r.BasicAuth() + if user != u || pass != p { + err = fmt.Errorf("unexpected user/password: %s/%s != %s/%s", user, pass, u, p) + w.WriteHeader(http.StatusInternalServerError) + return + } + + b, err := io.ReadAll(r.Body) + if err != nil { + err = fmt.Errorf("error reading body: %v", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + var alerts []*Alert + err = json.Unmarshal(b, &alerts) + if err == nil { + err = alertsEqual(*expected, alerts) + } + w.WriteHeader(int(status.Load())) + })) +} + func TestHandlerSendAll(t *testing.T) { var ( errc = make(chan error, 1) @@ -107,42 +142,8 @@ func TestHandlerSendAll(t *testing.T) { status1.Store(int32(http.StatusOK)) status2.Store(int32(http.StatusOK)) - newHTTPServer := func(u, p string, status *atomic.Int32) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var err error - defer func() { - if err == nil { - return - } - select { - case errc <- err: - default: - } - }() - user, pass, _ := r.BasicAuth() - if user != u || pass != p { - err = fmt.Errorf("unexpected user/password: %s/%s != %s/%s", user, pass, u, p) - w.WriteHeader(http.StatusInternalServerError) - return - } - - b, err := io.ReadAll(r.Body) - if err != nil { - err = fmt.Errorf("error reading body: %w", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - var alerts []*Alert - err = json.Unmarshal(b, &alerts) - if err == nil { - err = alertsEqual(expected, alerts) - } - w.WriteHeader(int(status.Load())) - })) - } - server1 := newHTTPServer("prometheus", "testing_password", &status1) - server2 := newHTTPServer("", "", &status2) + server1 := newTestHTTPServerBuilder(&expected, errc, "prometheus", "testing_password", &status1) + server2 := newTestHTTPServerBuilder(&expected, errc, "", "", &status2) defer server1.Close() defer server2.Close() @@ -213,6 +214,90 @@ func TestHandlerSendAll(t *testing.T) { checkNoErr() } +func TestHandlerSendAllRemapPerAm(t *testing.T) { + var ( + errc = make(chan error, 1) + expected1 = make([]*Alert, 0, maxBatchSize) + expected2 = make([]*Alert, 0, maxBatchSize) + + status1, status2 atomic.Int32 + ) + status1.Store(int32(http.StatusOK)) + status2.Store(int32(http.StatusOK)) + + server1 := newTestHTTPServerBuilder(&expected1, errc, "", "", &status1) + server2 := newTestHTTPServerBuilder(&expected2, errc, "", "", &status2) + + defer server1.Close() + defer server2.Close() + + h := NewManager(&Options{}, nil) + h.alertmanagers = make(map[string]*alertmanagerSet) + + am1Cfg := config.DefaultAlertmanagerConfig + am1Cfg.Timeout = model.Duration(time.Second) + + am2Cfg := config.DefaultAlertmanagerConfig + am2Cfg.Timeout = model.Duration(time.Second) + am2Cfg.AlertRelabelConfigs = []*relabel.Config{ + { + SourceLabels: model.LabelNames{"alertnamedrop"}, + Action: "drop", + Regex: relabel.MustNewRegexp(".+"), + }, + } + + h.alertmanagers["1"] = &alertmanagerSet{ + ams: []alertmanager{ + alertmanagerMock{ + urlf: func() string { return server1.URL }, + }, + }, + cfg: &am1Cfg, + } + + h.alertmanagers["2"] = &alertmanagerSet{ + ams: []alertmanager{ + alertmanagerMock{ + urlf: func() string { return server2.URL }, + }, + }, + cfg: &am2Cfg, + } + + for i := range make([]struct{}, maxBatchSize/2) { + h.queue = append(h.queue, &Alert{ + Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), + }) + h.queue = append(h.queue, &Alert{ + Labels: labels.FromStrings("alertnamedrop", fmt.Sprintf("%d", i)), + }) + + expected1 = append(expected1, &Alert{ + Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), + }) + expected1 = append(expected1, &Alert{ + Labels: labels.FromStrings("alertnamedrop", fmt.Sprintf("%d", i)), + }) + + expected2 = append(expected2, &Alert{ + Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), + }) + } + + checkNoErr := func() { + t.Helper() + select { + case err := <-errc: + require.NoError(t, err) + default: + } + } + + require.True(t, h.sendAll(h.queue...), "all sends failed unexpectedly") + checkNoErr() +} + func TestCustomDo(t *testing.T) { const testURL = "http://testurl.com/" const testBody = "testbody" From 9d8463339d70f8d39314b11615ae4350e246dc63 Mon Sep 17 00:00:00 2001 From: "m.nabokikh" Date: Sun, 23 Jul 2023 00:37:30 +0200 Subject: [PATCH 002/253] Fixes according to the code review Signed-off-by: m.nabokikh --- docs/configuration/configuration.md | 4 ++++ notifier/notifier.go | 12 +++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 30bb07a8c1..0efded225d 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -3415,6 +3415,10 @@ static_configs: # List of Alertmanager relabel configurations. relabel_configs: [ - ... ] + +# List of alert relabel configurations. +alert_relabel_configs: + [ - ... ] ``` ### `` diff --git a/notifier/notifier.go b/notifier/notifier.go index 630cbdf1e5..0f93c25a35 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -383,13 +383,11 @@ func relabelAlerts(relabelConfigs []*relabel.Config, externalLabels labels.Label for _, a := range alerts { lb.Reset(a.Labels) - if externalLabels.Len() > 0 { - externalLabels.Range(func(l labels.Label) { - if a.Labels.Get(l.Name) == "" { - lb.Set(l.Name, l.Value) - } - }) - } + externalLabels.Range(func(l labels.Label) { + if a.Labels.Get(l.Name) == "" { + lb.Set(l.Name, l.Value) + } + }) keep := relabel.ProcessBuilder(lb, relabelConfigs...) if !keep { From adde7db85f0c8ef9b147deb563ad00297b584f28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 23:32:17 +0000 Subject: [PATCH 003/253] build(deps): bump bufbuild/buf-lint-action from 1.0.3 to 1.1.0 Bumps [bufbuild/buf-lint-action](https://github.com/bufbuild/buf-lint-action) from 1.0.3 to 1.1.0. - [Release notes](https://github.com/bufbuild/buf-lint-action/releases) - [Commits](https://github.com/bufbuild/buf-lint-action/compare/bd48f53224baaaf0fc55de9a913e7680ca6dbea4...044d13acb1f155179c606aaa2e53aea304d22058) --- updated-dependencies: - dependency-name: bufbuild/buf-lint-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/buf-lint.yml | 2 +- .github/workflows/buf.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buf-lint.yml b/.github/workflows/buf-lint.yml index b44ba05118..df5fba02c9 100644 --- a/.github/workflows/buf-lint.yml +++ b/.github/workflows/buf-lint.yml @@ -16,7 +16,7 @@ jobs: - uses: bufbuild/buf-setup-action@eb60cd0de4f14f1f57cf346916b8cd69a9e7ed0b # v1.26.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} - - uses: bufbuild/buf-lint-action@bd48f53224baaaf0fc55de9a913e7680ca6dbea4 # v1.0.3 + - uses: bufbuild/buf-lint-action@044d13acb1f155179c606aaa2e53aea304d22058 # v1.1.0 with: input: 'prompb' - uses: bufbuild/buf-breaking-action@f47418c81c00bfd65394628385593542f64db477 # v1.1.2 diff --git a/.github/workflows/buf.yml b/.github/workflows/buf.yml index 58c1bc1989..213b4c2b63 100644 --- a/.github/workflows/buf.yml +++ b/.github/workflows/buf.yml @@ -16,7 +16,7 @@ jobs: - uses: bufbuild/buf-setup-action@eb60cd0de4f14f1f57cf346916b8cd69a9e7ed0b # v1.26.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} - - uses: bufbuild/buf-lint-action@bd48f53224baaaf0fc55de9a913e7680ca6dbea4 # v1.0.3 + - uses: bufbuild/buf-lint-action@044d13acb1f155179c606aaa2e53aea304d22058 # v1.1.0 with: input: 'prompb' - uses: bufbuild/buf-breaking-action@f47418c81c00bfd65394628385593542f64db477 # v1.1.2 From bfec57bd2e11c12077bc82e9ec144843e0a890af Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Thu, 25 Jan 2024 10:40:57 +0100 Subject: [PATCH 004/253] Further optimise FastRegexMatcher Signed-off-by: Marco Pracucci --- model/labels/matcher.go | 27 + model/labels/matcher_test.go | 94 ++- model/labels/regexp.go | 894 ++++++++++++++++++++++++++-- model/labels/regexp_test.go | 1055 +++++++++++++++++++++++++++++++--- 4 files changed, 1960 insertions(+), 110 deletions(-) diff --git a/model/labels/matcher.go b/model/labels/matcher.go index f299c40f64..1282f80d63 100644 --- a/model/labels/matcher.go +++ b/model/labels/matcher.go @@ -118,3 +118,30 @@ func (m *Matcher) GetRegexString() string { } return m.re.GetRegexString() } + +// SetMatches returns a set of equality matchers for the current regex matchers if possible. +// For examples the regexp `a(b|f)` will returns "ab" and "af". +// Returns nil if we can't replace the regexp by only equality matchers. +func (m *Matcher) SetMatches() []string { + if m.re == nil { + return nil + } + return m.re.SetMatches() +} + +// Prefix returns the required prefix of the value to match, if possible. +// It will be empty if it's an equality matcher or if the prefix can't be determined. +func (m *Matcher) Prefix() string { + if m.re == nil { + return "" + } + return m.re.prefix +} + +// IsRegexOptimized returns whether regex is optimized. +func (m *Matcher) IsRegexOptimized() bool { + if m.re == nil { + return false + } + return m.re.IsOptimized() +} diff --git a/model/labels/matcher_test.go b/model/labels/matcher_test.go index d26e9329f2..c23deafe61 100644 --- a/model/labels/matcher_test.go +++ b/model/labels/matcher_test.go @@ -14,13 +14,14 @@ package labels import ( + "fmt" "testing" "github.com/stretchr/testify/require" ) func mustNewMatcher(t *testing.T, mType MatchType, value string) *Matcher { - m, err := NewMatcher(mType, "", value) + m, err := NewMatcher(mType, "test_label_name", value) require.NoError(t, err) return m } @@ -81,6 +82,21 @@ func TestMatcher(t *testing.T) { value: "foo-bar", match: false, }, + { + matcher: mustNewMatcher(t, MatchRegexp, "$*bar"), + value: "foo-bar", + match: false, + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "bar^+"), + value: "foo-bar", + match: false, + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "$+bar"), + value: "foo-bar", + match: false, + }, } for _, test := range tests { @@ -118,6 +134,82 @@ func TestInverse(t *testing.T) { } } +func TestPrefix(t *testing.T) { + for i, tc := range []struct { + matcher *Matcher + prefix string + }{ + { + matcher: mustNewMatcher(t, MatchEqual, "abc"), + prefix: "", + }, + { + matcher: mustNewMatcher(t, MatchNotEqual, "abc"), + prefix: "", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "abc.+"), + prefix: "abc", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "abcd|abc.+"), + prefix: "abc", + }, + { + matcher: mustNewMatcher(t, MatchNotRegexp, "abcd|abc.+"), + prefix: "abc", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "abc(def|ghj)|ab|a."), + prefix: "a", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "foo.+bar|foo.*baz"), + prefix: "foo", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "abc|.*"), + prefix: "", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "abc|def"), + prefix: "", + }, + { + matcher: mustNewMatcher(t, MatchRegexp, ".+def"), + prefix: "", + }, + } { + t.Run(fmt.Sprintf("%d: %s", i, tc.matcher), func(t *testing.T) { + require.Equal(t, tc.prefix, tc.matcher.Prefix()) + }) + } +} + +func TestIsRegexOptimized(t *testing.T) { + for i, tc := range []struct { + matcher *Matcher + isRegexOptimized bool + }{ + { + matcher: mustNewMatcher(t, MatchEqual, "abc"), + isRegexOptimized: false, + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "."), + isRegexOptimized: false, + }, + { + matcher: mustNewMatcher(t, MatchRegexp, "abc.+"), + isRegexOptimized: true, + }, + } { + t.Run(fmt.Sprintf("%d: %s", i, tc.matcher), func(t *testing.T) { + require.Equal(t, tc.isRegexOptimized, tc.matcher.IsRegexOptimized()) + }) + } +} + func BenchmarkMatchType_String(b *testing.B) { for i := 0; i <= b.N; i++ { _ = MatchType(i % int(MatchNotRegexp+1)).String() diff --git a/model/labels/regexp.go b/model/labels/regexp.go index 14319c7f7a..5e470afa3b 100644 --- a/model/labels/regexp.go +++ b/model/labels/regexp.go @@ -18,69 +18,344 @@ import ( "github.com/grafana/regexp" "github.com/grafana/regexp/syntax" + "golang.org/x/exp/slices" +) + +const ( + maxSetMatches = 256 + + // The minimum number of alternate values a regex should have to trigger + // the optimization done by optimizeEqualStringMatchers() and so use a map + // to match values instead of iterating over a list. This value has + // been computed running BenchmarkOptimizeEqualStringMatchers. + minEqualMultiStringMatcherMapThreshold = 16 ) type FastRegexMatcher struct { + // Under some conditions, re is nil because the expression is never parsed. + // We store the original string to be able to return it in GetRegexString(). + reString string re *regexp.Regexp - prefix string - suffix string - contains string - // shortcut for literals - literal bool - value string + setMatches []string + stringMatcher StringMatcher + prefix string + suffix string + contains string + + // matchString is the "compiled" function to run by MatchString(). + matchString func(string) bool } func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) { - if isLiteral(v) { - return &FastRegexMatcher{literal: true, value: v}, nil - } - re, err := regexp.Compile("^(?:" + v + ")$") - if err != nil { - return nil, err - } - - parsed, err := syntax.Parse(v, syntax.Perl) - if err != nil { - return nil, err - } - m := &FastRegexMatcher{ - re: re, + reString: v, } - if parsed.Op == syntax.OpConcat { - m.prefix, m.suffix, m.contains = optimizeConcatRegex(parsed) + m.stringMatcher, m.setMatches = optimizeAlternatingLiterals(v) + if m.stringMatcher != nil { + // If we already have a string matcher, we don't need to parse the regex + // or compile the matchString function. This also avoids the behavior in + // compileMatchStringFunction where it prefers to use setMatches when + // available, even if the string matcher is faster. + m.matchString = m.stringMatcher.Matches + } else { + parsed, err := syntax.Parse(v, syntax.Perl) + if err != nil { + return nil, err + } + // Simplify the syntax tree to run faster. + parsed = parsed.Simplify() + m.re, err = regexp.Compile("^(?:" + parsed.String() + ")$") + if err != nil { + return nil, err + } + if parsed.Op == syntax.OpConcat { + m.prefix, m.suffix, m.contains = optimizeConcatRegex(parsed) + } + if matches, caseSensitive := findSetMatches(parsed); caseSensitive { + m.setMatches = matches + } + m.stringMatcher = stringMatcherFromRegexp(parsed) + m.matchString = m.compileMatchStringFunction() } return m, nil } +// compileMatchStringFunction returns the function to run by MatchString(). +func (m *FastRegexMatcher) compileMatchStringFunction() func(string) bool { + // If the only optimization available is the string matcher, then we can just run it. + if len(m.setMatches) == 0 && m.prefix == "" && m.suffix == "" && m.contains == "" && m.stringMatcher != nil { + return m.stringMatcher.Matches + } + + return func(s string) bool { + if len(m.setMatches) != 0 { + for _, match := range m.setMatches { + if match == s { + return true + } + } + return false + } + if m.prefix != "" && !strings.HasPrefix(s, m.prefix) { + return false + } + if m.suffix != "" && !strings.HasSuffix(s, m.suffix) { + return false + } + if m.contains != "" && !strings.Contains(s, m.contains) { + return false + } + if m.stringMatcher != nil { + return m.stringMatcher.Matches(s) + } + return m.re.MatchString(s) + } +} + +// IsOptimized returns true if any fast-path optimization is applied to the +// regex matcher. +func (m *FastRegexMatcher) IsOptimized() bool { + return len(m.setMatches) > 0 || m.stringMatcher != nil || m.prefix != "" || m.suffix != "" || m.contains != "" +} + +// findSetMatches extract equality matches from a regexp. +// Returns nil if we can't replace the regexp by only equality matchers or the regexp contains +// a mix of case sensitive and case insensitive matchers. +func findSetMatches(re *syntax.Regexp) (matches []string, caseSensitive bool) { + clearBeginEndText(re) + + return findSetMatchesInternal(re, "") +} + +func findSetMatchesInternal(re *syntax.Regexp, base string) (matches []string, caseSensitive bool) { + switch re.Op { + case syntax.OpBeginText: + // Correctly handling the begin text operator inside a regex is tricky, + // so in this case we fallback to the regex engine. + return nil, false + case syntax.OpEndText: + // Correctly handling the end text operator inside a regex is tricky, + // so in this case we fallback to the regex engine. + return nil, false + case syntax.OpLiteral: + return []string{base + string(re.Rune)}, isCaseSensitive(re) + case syntax.OpEmptyMatch: + if base != "" { + return []string{base}, isCaseSensitive(re) + } + case syntax.OpAlternate: + return findSetMatchesFromAlternate(re, base) + case syntax.OpCapture: + clearCapture(re) + return findSetMatchesInternal(re, base) + case syntax.OpConcat: + return findSetMatchesFromConcat(re, base) + case syntax.OpCharClass: + if len(re.Rune)%2 != 0 { + return nil, false + } + var matches []string + var totalSet int + for i := 0; i+1 < len(re.Rune); i += 2 { + totalSet += int(re.Rune[i+1]-re.Rune[i]) + 1 + } + // limits the total characters that can be used to create matches. + // In some case like negation [^0-9] a lot of possibilities exists and that + // can create thousands of possible matches at which points we're better off using regexp. + if totalSet > maxSetMatches { + return nil, false + } + for i := 0; i+1 < len(re.Rune); i += 2 { + lo, hi := re.Rune[i], re.Rune[i+1] + for c := lo; c <= hi; c++ { + matches = append(matches, base+string(c)) + } + } + return matches, isCaseSensitive(re) + default: + return nil, false + } + return nil, false +} + +func findSetMatchesFromConcat(re *syntax.Regexp, base string) (matches []string, matchesCaseSensitive bool) { + if len(re.Sub) == 0 { + return nil, false + } + clearCapture(re.Sub...) + + matches = []string{base} + + for i := 0; i < len(re.Sub); i++ { + var newMatches []string + for j, b := range matches { + m, caseSensitive := findSetMatchesInternal(re.Sub[i], b) + if m == nil { + return nil, false + } + if tooManyMatches(newMatches, m...) { + return nil, false + } + + // All matches must have the same case sensitivity. If it's the first set of matches + // returned, we store its sensitivity as the expected case, and then we'll check all + // other ones. + if i == 0 && j == 0 { + matchesCaseSensitive = caseSensitive + } + if matchesCaseSensitive != caseSensitive { + return nil, false + } + + newMatches = append(newMatches, m...) + } + matches = newMatches + } + + return matches, matchesCaseSensitive +} + +func findSetMatchesFromAlternate(re *syntax.Regexp, base string) (matches []string, matchesCaseSensitive bool) { + for i, sub := range re.Sub { + found, caseSensitive := findSetMatchesInternal(sub, base) + if found == nil { + return nil, false + } + if tooManyMatches(matches, found...) { + return nil, false + } + + // All matches must have the same case sensitivity. If it's the first set of matches + // returned, we store its sensitivity as the expected case, and then we'll check all + // other ones. + if i == 0 { + matchesCaseSensitive = caseSensitive + } + if matchesCaseSensitive != caseSensitive { + return nil, false + } + + matches = append(matches, found...) + } + + return matches, matchesCaseSensitive +} + +// clearCapture removes capture operation as they are not used for matching. +func clearCapture(regs ...*syntax.Regexp) { + for _, r := range regs { + // Iterate on the regexp because capture groups could be nested. + for r.Op == syntax.OpCapture { + *r = *r.Sub[0] + } + } +} + +// clearBeginEndText removes the begin and end text from the regexp. Prometheus regexp are anchored to the beginning and end of the string. +func clearBeginEndText(re *syntax.Regexp) { + // Do not clear begin/end text from an alternate operator because it could + // change the actual regexp properties. + if re.Op == syntax.OpAlternate { + return + } + + if len(re.Sub) == 0 { + return + } + if len(re.Sub) == 1 { + if re.Sub[0].Op == syntax.OpBeginText || re.Sub[0].Op == syntax.OpEndText { + // We need to remove this element. Since it's the only one, we convert into a matcher of an empty string. + // OpEmptyMatch is regexp's nop operator. + re.Op = syntax.OpEmptyMatch + re.Sub = nil + return + } + } + if re.Sub[0].Op == syntax.OpBeginText { + re.Sub = re.Sub[1:] + } + if re.Sub[len(re.Sub)-1].Op == syntax.OpEndText { + re.Sub = re.Sub[:len(re.Sub)-1] + } +} + +// isCaseInsensitive tells if a regexp is case insensitive. +// The flag should be check at each level of the syntax tree. +func isCaseInsensitive(reg *syntax.Regexp) bool { + return (reg.Flags & syntax.FoldCase) != 0 +} + +// isCaseSensitive tells if a regexp is case sensitive. +// The flag should be check at each level of the syntax tree. +func isCaseSensitive(reg *syntax.Regexp) bool { + return !isCaseInsensitive(reg) +} + +// tooManyMatches guards against creating too many set matches. +func tooManyMatches(matches []string, added ...string) bool { + return len(matches)+len(added) > maxSetMatches +} + func (m *FastRegexMatcher) MatchString(s string) bool { - if m.literal { - return s == m.value - } - if m.prefix != "" && !strings.HasPrefix(s, m.prefix) { - return false - } - if m.suffix != "" && !strings.HasSuffix(s, m.suffix) { - return false - } - if m.contains != "" && !strings.Contains(s, m.contains) { - return false - } - return m.re.MatchString(s) + return m.matchString(s) +} + +func (m *FastRegexMatcher) SetMatches() []string { + // IMPORTANT: always return a copy, otherwise if the caller manipulate this slice it will + // also get manipulated in the cached FastRegexMatcher instance. + return slices.Clone(m.setMatches) } func (m *FastRegexMatcher) GetRegexString() string { - if m.literal { - return m.value - } - return m.re.String() + return m.reString } -func isLiteral(re string) bool { - return regexp.QuoteMeta(re) == re +// optimizeAlternatingLiterals optimizes a regex of the form +// +// `literal1|literal2|literal3|...` +// +// this function returns an optimized StringMatcher or nil if the regex +// cannot be optimized in this way, and a list of setMatches up to maxSetMatches. +func optimizeAlternatingLiterals(s string) (StringMatcher, []string) { + if len(s) == 0 { + return emptyStringMatcher{}, nil + } + + estimatedAlternates := strings.Count(s, "|") + 1 + + // If there are no alternates, check if the string is a literal + if estimatedAlternates == 1 { + if regexp.QuoteMeta(s) == s { + return &equalStringMatcher{s: s, caseSensitive: true}, []string{s} + } + return nil, nil + } + + multiMatcher := newEqualMultiStringMatcher(true, estimatedAlternates) + + for end := strings.IndexByte(s, '|'); end > -1; end = strings.IndexByte(s, '|') { + // Split the string into the next literal and the remainder + subMatch := s[:end] + s = s[end+1:] + + // break if any of the submatches are not literals + if regexp.QuoteMeta(subMatch) != subMatch { + return nil, nil + } + + multiMatcher.add(subMatch) + } + + // break if the remainder is not a literal + if regexp.QuoteMeta(s) != s { + return nil, nil + } + multiMatcher.add(s) + + return multiMatcher, multiMatcher.setMatches() } // optimizeConcatRegex returns literal prefix/suffix text that can be safely @@ -123,3 +398,540 @@ func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) { return } + +// StringMatcher is a matcher that matches a string in place of a regular expression. +type StringMatcher interface { + Matches(s string) bool +} + +// stringMatcherFromRegexp attempts to replace a common regexp with a string matcher. +// It returns nil if the regexp is not supported. +func stringMatcherFromRegexp(re *syntax.Regexp) StringMatcher { + clearBeginEndText(re) + + m := stringMatcherFromRegexpInternal(re) + m = optimizeEqualStringMatchers(m, minEqualMultiStringMatcherMapThreshold) + + return m +} + +func stringMatcherFromRegexpInternal(re *syntax.Regexp) StringMatcher { + clearCapture(re) + + switch re.Op { + case syntax.OpBeginText: + // Correctly handling the begin text operator inside a regex is tricky, + // so in this case we fallback to the regex engine. + return nil + case syntax.OpEndText: + // Correctly handling the end text operator inside a regex is tricky, + // so in this case we fallback to the regex engine. + return nil + case syntax.OpPlus: + if re.Sub[0].Op != syntax.OpAnyChar && re.Sub[0].Op != syntax.OpAnyCharNotNL { + return nil + } + return &anyNonEmptyStringMatcher{ + matchNL: re.Sub[0].Op == syntax.OpAnyChar, + } + case syntax.OpStar: + if re.Sub[0].Op != syntax.OpAnyChar && re.Sub[0].Op != syntax.OpAnyCharNotNL { + return nil + } + + // If the newline is valid, than this matcher literally match any string (even empty). + if re.Sub[0].Op == syntax.OpAnyChar { + return trueMatcher{} + } + + // Any string is fine (including an empty one), as far as it doesn't contain any newline. + return anyStringWithoutNewlineMatcher{} + case syntax.OpQuest: + // Only optimize for ".?". + if len(re.Sub) != 1 || (re.Sub[0].Op != syntax.OpAnyChar && re.Sub[0].Op != syntax.OpAnyCharNotNL) { + return nil + } + + return &zeroOrOneCharacterStringMatcher{ + matchNL: re.Sub[0].Op == syntax.OpAnyChar, + } + case syntax.OpEmptyMatch: + return emptyStringMatcher{} + + case syntax.OpLiteral: + return &equalStringMatcher{ + s: string(re.Rune), + caseSensitive: !isCaseInsensitive(re), + } + case syntax.OpAlternate: + or := make([]StringMatcher, 0, len(re.Sub)) + for _, sub := range re.Sub { + m := stringMatcherFromRegexpInternal(sub) + if m == nil { + return nil + } + or = append(or, m) + } + return orStringMatcher(or) + case syntax.OpConcat: + clearCapture(re.Sub...) + + if len(re.Sub) == 0 { + return emptyStringMatcher{} + } + if len(re.Sub) == 1 { + return stringMatcherFromRegexpInternal(re.Sub[0]) + } + + var left, right StringMatcher + + // Let's try to find if there's a first and last any matchers. + if re.Sub[0].Op == syntax.OpPlus || re.Sub[0].Op == syntax.OpStar || re.Sub[0].Op == syntax.OpQuest { + left = stringMatcherFromRegexpInternal(re.Sub[0]) + if left == nil { + return nil + } + re.Sub = re.Sub[1:] + } + if re.Sub[len(re.Sub)-1].Op == syntax.OpPlus || re.Sub[len(re.Sub)-1].Op == syntax.OpStar || re.Sub[len(re.Sub)-1].Op == syntax.OpQuest { + right = stringMatcherFromRegexpInternal(re.Sub[len(re.Sub)-1]) + if right == nil { + return nil + } + re.Sub = re.Sub[:len(re.Sub)-1] + } + + matches, matchesCaseSensitive := findSetMatchesInternal(re, "") + + if len(matches) == 0 && len(re.Sub) == 2 { + // We have not find fixed set matches. We look for other known cases that + // we can optimize. + switch { + // Prefix is literal. + case right == nil && re.Sub[0].Op == syntax.OpLiteral: + right = stringMatcherFromRegexpInternal(re.Sub[1]) + if right != nil { + matches = []string{string(re.Sub[0].Rune)} + matchesCaseSensitive = !isCaseInsensitive(re.Sub[0]) + } + + // Suffix is literal. + case left == nil && re.Sub[1].Op == syntax.OpLiteral: + left = stringMatcherFromRegexpInternal(re.Sub[0]) + if left != nil { + matches = []string{string(re.Sub[1].Rune)} + matchesCaseSensitive = !isCaseInsensitive(re.Sub[1]) + } + } + } + + // Ensure we've found some literals to match (optionally with a left and/or right matcher). + // If not, then this optimization doesn't trigger. + if len(matches) == 0 { + return nil + } + + // Use the right (and best) matcher based on what we've found. + switch { + // No left and right matchers (only fixed set matches). + case left == nil && right == nil: + // if there's no any matchers on both side it's a concat of literals + or := make([]StringMatcher, 0, len(matches)) + for _, match := range matches { + or = append(or, &equalStringMatcher{ + s: match, + caseSensitive: matchesCaseSensitive, + }) + } + return orStringMatcher(or) + + // Right matcher with 1 fixed set match. + case left == nil && len(matches) == 1: + return &literalPrefixStringMatcher{ + prefix: matches[0], + prefixCaseSensitive: matchesCaseSensitive, + right: right, + } + + // Left matcher with 1 fixed set match. + case right == nil && len(matches) == 1: + return &literalSuffixStringMatcher{ + left: left, + suffix: matches[0], + suffixCaseSensitive: matchesCaseSensitive, + } + + // We found literals in the middle. We can trigger the fast path only if + // the matches are case sensitive because containsStringMatcher doesn't + // support case insensitive. + case matchesCaseSensitive: + return &containsStringMatcher{ + substrings: matches, + left: left, + right: right, + } + } + } + return nil +} + +// containsStringMatcher matches a string if it contains any of the substrings. +// If left and right are not nil, it's a contains operation where left and right must match. +// If left is nil, it's a hasPrefix operation and right must match. +// Finally, if right is nil it's a hasSuffix operation and left must match. +type containsStringMatcher struct { + // The matcher that must match the left side. Can be nil. + left StringMatcher + + // At least one of these strings must match in the "middle", between left and right matchers. + substrings []string + + // The matcher that must match the right side. Can be nil. + right StringMatcher +} + +func (m *containsStringMatcher) Matches(s string) bool { + for _, substr := range m.substrings { + switch { + case m.right != nil && m.left != nil: + searchStartPos := 0 + + for { + pos := strings.Index(s[searchStartPos:], substr) + if pos < 0 { + break + } + + // Since we started searching from searchStartPos, we have to add that offset + // to get the actual position of the substring inside the text. + pos += searchStartPos + + // If both the left and right matchers match, then we can stop searching because + // we've found a match. + if m.left.Matches(s[:pos]) && m.right.Matches(s[pos+len(substr):]) { + return true + } + + // Continue searching for another occurrence of the substring inside the text. + searchStartPos = pos + 1 + } + case m.left != nil: + // If we have to check for characters on the left then we need to match a suffix. + if strings.HasSuffix(s, substr) && m.left.Matches(s[:len(s)-len(substr)]) { + return true + } + case m.right != nil: + if strings.HasPrefix(s, substr) && m.right.Matches(s[len(substr):]) { + return true + } + } + } + return false +} + +// literalPrefixStringMatcher matches a string with the given literal prefix and right side matcher. +type literalPrefixStringMatcher struct { + prefix string + prefixCaseSensitive bool + + // The matcher that must match the right side. Can be nil. + right StringMatcher +} + +func (m *literalPrefixStringMatcher) Matches(s string) bool { + // Ensure the prefix matches. + if m.prefixCaseSensitive && !strings.HasPrefix(s, m.prefix) { + return false + } + if !m.prefixCaseSensitive && !hasPrefixCaseInsensitive(s, m.prefix) { + return false + } + + // Ensure the right side matches. + return m.right.Matches(s[len(m.prefix):]) +} + +// literalSuffixStringMatcher matches a string with the given literal suffix and left side matcher. +type literalSuffixStringMatcher struct { + // The matcher that must match the left side. Can be nil. + left StringMatcher + + suffix string + suffixCaseSensitive bool +} + +func (m *literalSuffixStringMatcher) Matches(s string) bool { + // Ensure the suffix matches. + if m.suffixCaseSensitive && !strings.HasSuffix(s, m.suffix) { + return false + } + if !m.suffixCaseSensitive && !hasSuffixCaseInsensitive(s, m.suffix) { + return false + } + + // Ensure the left side matches. + return m.left.Matches(s[:len(s)-len(m.suffix)]) +} + +// emptyStringMatcher matches an empty string. +type emptyStringMatcher struct{} + +func (m emptyStringMatcher) Matches(s string) bool { + return len(s) == 0 +} + +// orStringMatcher matches any of the sub-matchers. +type orStringMatcher []StringMatcher + +func (m orStringMatcher) Matches(s string) bool { + for _, matcher := range m { + if matcher.Matches(s) { + return true + } + } + return false +} + +// equalStringMatcher matches a string exactly and support case insensitive. +type equalStringMatcher struct { + s string + caseSensitive bool +} + +func (m *equalStringMatcher) Matches(s string) bool { + if m.caseSensitive { + return m.s == s + } + return strings.EqualFold(m.s, s) +} + +type multiStringMatcherBuilder interface { + StringMatcher + add(s string) + setMatches() []string +} + +func newEqualMultiStringMatcher(caseSensitive bool, estimatedSize int) multiStringMatcherBuilder { + // If the estimated size is low enough, it's faster to use a slice instead of a map. + if estimatedSize < minEqualMultiStringMatcherMapThreshold { + return &equalMultiStringSliceMatcher{caseSensitive: caseSensitive, values: make([]string, 0, estimatedSize)} + } + + return &equalMultiStringMapMatcher{ + values: make(map[string]struct{}, estimatedSize), + caseSensitive: caseSensitive, + } +} + +// equalMultiStringSliceMatcher matches a string exactly against a slice of valid values. +type equalMultiStringSliceMatcher struct { + values []string + + caseSensitive bool +} + +func (m *equalMultiStringSliceMatcher) add(s string) { + m.values = append(m.values, s) +} + +func (m *equalMultiStringSliceMatcher) setMatches() []string { + return m.values +} + +func (m *equalMultiStringSliceMatcher) Matches(s string) bool { + if m.caseSensitive { + for _, v := range m.values { + if s == v { + return true + } + } + } else { + for _, v := range m.values { + if strings.EqualFold(s, v) { + return true + } + } + } + return false +} + +// equalMultiStringMapMatcher matches a string exactly against a map of valid values. +type equalMultiStringMapMatcher struct { + // values contains values to match a string against. If the matching is case insensitive, + // the values here must be lowercase. + values map[string]struct{} + + caseSensitive bool +} + +func (m *equalMultiStringMapMatcher) add(s string) { + if !m.caseSensitive { + s = strings.ToLower(s) + } + + m.values[s] = struct{}{} +} + +func (m *equalMultiStringMapMatcher) setMatches() []string { + if len(m.values) >= maxSetMatches { + return nil + } + + matches := make([]string, 0, len(m.values)) + for s := range m.values { + matches = append(matches, s) + } + return matches +} + +func (m *equalMultiStringMapMatcher) Matches(s string) bool { + if !m.caseSensitive { + s = strings.ToLower(s) + } + + _, ok := m.values[s] + return ok +} + +// anyStringWithoutNewlineMatcher is a stringMatcher which matches any string +// (including an empty one) as far as it doesn't contain any newline character. +type anyStringWithoutNewlineMatcher struct{} + +func (m anyStringWithoutNewlineMatcher) Matches(s string) bool { + // We need to make sure it doesn't contain a newline. Since the newline is + // an ASCII character, we can use strings.IndexByte(). + return strings.IndexByte(s, '\n') == -1 +} + +// anyNonEmptyStringMatcher is a stringMatcher which matches any non-empty string. +type anyNonEmptyStringMatcher struct { + matchNL bool +} + +func (m *anyNonEmptyStringMatcher) Matches(s string) bool { + if m.matchNL { + // It's OK if the string contains a newline so we just need to make + // sure it's non-empty. + return len(s) > 0 + } + + // We need to make sure it non-empty and doesn't contain a newline. + // Since the newline is an ASCII character, we can use strings.IndexByte(). + return len(s) > 0 && strings.IndexByte(s, '\n') == -1 +} + +// zeroOrOneCharacterStringMatcher is a StringMatcher which matches zero or one occurrence +// of any character. The newline character is matches only if matchNL is set to true. +type zeroOrOneCharacterStringMatcher struct { + matchNL bool +} + +func (m *zeroOrOneCharacterStringMatcher) Matches(s string) bool { + // Zero or one. + if len(s) > 1 { + return false + } + + // No need to check for the newline if the string is empty or matching a newline is OK. + if m.matchNL || len(s) == 0 { + return true + } + + return s[0] != '\n' +} + +// trueMatcher is a stringMatcher which matches any string (always returns true). +type trueMatcher struct{} + +func (m trueMatcher) Matches(_ string) bool { + return true +} + +// optimizeEqualStringMatchers optimize a specific case where all matchers are made by an +// alternation (orStringMatcher) of strings checked for equality (equalStringMatcher). In +// this specific case, when we have many strings to match against we can use a map instead +// of iterating over the list of strings. +func optimizeEqualStringMatchers(input StringMatcher, threshold int) StringMatcher { + var ( + caseSensitive bool + caseSensitiveSet bool + numValues int + ) + + // Analyse the input StringMatcher to count the number of occurrences + // and ensure all of them have the same case sensitivity. + analyseCallback := func(matcher *equalStringMatcher) bool { + // Ensure we don't have mixed case sensitivity. + if caseSensitiveSet && caseSensitive != matcher.caseSensitive { + return false + } else if !caseSensitiveSet { + caseSensitive = matcher.caseSensitive + caseSensitiveSet = true + } + + numValues++ + return true + } + + if !findEqualStringMatchers(input, analyseCallback) { + return input + } + + // If the number of values found is less than the threshold, then we should skip the optimization. + if numValues < threshold { + return input + } + + // Parse again the input StringMatcher to extract all values and storing them. + // We can skip the case sensitivity check because we've already checked it and + // if the code reach this point then it means all matchers have the same case sensitivity. + multiMatcher := newEqualMultiStringMatcher(caseSensitive, numValues) + + // Ignore the return value because we already iterated over the input StringMatcher + // and it was all good. + findEqualStringMatchers(input, func(matcher *equalStringMatcher) bool { + multiMatcher.add(matcher.s) + return true + }) + + return multiMatcher +} + +// findEqualStringMatchers analyze the input StringMatcher and calls the callback for each +// equalStringMatcher found. Returns true if and only if the input StringMatcher is *only* +// composed by an alternation of equalStringMatcher. +func findEqualStringMatchers(input StringMatcher, callback func(matcher *equalStringMatcher) bool) bool { + orInput, ok := input.(orStringMatcher) + if !ok { + return false + } + + for _, m := range orInput { + switch casted := m.(type) { + case orStringMatcher: + if !findEqualStringMatchers(m, callback) { + return false + } + + case *equalStringMatcher: + if !callback(casted) { + return false + } + + default: + // It's not an equal string matcher, so we have to stop searching + // cause this optimization can't be applied. + return false + } + } + + return true +} + +func hasPrefixCaseInsensitive(s, prefix string) bool { + return len(s) >= len(prefix) && strings.EqualFold(s[0:len(prefix)], prefix) +} + +func hasSuffixCaseInsensitive(s, suffix string) bool { + return len(s) >= len(suffix) && strings.EqualFold(s[len(s)-len(suffix):], suffix) +} diff --git a/model/labels/regexp_test.go b/model/labels/regexp_test.go index 3188f7cefc..fc21459ed0 100644 --- a/model/labels/regexp_test.go +++ b/model/labels/regexp_test.go @@ -14,49 +14,100 @@ package labels import ( + "fmt" + "math/rand" "strings" "testing" + "time" + "github.com/grafana/regexp" "github.com/grafana/regexp/syntax" "github.com/stretchr/testify/require" ) -func TestNewFastRegexMatcher(t *testing.T) { - cases := []struct { - regex string - value string - expected bool - }{ - {regex: "(foo|bar)", value: "foo", expected: true}, - {regex: "(foo|bar)", value: "foo bar", expected: false}, - {regex: "(foo|bar)", value: "bar", expected: true}, - {regex: "foo.*", value: "foo bar", expected: true}, - {regex: "foo.*", value: "bar foo", expected: false}, - {regex: ".*foo", value: "foo bar", expected: false}, - {regex: ".*foo", value: "bar foo", expected: true}, - {regex: ".*foo", value: "foo", expected: true}, - {regex: "^.*foo$", value: "foo", expected: true}, - {regex: "^.+foo$", value: "foo", expected: false}, - {regex: "^.+foo$", value: "bfoo", expected: true}, - {regex: ".*", value: "\n", expected: false}, - {regex: ".*", value: "\nfoo", expected: false}, - {regex: ".*foo", value: "\nfoo", expected: false}, - {regex: "foo.*", value: "foo\n", expected: false}, - {regex: "foo\n.*", value: "foo\n", expected: true}, - {regex: ".*foo.*", value: "foo", expected: true}, - {regex: ".*foo.*", value: "foo bar", expected: true}, - {regex: ".*foo.*", value: "hello foo world", expected: true}, - {regex: ".*foo.*", value: "hello foo\n world", expected: false}, - {regex: ".*foo\n.*", value: "hello foo\n world", expected: true}, - {regex: ".*", value: "foo", expected: true}, - {regex: "", value: "foo", expected: false}, - {regex: "", value: "", expected: true}, +var ( + asciiRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_") + regexes = []string{ + "", + "foo", + "^foo", + "(foo|bar)", + "foo.*", + ".*foo", + "^.*foo$", + "^.+foo$", + ".*", + ".+", + "foo.+", + ".+foo", + "foo\n.+", + "foo\n.*", + ".*foo.*", + ".+foo.+", + "(?s:.*)", + "(?s:.+)", + "(?s:^.*foo$)", + "(?i:foo)", + "(?i:(foo|bar))", + "(?i:(foo1|foo2|bar))", + "^(?i:foo|oo)|(bar)$", + "(?i:(foo1|foo2|aaa|bbb|ccc|ddd|eee|fff|ggg|hhh|iii|lll|mmm|nnn|ooo|ppp|qqq|rrr|sss|ttt|uuu|vvv|www|xxx|yyy|zzz))", + "((.*)(bar|b|buzz)(.+)|foo)$", + "^$", + "(prometheus|api_prom)_api_v1_.+", + "10\\.0\\.(1|2)\\.+", + "10\\.0\\.(1|2).+", + "((fo(bar))|.+foo)", + // A long case sensitive alternation. + "zQPbMkNO|NNSPdvMi|iWuuSoAl|qbvKMimS|IecrXtPa|seTckYqt|NxnyHkgB|fIDlOgKb|UhlWIygH|OtNoJxHG|cUTkFVIV|mTgFIHjr|jQkoIDtE|PPMKxRXl|AwMfwVkQ|CQyMrTQJ|BzrqxVSi|nTpcWuhF|PertdywG|ZZDgCtXN|WWdDPyyE|uVtNQsKk|BdeCHvPZ|wshRnFlH|aOUIitIp|RxZeCdXT|CFZMslCj|AVBZRDxl|IzIGCnhw|ythYuWiz|oztXVXhl|VbLkwqQx|qvaUgyVC|VawUjPWC|ecloYJuj|boCLTdSU|uPrKeAZx|hrMWLWBq|JOnUNHRM|rYnujkPq|dDEdZhIj|DRrfvugG|yEGfDxVV|YMYdJWuP|PHUQZNWM|AmKNrLis|zTxndVfn|FPsHoJnc|EIulZTua|KlAPhdzg|ScHJJCLt|NtTfMzME|eMCwuFdo|SEpJVJbR|cdhXZeCx|sAVtBwRh|kVFEVcMI|jzJrxraA|tGLHTell|NNWoeSaw|DcOKSetX|UXZAJyka|THpMphDP|rizheevl|kDCBRidd|pCZZRqyu|pSygkitl|SwZGkAaW|wILOrfNX|QkwVOerj|kHOMxPDr|EwOVycJv|AJvtzQFS|yEOjKYYB|LizIINLL|JBRSsfcG|YPiUqqNl|IsdEbvee|MjEpGcBm|OxXZVgEQ|xClXGuxa|UzRCGFEb|buJbvfvA|IPZQxRet|oFYShsMc|oBHffuHO|bzzKrcBR|KAjzrGCl|IPUsAVls|OGMUMbIU|gyDccHuR|bjlalnDd|ZLWjeMna|fdsuIlxQ|dVXtiomV|XxedTjNg|XWMHlNoA|nnyqArQX|opfkWGhb|wYtnhdYb", + // An extremely long case sensitive alternation. This is a special + // case because the values share common prefixes rather than being + // entirely random. This is common in the real world. For example, the + // values of a label like kubernetes pod will often include the + // deployment name as a prefix. + "jyyfj00j0061|jyyfj00j0062|jyyfj94j0093|jyyfj99j0093|jyyfm01j0021|jyyfm02j0021|jyefj00j0192|jyefj00j0193|jyefj00j0194|jyefj00j0195|jyefj00j0196|jyefj00j0197|jyefj00j0290|jyefj00j0291|jyefj00j0292|jyefj00j0293|jyefj00j0294|jyefj00j0295|jyefj00j0296|jyefj00j0297|jyefj89j0394|jyefj90j0394|jyefj91j0394|jyefj95j0347|jyefj96j0322|jyefj96j0347|jyefj97j0322|jyefj97j0347|jyefj98j0322|jyefj98j0347|jyefj99j0320|jyefj99j0322|jyefj99j0323|jyefj99j0335|jyefj99j0336|jyefj99j0344|jyefj99j0347|jyefj99j0349|jyefj99j0351|jyeff00j0117|lyyfm01j0025|lyyfm01j0028|lyyfm01j0041|lyyfm01j0133|lyyfm01j0701|lyyfm02j0025|lyyfm02j0028|lyyfm02j0041|lyyfm02j0133|lyyfm02j0701|lyyfm03j0701|lyefj00j0775|lyefj00j0776|lyefj00j0777|lyefj00j0778|lyefj00j0779|lyefj00j0780|lyefj00j0781|lyefj00j0782|lyefj50j3807|lyefj50j3852|lyefj51j3807|lyefj51j3852|lyefj52j3807|lyefj52j3852|lyefj53j3807|lyefj53j3852|lyefj54j3807|lyefj54j3852|lyefj54j3886|lyefj55j3807|lyefj55j3852|lyefj55j3886|lyefj56j3807|lyefj56j3852|lyefj56j3886|lyefj57j3807|lyefj57j3852|lyefj57j3886|lyefj58j3807|lyefj58j3852|lyefj58j3886|lyefj59j3807|lyefj59j3852|lyefj59j3886|lyefj60j3807|lyefj60j3852|lyefj60j3886|lyefj61j3807|lyefj61j3852|lyefj61j3886|lyefj62j3807|lyefj62j3852|lyefj62j3886|lyefj63j3807|lyefj63j3852|lyefj63j3886|lyefj64j3807|lyefj64j3852|lyefj64j3886|lyefj65j3807|lyefj65j3852|lyefj65j3886|lyefj66j3807|lyefj66j3852|lyefj66j3886|lyefj67j3807|lyefj67j3852|lyefj67j3886|lyefj68j3807|lyefj68j3852|lyefj68j3886|lyefj69j3807|lyefj69j3846|lyefj69j3852|lyefj69j3886|lyefj70j3807|lyefj70j3846|lyefj70j3852|lyefj70j3886|lyefj71j3807|lyefj71j3846|lyefj71j3852|lyefj71j3886|lyefj72j3807|lyefj72j3846|lyefj72j3852|lyefj72j3886|lyefj73j3807|lyefj73j3846|lyefj73j3852|lyefj73j3886|lyefj74j3807|lyefj74j3846|lyefj74j3852|lyefj74j3886|lyefj75j3807|lyefj75j3808|lyefj75j3846|lyefj75j3852|lyefj75j3886|lyefj76j3732|lyefj76j3807|lyefj76j3808|lyefj76j3846|lyefj76j3852|lyefj76j3886|lyefj77j3732|lyefj77j3807|lyefj77j3808|lyefj77j3846|lyefj77j3852|lyefj77j3886|lyefj78j3278|lyefj78j3732|lyefj78j3807|lyefj78j3808|lyefj78j3846|lyefj78j3852|lyefj78j3886|lyefj79j3732|lyefj79j3807|lyefj79j3808|lyefj79j3846|lyefj79j3852|lyefj79j3886|lyefj80j3732|lyefj80j3807|lyefj80j3808|lyefj80j3846|lyefj80j3852|lyefj80j3886|lyefj81j3732|lyefj81j3807|lyefj81j3808|lyefj81j3846|lyefj81j3852|lyefj81j3886|lyefj82j3732|lyefj82j3807|lyefj82j3808|lyefj82j3846|lyefj82j3852|lyefj82j3886|lyefj83j3732|lyefj83j3807|lyefj83j3808|lyefj83j3846|lyefj83j3852|lyefj83j3886|lyefj84j3732|lyefj84j3807|lyefj84j3808|lyefj84j3846|lyefj84j3852|lyefj84j3886|lyefj85j3732|lyefj85j3807|lyefj85j3808|lyefj85j3846|lyefj85j3852|lyefj85j3886|lyefj86j3278|lyefj86j3732|lyefj86j3807|lyefj86j3808|lyefj86j3846|lyefj86j3852|lyefj86j3886|lyefj87j3278|lyefj87j3732|lyefj87j3807|lyefj87j3808|lyefj87j3846|lyefj87j3852|lyefj87j3886|lyefj88j3732|lyefj88j3807|lyefj88j3808|lyefj88j3846|lyefj88j3852|lyefj88j3886|lyefj89j3732|lyefj89j3807|lyefj89j3808|lyefj89j3846|lyefj89j3852|lyefj89j3886|lyefj90j3732|lyefj90j3807|lyefj90j3808|lyefj90j3846|lyefj90j3852|lyefj90j3886|lyefj91j3732|lyefj91j3807|lyefj91j3808|lyefj91j3846|lyefj91j3852|lyefj91j3886|lyefj92j3732|lyefj92j3807|lyefj92j3808|lyefj92j3846|lyefj92j3852|lyefj92j3886|lyefj93j3732|lyefj93j3807|lyefj93j3808|lyefj93j3846|lyefj93j3852|lyefj93j3885|lyefj93j3886|lyefj94j3525|lyefj94j3732|lyefj94j3807|lyefj94j3808|lyefj94j3846|lyefj94j3852|lyefj94j3885|lyefj94j3886|lyefj95j3525|lyefj95j3732|lyefj95j3807|lyefj95j3808|lyefj95j3846|lyefj95j3852|lyefj95j3886|lyefj96j3732|lyefj96j3803|lyefj96j3807|lyefj96j3808|lyefj96j3846|lyefj96j3852|lyefj96j3886|lyefj97j3333|lyefj97j3732|lyefj97j3792|lyefj97j3803|lyefj97j3807|lyefj97j3808|lyefj97j3838|lyefj97j3843|lyefj97j3846|lyefj97j3852|lyefj97j3886|lyefj98j3083|lyefj98j3333|lyefj98j3732|lyefj98j3807|lyefj98j3808|lyefj98j3838|lyefj98j3843|lyefj98j3846|lyefj98j3852|lyefj98j3873|lyefj98j3877|lyefj98j3882|lyefj98j3886|lyefj99j2984|lyefj99j3083|lyefj99j3333|lyefj99j3732|lyefj99j3807|lyefj99j3808|lyefj99j3846|lyefj99j3849|lyefj99j3852|lyefj99j3873|lyefj99j3877|lyefj99j3882|lyefj99j3884|lyefj99j3886|lyeff00j0106|lyeff00j0107|lyeff00j0108|lyeff00j0129|lyeff00j0130|lyeff00j0131|lyeff00j0132|lyeff00j0133|lyeff00j0134|lyeff00j0444|lyeff00j0445|lyeff91j0473|lyeff92j0473|lyeff92j3877|lyeff93j3877|lyeff94j0501|lyeff94j3525|lyeff94j3877|lyeff95j0501|lyeff95j3525|lyeff95j3877|lyeff96j0503|lyeff96j3877|lyeff97j3877|lyeff98j3333|lyeff98j3877|lyeff99j2984|lyeff99j3333|lyeff99j3877|mfyr9149ej|mfyr9149ek|mfyr9156ej|mfyr9156ek|mfyr9157ej|mfyr9157ek|mfyr9159ej|mfyr9159ek|mfyr9203ej|mfyr9204ej|mfyr9205ej|mfyr9206ej|mfyr9207ej|mfyr9207ek|mfyr9217ej|mfyr9217ek|mfyr9222ej|mfyr9222ek|mfyu0185ej|mfye9187ej|mfye9187ek|mfye9188ej|mfye9188ek|mfye9189ej|mfye9189ek|mfyf0185ej|oyefj87j0007|oyefj88j0007|oyefj89j0007|oyefj90j0007|oyefj91j0007|oyefj95j0001|oyefj96j0001|oyefj98j0004|oyefj99j0004|oyeff91j0004|oyeff92j0004|oyeff93j0004|oyeff94j0004|oyeff95j0004|oyeff96j0004|rklvyaxmany|ryefj93j0001|ryefj94j0001|tyyfj00a0001|tyyfj84j0005|tyyfj85j0005|tyyfj86j0005|tyyfj87j0005|tyyfj88j0005|tyyfj89j0005|tyyfj90j0005|tyyfj91j0005|tyyfj92j0005|tyyfj93j0005|tyyfj94j0005|tyyfj95j0005|tyyfj96j0005|tyyfj97j0005|tyyfj98j0005|tyyfj99j0005|tyefj50j0015|tyefj50j0017|tyefj50j0019|tyefj50j0020|tyefj50j0021|tyefj51j0015|tyefj51j0017|tyefj51j0019|tyefj51j0020|tyefj51j0021|tyefj52j0015|tyefj52j0017|tyefj52j0019|tyefj52j0020|tyefj52j0021|tyefj53j0015|tyefj53j0017|tyefj53j0019|tyefj53j0020|tyefj53j0021|tyefj54j0015|tyefj54j0017|tyefj54j0019|tyefj54j0020|tyefj54j0021|tyefj55j0015|tyefj55j0017|tyefj55j0019|tyefj55j0020|tyefj55j0021|tyefj56j0015|tyefj56j0017|tyefj56j0019|tyefj56j0020|tyefj56j0021|tyefj57j0015|tyefj57j0017|tyefj57j0019|tyefj57j0020|tyefj57j0021|tyefj58j0015|tyefj58j0017|tyefj58j0019|tyefj58j0020|tyefj58j0021|tyefj59j0015|tyefj59j0017|tyefj59j0019|tyefj59j0020|tyefj59j0021|tyefj60j0015|tyefj60j0017|tyefj60j0019|tyefj60j0020|tyefj60j0021|tyefj61j0015|tyefj61j0017|tyefj61j0019|tyefj61j0020|tyefj61j0021|tyefj62j0015|tyefj62j0017|tyefj62j0019|tyefj62j0020|tyefj62j0021|tyefj63j0015|tyefj63j0017|tyefj63j0019|tyefj63j0020|tyefj63j0021|tyefj64j0015|tyefj64j0017|tyefj64j0019|tyefj64j0020|tyefj64j0021|tyefj65j0015|tyefj65j0017|tyefj65j0019|tyefj65j0020|tyefj65j0021|tyefj66j0015|tyefj66j0017|tyefj66j0019|tyefj66j0020|tyefj66j0021|tyefj67j0015|tyefj67j0017|tyefj67j0019|tyefj67j0020|tyefj67j0021|tyefj68j0015|tyefj68j0017|tyefj68j0019|tyefj68j0020|tyefj68j0021|tyefj69j0015|tyefj69j0017|tyefj69j0019|tyefj69j0020|tyefj69j0021|tyefj70j0015|tyefj70j0017|tyefj70j0019|tyefj70j0020|tyefj70j0021|tyefj71j0015|tyefj71j0017|tyefj71j0019|tyefj71j0020|tyefj71j0021|tyefj72j0015|tyefj72j0017|tyefj72j0019|tyefj72j0020|tyefj72j0021|tyefj72j0022|tyefj73j0015|tyefj73j0017|tyefj73j0019|tyefj73j0020|tyefj73j0021|tyefj73j0022|tyefj74j0015|tyefj74j0017|tyefj74j0019|tyefj74j0020|tyefj74j0021|tyefj74j0022|tyefj75j0015|tyefj75j0017|tyefj75j0019|tyefj75j0020|tyefj75j0021|tyefj75j0022|tyefj76j0015|tyefj76j0017|tyefj76j0019|tyefj76j0020|tyefj76j0021|tyefj76j0022|tyefj76j0119|tyefj77j0015|tyefj77j0017|tyefj77j0019|tyefj77j0020|tyefj77j0021|tyefj77j0022|tyefj77j0119|tyefj78j0015|tyefj78j0017|tyefj78j0019|tyefj78j0020|tyefj78j0021|tyefj78j0022|tyefj78j0119|tyefj79j0015|tyefj79j0017|tyefj79j0019|tyefj79j0020|tyefj79j0021|tyefj79j0022|tyefj79j0119|tyefj80j0015|tyefj80j0017|tyefj80j0019|tyefj80j0020|tyefj80j0021|tyefj80j0022|tyefj80j0114|tyefj80j0119|tyefj81j0015|tyefj81j0017|tyefj81j0019|tyefj81j0020|tyefj81j0021|tyefj81j0022|tyefj81j0114|tyefj81j0119|tyefj82j0015|tyefj82j0017|tyefj82j0019|tyefj82j0020|tyefj82j0021|tyefj82j0022|tyefj82j0119|tyefj83j0015|tyefj83j0017|tyefj83j0019|tyefj83j0020|tyefj83j0021|tyefj83j0022|tyefj83j0119|tyefj84j0014|tyefj84j0015|tyefj84j0017|tyefj84j0019|tyefj84j0020|tyefj84j0021|tyefj84j0022|tyefj84j0119|tyefj85j0014|tyefj85j0015|tyefj85j0017|tyefj85j0019|tyefj85j0020|tyefj85j0021|tyefj85j0022|tyefj85j0119|tyefj86j0014|tyefj86j0015|tyefj86j0017|tyefj86j0019|tyefj86j0020|tyefj86j0021|tyefj86j0022|tyefj87j0014|tyefj87j0015|tyefj87j0017|tyefj87j0019|tyefj87j0020|tyefj87j0021|tyefj87j0022|tyefj88j0014|tyefj88j0015|tyefj88j0017|tyefj88j0019|tyefj88j0020|tyefj88j0021|tyefj88j0022|tyefj88j0100|tyefj88j0115|tyefj89j0003|tyefj89j0014|tyefj89j0015|tyefj89j0017|tyefj89j0019|tyefj89j0020|tyefj89j0021|tyefj89j0022|tyefj89j0100|tyefj89j0115|tyefj90j0014|tyefj90j0015|tyefj90j0016|tyefj90j0017|tyefj90j0018|tyefj90j0019|tyefj90j0020|tyefj90j0021|tyefj90j0022|tyefj90j0100|tyefj90j0111|tyefj90j0115|tyefj91j0014|tyefj91j0015|tyefj91j0016|tyefj91j0017|tyefj91j0018|tyefj91j0019|tyefj91j0020|tyefj91j0021|tyefj91j0022|tyefj91j0100|tyefj91j0111|tyefj91j0115|tyefj92j0014|tyefj92j0015|tyefj92j0016|tyefj92j0017|tyefj92j0018|tyefj92j0019|tyefj92j0020|tyefj92j0021|tyefj92j0022|tyefj92j0100|tyefj92j0105|tyefj92j0115|tyefj92j0121|tyefj93j0004|tyefj93j0014|tyefj93j0015|tyefj93j0017|tyefj93j0018|tyefj93j0019|tyefj93j0020|tyefj93j0021|tyefj93j0022|tyefj93j0100|tyefj93j0105|tyefj93j0115|tyefj93j0121|tyefj94j0002|tyefj94j0004|tyefj94j0008|tyefj94j0014|tyefj94j0015|tyefj94j0017|tyefj94j0019|tyefj94j0020|tyefj94j0021|tyefj94j0022|tyefj94j0084|tyefj94j0088|tyefj94j0100|tyefj94j0106|tyefj94j0116|tyefj94j0121|tyefj94j0123|tyefj95j0002|tyefj95j0004|tyefj95j0008|tyefj95j0014|tyefj95j0015|tyefj95j0017|tyefj95j0019|tyefj95j0020|tyefj95j0021|tyefj95j0022|tyefj95j0084|tyefj95j0088|tyefj95j0100|tyefj95j0101|tyefj95j0106|tyefj95j0112|tyefj95j0116|tyefj95j0121|tyefj95j0123|tyefj96j0014|tyefj96j0015|tyefj96j0017|tyefj96j0019|tyefj96j0020|tyefj96j0021|tyefj96j0022|tyefj96j0082|tyefj96j0084|tyefj96j0100|tyefj96j0101|tyefj96j0112|tyefj96j0117|tyefj96j0121|tyefj96j0124|tyefj97j0014|tyefj97j0015|tyefj97j0017|tyefj97j0019|tyefj97j0020|tyefj97j0021|tyefj97j0022|tyefj97j0081|tyefj97j0087|tyefj97j0098|tyefj97j0100|tyefj97j0107|tyefj97j0109|tyefj97j0113|tyefj97j0117|tyefj97j0118|tyefj97j0121|tyefj98j0003|tyefj98j0006|tyefj98j0014|tyefj98j0015|tyefj98j0017|tyefj98j0019|tyefj98j0020|tyefj98j0021|tyefj98j0022|tyefj98j0083|tyefj98j0085|tyefj98j0086|tyefj98j0100|tyefj98j0104|tyefj98j0118|tyefj98j0121|tyefj99j0003|tyefj99j0006|tyefj99j0007|tyefj99j0014|tyefj99j0015|tyefj99j0017|tyefj99j0019|tyefj99j0020|tyefj99j0021|tyefj99j0022|tyefj99j0023|tyefj99j0100|tyefj99j0108|tyefj99j0110|tyefj99j0121|tyefj99j0125|tyeff94j0002|tyeff94j0008|tyeff94j0010|tyeff94j0011|tyeff94j0035|tyeff95j0002|tyeff95j0006|tyeff95j0008|tyeff95j0010|tyeff95j0011|tyeff95j0035|tyeff96j0003|tyeff96j0006|tyeff96j0009|tyeff96j0010|tyeff97j0004|tyeff97j0009|tyeff97j0116|tyeff98j0007|tyeff99j0007|tyeff99j0125|uyyfj00j0484|uyyfj00j0485|uyyfj00j0486|uyyfj00j0487|uyyfj00j0488|uyyfj00j0489|uyyfj00j0490|uyyfj00j0491|uyyfj00j0492|uyyfj00j0493|uyyfj00j0494|uyyfj00j0495|uyyfj00j0496|uyyfj00j0497|uyyfj00j0498|uyyfj00j0499|uyyfj00j0500|uyyfj00j0501|uyyfj00j0502|uyyfj00j0503|uyyfj00j0504|uyyfj00j0505|uyyfj00j0506|uyyfj00j0507|uyyfj00j0508|uyyfj00j0509|uyyfj00j0510|uyyfj00j0511|uyyfj00j0512|uyyfj00j0513|uyyfj00j0514|uyyfj00j0515|uyyfj00j0516|uyyfj00j0517|uyyfj00j0518|uyyfj00j0519|uyyfj00j0520|uyyfj00j0521|uyyfj00j0522|uyyfj00j0523|uyyfj00j0524|uyyfj00j0525|uyyfj00j0526|uyyfj00j0527|uyyfj00j0528|uyyfj00j0529|uyyfj00j0530|uyyfj00j0531|uyyfj00j0532|uyyfj00j0533|uyyfj00j0534|uyyfj00j0535|uyyfj00j0536|uyyfj00j0537|uyyfj00j0538|uyyfj00j0539|uyyfj00j0540|uyyfj00j0541|uyyfj00j0542|uyyfj00j0543|uyyfj00j0544|uyyfj00j0545|uyyfj00j0546|uyyfj00j0547|uyyfj00j0548|uyyfj00j0549|uyyfj00j0550|uyyfj00j0551|uyyfj00j0553|uyyfj00j0554|uyyfj00j0555|uyyfj00j0556|uyyfj00j0557|uyyfj00j0558|uyyfj00j0559|uyyfj00j0560|uyyfj00j0561|uyyfj00j0562|uyyfj00j0563|uyyfj00j0564|uyyfj00j0565|uyyfj00j0566|uyyfj00j0614|uyyfj00j0615|uyyfj00j0616|uyyfj00j0617|uyyfj00j0618|uyyfj00j0619|uyyfj00j0620|uyyfj00j0621|uyyfj00j0622|uyyfj00j0623|uyyfj00j0624|uyyfj00j0625|uyyfj00j0626|uyyfj00j0627|uyyfj00j0628|uyyfj00j0629|uyyfj00j0630|uyyfj00j0631|uyyfj00j0632|uyyfj00j0633|uyyfj00j0634|uyyfj00j0635|uyyfj00j0636|uyyfj00j0637|uyyfj00j0638|uyyfj00j0639|uyyfj00j0640|uyyfj00j0641|uyyfj00j0642|uyyfj00j0643|uyyfj00j0644|uyyfj00j0645|uyyfj00j0646|uyyfj00j0647|uyyfj00j0648|uyyfj00j0649|uyyfj00j0650|uyyfj00j0651|uyyfj00j0652|uyyfj00j0653|uyyfj00j0654|uyyfj00j0655|uyyfj00j0656|uyyfj00j0657|uyyfj00j0658|uyyfj00j0659|uyyfj00j0660|uyyfj00j0661|uyyfj00j0662|uyyfj00j0663|uyyfj00j0664|uyyfj00j0665|uyyfj00j0666|uyyfj00j0667|uyyfj00j0668|uyyfj00j0669|uyyfj00j0670|uyyfj00j0671|uyyfj00j0672|uyyfj00j0673|uyyfj00j0674|uyyfj00j0675|uyyfj00j0676|uyyfj00j0677|uyyfj00j0678|uyyfj00j0679|uyyfj00j0680|uyyfj00j0681|uyyfj00j0682|uyyfj00j0683|uyyfj00j0684|uyyfj00j0685|uyyfj00j0686|uyyfj00j0687|uyyfj00j0688|uyyfj00j0689|uyyfj00j0690|uyyfj00j0691|uyyfj00j0692|uyyfj00j0693|uyyfj00j0694|uyyfj00j0695|uyyfj00j0696|uyyfj00j0697|uyyfj00j0698|uyyfj00j0699|uyyfj00j0700|uyyfj00j0701|uyyfj00j0702|uyyfj00j0703|uyyfj00j0704|uyyfj00j0705|uyyfj00j0706|uyyfj00j0707|uyyfj00j0708|uyyfj00j0709|uyyfj00j0710|uyyfj00j0711|uyyfj00j0712|uyyfj00j0713|uyyfj00j0714|uyyfj00j0715|uyyfj00j0716|uyyfj00j0717|uyyfj00j0718|uyyfj00j0719|uyyfj00j0720|uyyfj00j0721|uyyfj00j0722|uyyfj00j0723|uyyfj00j0724|uyyfj00j0725|uyyfj00j0726|uyyfj00j0727|uyyfj00j0728|uyyfj00j0729|uyyfj00j0730|uyyfj00j0731|uyyfj00j0732|uyyfj00j0733|uyyfj00j0734|uyyfj00j0735|uyyfj00j0736|uyyfj00j0737|uyyfj00j0738|uyyfj00j0739|uyyfj00j0740|uyyfj00j0741|uyyfj00j0742|uyyfj00j0743|uyyfj00j0744|uyyfj00j0745|uyyfj00j0746|uyyfj00j0747|uyyfj00j0748|uyyfj00j0749|uyyfj00j0750|uyyfj00j0751|uyyfj00j0752|uyyfj00j0753|uyyfj00j0754|uyyfj00j0755|uyyfj00j0756|uyyfj00j0757|uyyfj00j0758|uyyfj00j0759|uyyfj00j0760|uyyfj00j0761|uyyfj00j0762|uyyfj00j0763|uyyfj00j0764|uyyfj00j0765|uyyfj00j0766|uyyfj00j0767|uyyfj00j0768|uyyfj00j0769|uyyfj00j0770|uyyfj00j0771|uyyfj00j0772|uyyfj00j0773|uyyfj00j0774|uyyfj00j0775|uyyfj00j0776|uyyfj00j0777|uyyfj00j0778|uyyfj00j0779|uyyfj00j0780|uyyfj00j0781|uyyfj00j0782|uyyff00j0011|uyyff00j0031|uyyff00j0032|uyyff00j0033|uyyff00j0034|uyyff99j0012|uyefj00j0071|uyefj00j0455|uyefj00j0456|uyefj00j0582|uyefj00j0583|uyefj00j0584|uyefj00j0585|uyefj00j0586|uyefj00j0590|uyeff00j0188|xyrly-f-jyy-y01|xyrly-f-jyy-y02|xyrly-f-jyy-y03|xyrly-f-jyy-y04|xyrly-f-jyy-y05|xyrly-f-jyy-y06|xyrly-f-jyy-y07|xyrly-f-jyy-y08|xyrly-f-jyy-y09|xyrly-f-jyy-y10|xyrly-f-jyy-y11|xyrly-f-jyy-y12|xyrly-f-jyy-y13|xyrly-f-jyy-y14|xyrly-f-jyy-y15|xyrly-f-jyy-y16|xyrly-f-url-y01|xyrly-f-url-y02|yyefj97j0005|ybyfcy4000|ybyfcy4001|ayefj99j0035|by-b-y-bzu-l01|by-b-y-bzu-l02|by-b-e-079|by-b-e-080|by-b-e-082|by-b-e-083|byefj72j0002|byefj73j0002|byefj74j0002|byefj75j0002|byefj76j0002|byefj77j0002|byefj78j0002|byefj79j0002|byefj91j0007|byefj92j0007|byefj98j0003|byefj99j0003|byefj99j0005|byefj99j0006|byeff88j0002|byeff89j0002|byeff90j0002|byeff91j0002|byeff92j0002|byeff93j0002|byeff96j0003|byeff97j0003|byeff98j0003|byeff99j0003|fymfj98j0001|fymfj99j0001|fyyaj98k0297|fyyaj99k0297|fyyfj00j0109|fyyfj00j0110|fyyfj00j0122|fyyfj00j0123|fyyfj00j0201|fyyfj00j0202|fyyfj00j0207|fyyfj00j0208|fyyfj00j0227|fyyfj00j0228|fyyfj00j0229|fyyfj00j0230|fyyfj00j0231|fyyfj00j0232|fyyfj00j0233|fyyfj00j0234|fyyfj00j0235|fyyfj00j0236|fyyfj00j0237|fyyfj00j0238|fyyfj00j0239|fyyfj00j0240|fyyfj00j0241|fyyfj00j0242|fyyfj00j0243|fyyfj00j0244|fyyfj00j0245|fyyfj00j0246|fyyfj00j0247|fyyfj00j0248|fyyfj00j0249|fyyfj00j0250|fyyfj00j0251|fyyfj00j0252|fyyfj00j0253|fyyfj00j0254|fyyfj00j0255|fyyfj00j0256|fyyfj00j0257|fyyfj00j0258|fyyfj00j0259|fyyfj00j0260|fyyfj00j0261|fyyfj00j0262|fyyfj00j0263|fyyfj00j0264|fyyfj00j0265|fyyfj00j0266|fyyfj00j0267|fyyfj00j0268|fyyfj00j0290|fyyfj00j0291|fyyfj00j0292|fyyfj00j0293|fyyfj00j0294|fyyfj00j0295|fyyfj00j0296|fyyfj00j0297|fyyfj00j0298|fyyfj00j0299|fyyfj00j0300|fyyfj00j0301|fyyfj00j0302|fyyfj00j0303|fyyfj00j0304|fyyfj00j0305|fyyfj00j0306|fyyfj00j0307|fyyfj00j0308|fyyfj00j0309|fyyfj00j0310|fyyfj00j0311|fyyfj00j0312|fyyfj00j0313|fyyfj00j0314|fyyfj00j0315|fyyfj00j0316|fyyfj00j0317|fyyfj00j0318|fyyfj00j0319|fyyfj00j0320|fyyfj00j0321|fyyfj00j0322|fyyfj00j0323|fyyfj00j0324|fyyfj00j0325|fyyfj00j0326|fyyfj00j0327|fyyfj00j0328|fyyfj00j0329|fyyfj00j0330|fyyfj00j0331|fyyfj00j0332|fyyfj00j0333|fyyfj00j0334|fyyfj00j0335|fyyfj00j0340|fyyfj00j0341|fyyfj00j0342|fyyfj00j0343|fyyfj00j0344|fyyfj00j0345|fyyfj00j0346|fyyfj00j0347|fyyfj00j0348|fyyfj00j0349|fyyfj00j0367|fyyfj00j0368|fyyfj00j0369|fyyfj00j0370|fyyfj00j0371|fyyfj00j0372|fyyfj00j0373|fyyfj00j0374|fyyfj00j0375|fyyfj00j0376|fyyfj00j0377|fyyfj00j0378|fyyfj00j0379|fyyfj00j0380|fyyfj00j0381|fyyfj00j0382|fyyfj00j0383|fyyfj00j0384|fyyfj00j0385|fyyfj00j0386|fyyfj00j0387|fyyfj00j0388|fyyfj00j0415|fyyfj00j0416|fyyfj00j0417|fyyfj00j0418|fyyfj00j0419|fyyfj00j0420|fyyfj00j0421|fyyfj00j0422|fyyfj00j0423|fyyfj00j0424|fyyfj00j0425|fyyfj00j0426|fyyfj00j0427|fyyfj00j0428|fyyfj00j0429|fyyfj00j0430|fyyfj00j0431|fyyfj00j0432|fyyfj00j0433|fyyfj00j0434|fyyfj00j0435|fyyfj00j0436|fyyfj00j0437|fyyfj00j0438|fyyfj00j0439|fyyfj00j0440|fyyfj00j0441|fyyfj00j0446|fyyfj00j0447|fyyfj00j0448|fyyfj00j0449|fyyfj00j0451|fyyfj00j0452|fyyfj00j0453|fyyfj00j0454|fyyfj00j0455|fyyfj00j0456|fyyfj00j0457|fyyfj00j0459|fyyfj00j0460|fyyfj00j0461|fyyfj00j0462|fyyfj00j0463|fyyfj00j0464|fyyfj00j0465|fyyfj00j0466|fyyfj00j0467|fyyfj00j0468|fyyfj00j0469|fyyfj00j0470|fyyfj00j0471|fyyfj00j0474|fyyfj00j0475|fyyfj00j0476|fyyfj00j0477|fyyfj00j0478|fyyfj00j0479|fyyfj00j0480|fyyfj00j0481|fyyfj00j0482|fyyfj00j0483|fyyfj00j0484|fyyfj00j0485|fyyfj00j0486|fyyfj00j0487|fyyfj00j0488|fyyfj00j0489|fyyfj00j0490|fyyfj00j0491|fyyfj00j0492|fyyfj00j0493|fyyfj00j0494|fyyfj00j0495|fyyfj00j0496|fyyfj00j0497|fyyfj00j0498|fyyfj00j0499|fyyfj00j0500|fyyfj00j0501|fyyfj00j0502|fyyfj00j0503|fyyfj00j0504|fyyfj00j0505|fyyfj00j0506|fyyfj00j0507|fyyfj00j0508|fyyfj00j0509|fyyfj00j0510|fyyfj00j0511|fyyfj00j0512|fyyfj00j0513|fyyfj00j0514|fyyfj00j0515|fyyfj00j0516|fyyfj00j0517|fyyfj00j0518|fyyfj00j0521|fyyfj00j0522|fyyfj00j0523|fyyfj00j0524|fyyfj00j0526|fyyfj00j0527|fyyfj00j0528|fyyfj00j0529|fyyfj00j0530|fyyfj00j0531|fyyfj00j0532|fyyfj00j0533|fyyfj00j0534|fyyfj00j0535|fyyfj00j0536|fyyfj00j0537|fyyfj00j0538|fyyfj00j0539|fyyfj00j0540|fyyfj00j0541|fyyfj00j0542|fyyfj00j0543|fyyfj00j0544|fyyfj00j0545|fyyfj00j0546|fyyfj00j0564|fyyfj00j0565|fyyfj00j0566|fyyfj00j0567|fyyfj00j0568|fyyfj00j0569|fyyfj00j0570|fyyfj00j0571|fyyfj00j0572|fyyfj00j0574|fyyfj00j0575|fyyfj00j0576|fyyfj00j0577|fyyfj00j0578|fyyfj00j0579|fyyfj00j0580|fyyfj01j0473|fyyfj02j0473|fyyfj36j0289|fyyfj37j0209|fyyfj37j0289|fyyfj38j0209|fyyfj38j0289|fyyfj39j0209|fyyfj39j0289|fyyfj40j0209|fyyfj40j0289|fyyfj41j0209|fyyfj41j0289|fyyfj42j0209|fyyfj42j0289|fyyfj43j0209|fyyfj43j0289|fyyfj44j0209|fyyfj44j0289|fyyfj45j0104|fyyfj45j0209|fyyfj45j0289|fyyfj46j0104|fyyfj46j0209|fyyfj46j0289|fyyfj47j0104|fyyfj47j0209|fyyfj47j0289|fyyfj48j0104|fyyfj48j0209|fyyfj48j0289|fyyfj49j0104|fyyfj49j0209|fyyfj49j0289|fyyfj50j0104|fyyfj50j0209|fyyfj50j0289|fyyfj50j0500|fyyfj51j0104|fyyfj51j0209|fyyfj51j0289|fyyfj51j0500|fyyfj52j0104|fyyfj52j0209|fyyfj52j0289|fyyfj52j0500|fyyfj53j0104|fyyfj53j0209|fyyfj53j0289|fyyfj53j0500|fyyfj54j0104|fyyfj54j0209|fyyfj54j0289|fyyfj54j0500|fyyfj55j0104|fyyfj55j0209|fyyfj55j0289|fyyfj55j0500|fyyfj56j0104|fyyfj56j0209|fyyfj56j0289|fyyfj56j0500|fyyfj57j0104|fyyfj57j0209|fyyfj57j0289|fyyfj57j0500|fyyfj58j0104|fyyfj58j0209|fyyfj58j0289|fyyfj58j0500|fyyfj59j0104|fyyfj59j0209|fyyfj59j0289|fyyfj59j0500|fyyfj60j0104|fyyfj60j0209|fyyfj60j0289|fyyfj60j0500|fyyfj61j0104|fyyfj61j0209|fyyfj61j0289|fyyfj61j0500|fyyfj62j0104|fyyfj62j0209|fyyfj62j0289|fyyfj62j0500|fyyfj63j0104|fyyfj63j0209|fyyfj63j0289|fyyfj63j0500|fyyfj64j0104|fyyfj64j0107|fyyfj64j0209|fyyfj64j0289|fyyfj64j0500|fyyfj64j0573|fyyfj65j0104|fyyfj65j0107|fyyfj65j0209|fyyfj65j0289|fyyfj65j0500|fyyfj65j0573|fyyfj66j0104|fyyfj66j0107|fyyfj66j0209|fyyfj66j0289|fyyfj66j0500|fyyfj66j0573|fyyfj67j0104|fyyfj67j0107|fyyfj67j0209|fyyfj67j0289|fyyfj67j0500|fyyfj67j0573|fyyfj68j0104|fyyfj68j0107|fyyfj68j0209|fyyfj68j0289|fyyfj68j0500|fyyfj68j0573|fyyfj69j0104|fyyfj69j0107|fyyfj69j0209|fyyfj69j0289|fyyfj69j0500|fyyfj69j0573|fyyfj70j0104|fyyfj70j0107|fyyfj70j0209|fyyfj70j0289|fyyfj70j0472|fyyfj70j0500|fyyfj70j0573|fyyfj71j0104|fyyfj71j0107|fyyfj71j0209|fyyfj71j0289|fyyfj71j0472|fyyfj71j0500|fyyfj71j0573|fyyfj72j0104|fyyfj72j0107|fyyfj72j0209|fyyfj72j0289|fyyfj72j0472|fyyfj72j0500|fyyfj72j0573|fyyfj73j0104|fyyfj73j0107|fyyfj73j0209|fyyfj73j0289|fyyfj73j0472|fyyfj73j0500|fyyfj73j0573|fyyfj74j0104|fyyfj74j0107|fyyfj74j0209|fyyfj74j0289|fyyfj74j0472|fyyfj74j0500|fyyfj74j0573|fyyfj75j0104|fyyfj75j0107|fyyfj75j0108|fyyfj75j0209|fyyfj75j0289|fyyfj75j0472|fyyfj75j0500|fyyfj75j0573|fyyfj76j0104|fyyfj76j0107|fyyfj76j0108|fyyfj76j0209|fyyfj76j0289|fyyfj76j0472|fyyfj76j0500|fyyfj76j0573|fyyfj77j0104|fyyfj77j0107|fyyfj77j0108|fyyfj77j0209|fyyfj77j0289|fyyfj77j0472|fyyfj77j0500|fyyfj77j0573|fyyfj78j0104|fyyfj78j0107|fyyfj78j0108|fyyfj78j0209|fyyfj78j0289|fyyfj78j0472|fyyfj78j0500|fyyfj78j0573|fyyfj79j0104|fyyfj79j0107|fyyfj79j0108|fyyfj79j0209|fyyfj79j0289|fyyfj79j0339|fyyfj79j0472|fyyfj79j0500|fyyfj79j0573|fyyfj80j0104|fyyfj80j0107|fyyfj80j0108|fyyfj80j0209|fyyfj80j0289|fyyfj80j0339|fyyfj80j0352|fyyfj80j0472|fyyfj80j0500|fyyfj80j0573|fyyfj81j0104|fyyfj81j0107|fyyfj81j0108|fyyfj81j0209|fyyfj81j0289|fyyfj81j0339|fyyfj81j0352|fyyfj81j0472|fyyfj81j0500|fyyfj81j0573|fyyfj82j0104|fyyfj82j0107|fyyfj82j0108|fyyfj82j0209|fyyfj82j0289|fyyfj82j0339|fyyfj82j0352|fyyfj82j0472|fyyfj82j0500|fyyfj82j0573|fyyfj83j0104|fyyfj83j0107|fyyfj83j0108|fyyfj83j0209|fyyfj83j0289|fyyfj83j0339|fyyfj83j0352|fyyfj83j0472|fyyfj83j0500|fyyfj83j0573|fyyfj84j0104|fyyfj84j0107|fyyfj84j0108|fyyfj84j0209|fyyfj84j0289|fyyfj84j0339|fyyfj84j0352|fyyfj84j0472|fyyfj84j0500|fyyfj84j0573|fyyfj85j0104|fyyfj85j0107|fyyfj85j0108|fyyfj85j0209|fyyfj85j0289|fyyfj85j0301|fyyfj85j0339|fyyfj85j0352|fyyfj85j0472|fyyfj85j0500|fyyfj85j0573|fyyfj86j0104|fyyfj86j0107|fyyfj86j0108|fyyfj86j0209|fyyfj86j0289|fyyfj86j0301|fyyfj86j0339|fyyfj86j0352|fyyfj86j0472|fyyfj86j0500|fyyfj86j0573|fyyfj87j0067|fyyfj87j0104|fyyfj87j0107|fyyfj87j0108|fyyfj87j0209|fyyfj87j0289|fyyfj87j0301|fyyfj87j0339|fyyfj87j0352|fyyfj87j0472|fyyfj87j0500|fyyfj87j0573|fyyfj88j0067|fyyfj88j0104|fyyfj88j0107|fyyfj88j0108|fyyfj88j0209|fyyfj88j0289|fyyfj88j0301|fyyfj88j0339|fyyfj88j0352|fyyfj88j0472|fyyfj88j0500|fyyfj88j0573|fyyfj89j0067|fyyfj89j0104|fyyfj89j0107|fyyfj89j0108|fyyfj89j0209|fyyfj89j0289|fyyfj89j0301|fyyfj89j0339|fyyfj89j0352|fyyfj89j0358|fyyfj89j0472|fyyfj89j0500|fyyfj89j0573|fyyfj90j0067|fyyfj90j0104|fyyfj90j0107|fyyfj90j0108|fyyfj90j0209|fyyfj90j0289|fyyfj90j0301|fyyfj90j0321|fyyfj90j0339|fyyfj90j0352|fyyfj90j0358|fyyfj90j0452|fyyfj90j0472|fyyfj90j0500|fyyfj90j0573|fyyfj91j0067|fyyfj91j0104|fyyfj91j0107|fyyfj91j0108|fyyfj91j0209|fyyfj91j0289|fyyfj91j0301|fyyfj91j0321|fyyfj91j0339|fyyfj91j0352|fyyfj91j0358|fyyfj91j0452|fyyfj91j0472|fyyfj91j0500|fyyfj91j0573|fyyfj92j0067|fyyfj92j0104|fyyfj92j0107|fyyfj92j0108|fyyfj92j0209|fyyfj92j0289|fyyfj92j0301|fyyfj92j0321|fyyfj92j0339|fyyfj92j0352|fyyfj92j0358|fyyfj92j0452|fyyfj92j0472|fyyfj92j0500|fyyfj92j0573|fyyfj93j0067|fyyfj93j0099|fyyfj93j0104|fyyfj93j0107|fyyfj93j0108|fyyfj93j0209|fyyfj93j0289|fyyfj93j0301|fyyfj93j0321|fyyfj93j0352|fyyfj93j0358|fyyfj93j0452|fyyfj93j0472|fyyfj93j0500|fyyfj93j0573|fyyfj94j0067|fyyfj94j0099|fyyfj94j0104|fyyfj94j0107|fyyfj94j0108|fyyfj94j0209|fyyfj94j0211|fyyfj94j0289|fyyfj94j0301|fyyfj94j0321|fyyfj94j0352|fyyfj94j0358|fyyfj94j0359|fyyfj94j0452|fyyfj94j0472|fyyfj94j0500|fyyfj94j0573|fyyfj95j0067|fyyfj95j0099|fyyfj95j0104|fyyfj95j0107|fyyfj95j0108|fyyfj95j0209|fyyfj95j0211|fyyfj95j0289|fyyfj95j0298|fyyfj95j0301|fyyfj95j0321|fyyfj95j0339|fyyfj95j0352|fyyfj95j0358|fyyfj95j0359|fyyfj95j0414|fyyfj95j0452|fyyfj95j0472|fyyfj95j0500|fyyfj95j0573|fyyfj96j0067|fyyfj96j0099|fyyfj96j0104|fyyfj96j0107|fyyfj96j0108|fyyfj96j0209|fyyfj96j0211|fyyfj96j0289|fyyfj96j0298|fyyfj96j0301|fyyfj96j0321|fyyfj96j0339|fyyfj96j0352|fyyfj96j0358|fyyfj96j0359|fyyfj96j0414|fyyfj96j0452|fyyfj96j0472|fyyfj96j0500|fyyfj96j0573|fyyfj97j0067|fyyfj97j0099|fyyfj97j0100|fyyfj97j0104|fyyfj97j0107|fyyfj97j0108|fyyfj97j0209|fyyfj97j0211|fyyfj97j0289|fyyfj97j0298|fyyfj97j0301|fyyfj97j0321|fyyfj97j0339|fyyfj97j0352|fyyfj97j0358|fyyfj97j0359|fyyfj97j0414|fyyfj97j0445|fyyfj97j0452|fyyfj97j0472|fyyfj97j0500|fyyfj97j0573|fyyfj98j0067|fyyfj98j0099|fyyfj98j0100|fyyfj98j0104|fyyfj98j0107|fyyfj98j0108|fyyfj98j0178|fyyfj98j0209|fyyfj98j0211|fyyfj98j0289|fyyfj98j0298|fyyfj98j0301|fyyfj98j0303|fyyfj98j0321|fyyfj98j0339|fyyfj98j0352|fyyfj98j0358|fyyfj98j0359|fyyfj98j0413|fyyfj98j0414|fyyfj98j0445|fyyfj98j0452|fyyfj98j0472|fyyfj98j0500|fyyfj98j0573|fyyfj99j0067|fyyfj99j0099|fyyfj99j0100|fyyfj99j0104|fyyfj99j0107|fyyfj99j0108|fyyfj99j0131|fyyfj99j0209|fyyfj99j0211|fyyfj99j0285|fyyfj99j0289|fyyfj99j0298|fyyfj99j0301|fyyfj99j0303|fyyfj99j0321|fyyfj99j0339|fyyfj99j0352|fyyfj99j0358|fyyfj99j0359|fyyfj99j0413|fyyfj99j0414|fyyfj99j0445|fyyfj99j0452|fyyfj99j0472|fyyfj99j0500|fyyfj99j0573|fyyfm01j0064|fyyfm01j0070|fyyfm01j0071|fyyfm01j0088|fyyfm01j0091|fyyfm01j0108|fyyfm01j0111|fyyfm01j0112|fyyfm01j0114|fyyfm01j0115|fyyfm01j0133|fyyfm01j0140|fyyfm01j0141|fyyfm01j0142|fyyfm01j0143|fyyfm01j0148|fyyfm01j0149|fyyfm01j0152|fyyfm01j0153|fyyfm01j0155|fyyfm01j0159|fyyfm01j0160|fyyfm01j0163|fyyfm01j0165|fyyfm01j0168|fyyfm01j0169|fyyfm01j0221|fyyfm01j0223|fyyfm01j0268|fyyfm01j0271|fyyfm01j0285|fyyfm01j0299|fyyfm01j0320|fyyfm01j0321|fyyfm01j0360|fyyfm01j0369|fyyfm01j0400|fyyfm01j0401|fyyfm01j0411|fyyfm01j0572|fyyfm01j0765|fyyfm02j0064|fyyfm02j0069|fyyfm02j0070|fyyfm02j0071|fyyfm02j0088|fyyfm02j0091|fyyfm02j0108|fyyfm02j0111|fyyfm02j0112|fyyfm02j0114|fyyfm02j0115|fyyfm02j0133|fyyfm02j0140|fyyfm02j0141|fyyfm02j0142|fyyfm02j0143|fyyfm02j0148|fyyfm02j0149|fyyfm02j0152|fyyfm02j0153|fyyfm02j0155|fyyfm02j0159|fyyfm02j0160|fyyfm02j0163|fyyfm02j0165|fyyfm02j0168|fyyfm02j0169|fyyfm02j0221|fyyfm02j0223|fyyfm02j0268|fyyfm02j0271|fyyfm02j0285|fyyfm02j0299|fyyfm02j0320|fyyfm02j0321|fyyfm02j0360|fyyfm02j0369|fyyfm02j0400|fyyfm02j0572|fyyfm02j0765|fyyfm03j0064|fyyfm03j0070|fyyfm03j0091|fyyfm03j0108|fyyfm03j0111|fyyfm03j0115|fyyfm03j0160|fyyfm03j0165|fyyfm03j0299|fyyfm03j0400|fyyfm03j0572|fyyfm04j0111|fyyfm51j0064|fyyfm51j0369|fyyfm52j0064|fyyfm52j0369|fyyfr88j0003|fyyfr89j0003|fyyff98j0071|fyyff98j0303|fyyff99j0029|fyyff99j0303|fyefj00j0112|fyefj00j0545|fyefj00j0546|fyefj00j0633|fyefj00j0634|fyefj00j0635|fyefj00j0636|fyefj00j0637|fyefj00j0649|fyefj00j0651|fyefj00j0652|fyefj00j0656|fyefj00j0657|fyefj00j0658|fyefj00j0659|fyefj00j0660|fyefj00j0685|fyefj00j0686|fyefj00j0688|fyefj00j0701|fyefj00j0702|fyefj00j0703|fyefj00j0715|fyefj00j0720|fyefj00j0721|fyefj00j0722|fyefj00j0724|fyefj00j0725|fyefj00j0726|fyefj00j0731|fyefj00j0751|fyefj00j0752|fyefj00j0756|fyefj00j0757|fyefj00j0758|fyefj00j0759|fyefj00j0761|fyefj00j0762|fyefj00j0763|fyefj00j0764|fyefj00j0768|fyefj00j0769|fyefj00j0785|fyefj00j0786|fyefj00j0789|fyefj00j0790|fyefj00j0793|fyefj00j0794|fyefj00j0803|fyefj00j0811|fyefj00j0821|fyefj00j0822|fyefj00j0823|fyefj00j0824|fyefj00j0825|fyefj00j0826|fyefj00j0827|fyefj00j0828|fyefj00j0829|fyefj00j0831|fyefj00j0832|fyefj00j0833|fyefj00j0838|fyefj00j0839|fyefj00j0840|fyefj00j0854|fyefj00j0855|fyefj00j0856|fyefj00j0859|fyefj00j0860|fyefj00j0861|fyefj00j0869|fyefj00j0870|fyefj00j0879|fyefj00j0887|fyefj00j0888|fyefj00j0889|fyefj00j0900|fyefj00j0901|fyefj00j0903|fyefj00j0904|fyefj00j0905|fyefj00j0959|fyefj00j0960|fyefj00j0961|fyefj00j1004|fyefj00j1005|fyefj00j1012|fyefj00j1013|fyefj00j1014|fyefj00j1015|fyefj00j1016|fyefj00j1017|fyefj00j1018|fyefj00j1019|fyefj00j1020|fyefj00j1021|fyefj00j1218|fyefj00j1219|fyefj00j1220|fyefj00j1221|fyefj00j1222|fyefj00j1811|fyefj00j1854|fyefj00j1855|fyefj00j1856|fyefj01j0707|fyefj02j0707|fyefj03j0707|fyefj66j0001|fyefj67j0001|fyefj68j0001|fyefj68j1064|fyefj69j0001|fyefj69j1064|fyefj70j0001|fyefj70j0859|fyefj70j1064|fyefj71j0001|fyefj71j1064|fyefj72j0001|fyefj72j1064|fyefj73j0001|fyefj73j1064|fyefj74j0001|fyefj74j1064|fyefj75j0001|fyefj75j1064|fyefj75j1092|fyefj76j0001|fyefj76j1064|fyefj76j1092|fyefj77j0001|fyefj77j1064|fyefj77j1092|fyefj78j0001|fyefj78j1064|fyefj78j1092|fyefj79j0001|fyefj79j1064|fyefj79j1092|fyefj80j0001|fyefj80j0859|fyefj80j1064|fyefj80j1077|fyefj80j1092|fyefj81j0001|fyefj81j1064|fyefj81j1077|fyefj81j1092|fyefj82j0001|fyefj82j1064|fyefj82j1092|fyefj83j0001|fyefj83j1064|fyefj83j1092|fyefj84j0001|fyefj84j1064|fyefj84j1092|fyefj85j0001|fyefj85j0356|fyefj85j1064|fyefj85j1092|fyefj86j0001|fyefj86j0356|fyefj86j1064|fyefj87j0001|fyefj87j0356|fyefj87j1064|fyefj88j0001|fyefj88j0356|fyefj88j1064|fyefj89j0001|fyefj89j0356|fyefj89j1064|fyefj89j1067|fyefj90j0001|fyefj90j0758|fyefj90j1021|fyefj90j1064|fyefj90j1067|fyefj91j0001|fyefj91j0758|fyefj91j0791|fyefj91j1021|fyefj91j1064|fyefj91j1067|fyefj91j1077|fyefj92j0001|fyefj92j0359|fyefj92j0678|fyefj92j0758|fyefj92j0791|fyefj92j0867|fyefj92j1021|fyefj92j1064|fyefj92j1077|fyefj93j0001|fyefj93j0359|fyefj93j0678|fyefj93j0758|fyefj93j0791|fyefj93j0867|fyefj93j1010|fyefj93j1021|fyefj93j1049|fyefj93j1064|fyefj93j1077|fyefj94j0001|fyefj94j0678|fyefj94j0758|fyefj94j0791|fyefj94j0867|fyefj94j1010|fyefj94j1021|fyefj94j1049|fyefj94j1064|fyefj94j1070|fyefj94j1077|fyefj94j1085|fyefj95j0001|fyefj95j0678|fyefj95j0758|fyefj95j0791|fyefj95j0867|fyefj95j0965|fyefj95j0966|fyefj95j1010|fyefj95j1011|fyefj95j1021|fyefj95j1055|fyefj95j1064|fyefj95j1069|fyefj95j1077|fyefj95j1085|fyefj95j1089|fyefj96j0001|fyefj96j0106|fyefj96j0671|fyefj96j0678|fyefj96j0758|fyefj96j0791|fyefj96j0814|fyefj96j0836|fyefj96j0867|fyefj96j0931|fyefj96j0965|fyefj96j0966|fyefj96j0976|fyefj96j1010|fyefj96j1021|fyefj96j1051|fyefj96j1055|fyefj96j1064|fyefj96j1068|fyefj96j1070|fyefj96j1077|fyefj96j1079|fyefj96j1081|fyefj96j1086|fyefj96j1088|fyefj96j1091|fyefj96j1093|fyefj96j1094|fyefj97j0001|fyefj97j0106|fyefj97j0584|fyefj97j0586|fyefj97j0671|fyefj97j0678|fyefj97j0758|fyefj97j0791|fyefj97j0814|fyefj97j0825|fyefj97j0836|fyefj97j0863|fyefj97j0865|fyefj97j0867|fyefj97j0914|fyefj97j0931|fyefj97j0952|fyefj97j0965|fyefj97j0966|fyefj97j0969|fyefj97j0971|fyefj97j0972|fyefj97j0976|fyefj97j0985|fyefj97j1010|fyefj97j1021|fyefj97j1051|fyefj97j1052|fyefj97j1055|fyefj97j1058|fyefj97j1059|fyefj97j1064|fyefj97j1068|fyefj97j1077|fyefj97j1079|fyefj97j1081|fyefj97j1086|fyefj97j1088|fyefj97j1095|fyefj98j0001|fyefj98j0243|fyefj98j0326|fyefj98j0329|fyefj98j0343|fyefj98j0344|fyefj98j0380|fyefj98j0472|fyefj98j0584|fyefj98j0586|fyefj98j0604|fyefj98j0671|fyefj98j0673|fyefj98j0676|fyefj98j0677|fyefj98j0678|fyefj98j0694|fyefj98j0758|fyefj98j0814|fyefj98j0825|fyefj98j0836|fyefj98j0863|fyefj98j0865|fyefj98j0867|fyefj98j0896|fyefj98j0898|fyefj98j0901|fyefj98j0906|fyefj98j0910|fyefj98j0913|fyefj98j0914|fyefj98j0922|fyefj98j0931|fyefj98j0934|fyefj98j0936|fyefj98j0951|fyefj98j0952|fyefj98j0963|fyefj98j0965|fyefj98j0966|fyefj98j0969|fyefj98j0971|fyefj98j0972|fyefj98j0974|fyefj98j0975|fyefj98j0976|fyefj98j0977|fyefj98j0978|fyefj98j0985|fyefj98j0992|fyefj98j1008|fyefj98j1009|fyefj98j1010|fyefj98j1011|fyefj98j1012|fyefj98j1019|fyefj98j1021|fyefj98j1028|fyefj98j1034|fyefj98j1039|fyefj98j1046|fyefj98j1047|fyefj98j1048|fyefj98j1054|fyefj98j1055|fyefj98j1064|fyefj98j1068|fyefj98j1077|fyefj98j1079|fyefj98j1080|fyefj98j1081|fyefj98j1082|fyefj98j1084|fyefj98j1087|fyefj98j1088|fyefj98j1090|fyefj99j0010|fyefj99j0188|fyefj99j0243|fyefj99j0268|fyefj99j0280|fyefj99j0301|fyefj99j0329|fyefj99j0343|fyefj99j0344|fyefj99j0380|fyefj99j0552|fyefj99j0573|fyefj99j0584|fyefj99j0586|fyefj99j0604|fyefj99j0671|fyefj99j0673|fyefj99j0676|fyefj99j0677|fyefj99j0678|fyefj99j0694|fyefj99j0722|fyefj99j0757|fyefj99j0758|fyefj99j0771|fyefj99j0772|fyefj99j0804|fyefj99j0806|fyefj99j0809|fyefj99j0814|fyefj99j0825|fyefj99j0836|fyefj99j0862|fyefj99j0863|fyefj99j0865|fyefj99j0866|fyefj99j0867|fyefj99j0875|fyefj99j0896|fyefj99j0898|fyefj99j0901|fyefj99j0906|fyefj99j0907|fyefj99j0908|fyefj99j0910|fyefj99j0912|fyefj99j0913|fyefj99j0914|fyefj99j0921|fyefj99j0922|fyefj99j0923|fyefj99j0931|fyefj99j0934|fyefj99j0936|fyefj99j0937|fyefj99j0949|fyefj99j0951|fyefj99j0952|fyefj99j0962|fyefj99j0963|fyefj99j0965|fyefj99j0966|fyefj99j0969|fyefj99j0971|fyefj99j0972|fyefj99j0974|fyefj99j0975|fyefj99j0976|fyefj99j0977|fyefj99j0978|fyefj99j0982|fyefj99j0985|fyefj99j0986|fyefj99j0988|fyefj99j0991|fyefj99j0992|fyefj99j0995|fyefj99j0997|fyefj99j0999|fyefj99j1003|fyefj99j1006|fyefj99j1008|fyefj99j1009|fyefj99j1010|fyefj99j1011|fyefj99j1016|fyefj99j1019|fyefj99j1020|fyefj99j1021|fyefj99j1024|fyefj99j1026|fyefj99j1028|fyefj99j1031|fyefj99j1033|fyefj99j1034|fyefj99j1036|fyefj99j1039|fyefj99j1042|fyefj99j1045|fyefj99j1046|fyefj99j1048|fyefj99j1053|fyefj99j1054|fyefj99j1055|fyefj99j1061|fyefj99j1062|fyefj99j1063|fyefj99j1064|fyefj99j1068|fyefj99j1072|fyefj99j1076|fyefj99j1077|fyefj99j1079|fyefj99j1080|fyefj99j1081|fyefj99j1083|fyefj99j1084|fyefj99j1087|fyefj99j1088|fyefm00j0113|fyefm01j0057|fyefm01j0088|fyefm01j0091|fyefm01j0101|fyefm01j0104|fyefm01j0107|fyefm01j0112|fyefm01j0379|fyefm02j0057|fyefm02j0101|fyefm02j0104|fyefm02j0107|fyefm02j0112|fyefm02j0379|fyefm98j0066|fyefm99j0066|fyefm99j0090|fyefm99j0093|fyefm99j0110|fyefm99j0165|fyefm99j0208|fyefm99j0209|fyefm99j0295|fyefm99j0401|fyefm99j0402|fyefm99j0907|fyefm99j1054|fyefn98j0015|fyefn98j0024|fyefn98j0030|fyefn99j0015|fyefn99j0024|fyefn99j0030|fyefr94j0559|fyefr95j0559|fyefr96j0559|fyefr97j0559|fyefr98j0559|fyefr99j0012|fyefr99j0559|fyefb01305|fyeff00j0170|fyeff00j0224|fyeff00j0227|fyeff00j0228|fyeff00j0229|fyeff00j0280|fyeff00j0281|fyeff00j0282|fyeff00j0283|fyeff00j0288|fyeff00j0289|fyeff00j0331|fyeff00j0332|fyeff00j0333|fyeff00j0334|fyeff00j0335|fyeff00j0336|fyeff00j0337|fyeff00j0338|fyeff00j0346|fyeff00j0347|fyeff00j0348|fyeff00j0349|fyeff00j0350|fyeff00j0351|fyeff00j0357|fyeff00j0358|fyeff00j0371|fyeff00j0372|fyeff00j0396|fyeff00j0397|fyeff00j0424|fyeff00j0425|fyeff01j0416|fyeff02j0416|fyeff78j0418|fyeff79j0418|fyeff79j1051|fyeff80j1051|fyeff81j1051|fyeff82j1051|fyeff83j1051|fyeff84j1051|fyeff85j1051|fyeff86j1051|fyeff87j1051|fyeff88j0422|fyeff89j0422|fyeff90j0422|fyeff90j0434|fyeff90j0440|fyeff91j0422|fyeff91j0434|fyeff91j0440|fyeff92j0440|fyeff93j0440|fyeff93j1045|fyeff93j1067|fyeff94j0392|fyeff94j0440|fyeff94j0443|fyeff94j1045|fyeff94j1067|fyeff95j0219|fyeff95j0392|fyeff95j0439|fyeff95j0440|fyeff95j0443|fyeff96j0053|fyeff96j0219|fyeff96j0392|fyeff96j0429|fyeff96j0434|fyeff96j0950|fyeff96j1019|fyeff96j1028|fyeff97j0053|fyeff97j0178|fyeff97j0191|fyeff97j0219|fyeff97j0221|fyeff97j0258|fyeff97j0324|fyeff97j0355|fyeff97j0370|fyeff97j0377|fyeff97j0392|fyeff97j0429|fyeff97j0434|fyeff97j0950|fyeff97j1019|fyeff98j0053|fyeff98j0065|fyeff98j0101|fyeff98j0144|fyeff98j0156|fyeff98j0178|fyeff98j0191|fyeff98j0193|fyeff98j0196|fyeff98j0197|fyeff98j0209|fyeff98j0210|fyeff98j0211|fyeff98j0214|fyeff98j0215|fyeff98j0218|fyeff98j0219|fyeff98j0221|fyeff98j0258|fyeff98j0260|fyeff98j0279|fyeff98j0284|fyeff98j0295|fyeff98j0296|fyeff98j0298|fyeff98j0324|fyeff98j0355|fyeff98j0370|fyeff98j0376|fyeff98j0379|fyeff98j0381|fyeff98j0392|fyeff98j0401|fyeff98j0404|fyeff98j0405|fyeff98j0407|fyeff98j0411|fyeff98j0418|fyeff98j0421|fyeff98j0423|fyeff98j0433|fyeff98j0436|fyeff98j0673|fyeff98j0896|fyeff98j0950|fyeff98j0985|fyeff98j1012|fyeff99j0053|fyeff99j0065|fyeff99j0152|fyeff99j0156|fyeff99j0159|fyeff99j0178|fyeff99j0191|fyeff99j0193|fyeff99j0196|fyeff99j0197|fyeff99j0209|fyeff99j0210|fyeff99j0211|fyeff99j0214|fyeff99j0215|fyeff99j0218|fyeff99j0219|fyeff99j0220|fyeff99j0221|fyeff99j0260|fyeff99j0279|fyeff99j0284|fyeff99j0291|fyeff99j0295|fyeff99j0296|fyeff99j0297|fyeff99j0298|fyeff99j0324|fyeff99j0339|fyeff99j0355|fyeff99j0370|fyeff99j0376|fyeff99j0379|fyeff99j0381|fyeff99j0392|fyeff99j0401|fyeff99j0404|fyeff99j0405|fyeff99j0407|fyeff99j0410|fyeff99j0411|fyeff99j0413|fyeff99j0414|fyeff99j0415|fyeff99j0418|fyeff99j0421|fyeff99j0423|fyeff99j0436|fyeff99j0673|fyeff99j0896|fyeff99j0950|fyeff99j0962|fyeff99j0985|fyeff99j1010|fyeff99j1012|fyeff99j1028|fyeff99j1090|fyeff99j1370|fayfm01j0148|fayfm01j0149|fayfm01j0155|fayfm02j0148|fayfm02j0149|fayfm02j0155|faefj00j0594|faefj00j0595|faefj00j0596|faefj00j0597|faefj01j0707|faefj02j0707|faefj03j0707|faefj90j1023|faefj91j1023|faefj92j1023|faefj94j1056|faefj95j1023|faefj95j1056|faefj96j1056|faefj98j1038|faefj99j1078|fdeff99j9001|fdeff99j9002|gyefj99j0005", + // A long case insensitive alternation. + "(?i:(zQPbMkNO|NNSPdvMi|iWuuSoAl|qbvKMimS|IecrXtPa|seTckYqt|NxnyHkgB|fIDlOgKb|UhlWIygH|OtNoJxHG|cUTkFVIV|mTgFIHjr|jQkoIDtE|PPMKxRXl|AwMfwVkQ|CQyMrTQJ|BzrqxVSi|nTpcWuhF|PertdywG|ZZDgCtXN|WWdDPyyE|uVtNQsKk|BdeCHvPZ|wshRnFlH|aOUIitIp|RxZeCdXT|CFZMslCj|AVBZRDxl|IzIGCnhw|ythYuWiz|oztXVXhl|VbLkwqQx|qvaUgyVC|VawUjPWC|ecloYJuj|boCLTdSU|uPrKeAZx|hrMWLWBq|JOnUNHRM|rYnujkPq|dDEdZhIj|DRrfvugG|yEGfDxVV|YMYdJWuP|PHUQZNWM|AmKNrLis|zTxndVfn|FPsHoJnc|EIulZTua|KlAPhdzg|ScHJJCLt|NtTfMzME|eMCwuFdo|SEpJVJbR|cdhXZeCx|sAVtBwRh|kVFEVcMI|jzJrxraA|tGLHTell|NNWoeSaw|DcOKSetX|UXZAJyka|THpMphDP|rizheevl|kDCBRidd|pCZZRqyu|pSygkitl|SwZGkAaW|wILOrfNX|QkwVOerj|kHOMxPDr|EwOVycJv|AJvtzQFS|yEOjKYYB|LizIINLL|JBRSsfcG|YPiUqqNl|IsdEbvee|MjEpGcBm|OxXZVgEQ|xClXGuxa|UzRCGFEb|buJbvfvA|IPZQxRet|oFYShsMc|oBHffuHO|bzzKrcBR|KAjzrGCl|IPUsAVls|OGMUMbIU|gyDccHuR|bjlalnDd|ZLWjeMna|fdsuIlxQ|dVXtiomV|XxedTjNg|XWMHlNoA|nnyqArQX|opfkWGhb|wYtnhdYb))", + // A long case insensitive alternation where each entry ends with ".*". + "(?i:(zQPbMkNO.*|NNSPdvMi.*|iWuuSoAl.*|qbvKMimS.*|IecrXtPa.*|seTckYqt.*|NxnyHkgB.*|fIDlOgKb.*|UhlWIygH.*|OtNoJxHG.*|cUTkFVIV.*|mTgFIHjr.*|jQkoIDtE.*|PPMKxRXl.*|AwMfwVkQ.*|CQyMrTQJ.*|BzrqxVSi.*|nTpcWuhF.*|PertdywG.*|ZZDgCtXN.*|WWdDPyyE.*|uVtNQsKk.*|BdeCHvPZ.*|wshRnFlH.*|aOUIitIp.*|RxZeCdXT.*|CFZMslCj.*|AVBZRDxl.*|IzIGCnhw.*|ythYuWiz.*|oztXVXhl.*|VbLkwqQx.*|qvaUgyVC.*|VawUjPWC.*|ecloYJuj.*|boCLTdSU.*|uPrKeAZx.*|hrMWLWBq.*|JOnUNHRM.*|rYnujkPq.*|dDEdZhIj.*|DRrfvugG.*|yEGfDxVV.*|YMYdJWuP.*|PHUQZNWM.*|AmKNrLis.*|zTxndVfn.*|FPsHoJnc.*|EIulZTua.*|KlAPhdzg.*|ScHJJCLt.*|NtTfMzME.*|eMCwuFdo.*|SEpJVJbR.*|cdhXZeCx.*|sAVtBwRh.*|kVFEVcMI.*|jzJrxraA.*|tGLHTell.*|NNWoeSaw.*|DcOKSetX.*|UXZAJyka.*|THpMphDP.*|rizheevl.*|kDCBRidd.*|pCZZRqyu.*|pSygkitl.*|SwZGkAaW.*|wILOrfNX.*|QkwVOerj.*|kHOMxPDr.*|EwOVycJv.*|AJvtzQFS.*|yEOjKYYB.*|LizIINLL.*|JBRSsfcG.*|YPiUqqNl.*|IsdEbvee.*|MjEpGcBm.*|OxXZVgEQ.*|xClXGuxa.*|UzRCGFEb.*|buJbvfvA.*|IPZQxRet.*|oFYShsMc.*|oBHffuHO.*|bzzKrcBR.*|KAjzrGCl.*|IPUsAVls.*|OGMUMbIU.*|gyDccHuR.*|bjlalnDd.*|ZLWjeMna.*|fdsuIlxQ.*|dVXtiomV.*|XxedTjNg.*|XWMHlNoA.*|nnyqArQX.*|opfkWGhb.*|wYtnhdYb.*))", + // A long case insensitive alternation where each entry starts with ".*". + "(?i:(.*zQPbMkNO|.*NNSPdvMi|.*iWuuSoAl|.*qbvKMimS|.*IecrXtPa|.*seTckYqt|.*NxnyHkgB|.*fIDlOgKb|.*UhlWIygH|.*OtNoJxHG|.*cUTkFVIV|.*mTgFIHjr|.*jQkoIDtE|.*PPMKxRXl|.*AwMfwVkQ|.*CQyMrTQJ|.*BzrqxVSi|.*nTpcWuhF|.*PertdywG|.*ZZDgCtXN|.*WWdDPyyE|.*uVtNQsKk|.*BdeCHvPZ|.*wshRnFlH|.*aOUIitIp|.*RxZeCdXT|.*CFZMslCj|.*AVBZRDxl|.*IzIGCnhw|.*ythYuWiz|.*oztXVXhl|.*VbLkwqQx|.*qvaUgyVC|.*VawUjPWC|.*ecloYJuj|.*boCLTdSU|.*uPrKeAZx|.*hrMWLWBq|.*JOnUNHRM|.*rYnujkPq|.*dDEdZhIj|.*DRrfvugG|.*yEGfDxVV|.*YMYdJWuP|.*PHUQZNWM|.*AmKNrLis|.*zTxndVfn|.*FPsHoJnc|.*EIulZTua|.*KlAPhdzg|.*ScHJJCLt|.*NtTfMzME|.*eMCwuFdo|.*SEpJVJbR|.*cdhXZeCx|.*sAVtBwRh|.*kVFEVcMI|.*jzJrxraA|.*tGLHTell|.*NNWoeSaw|.*DcOKSetX|.*UXZAJyka|.*THpMphDP|.*rizheevl|.*kDCBRidd|.*pCZZRqyu|.*pSygkitl|.*SwZGkAaW|.*wILOrfNX|.*QkwVOerj|.*kHOMxPDr|.*EwOVycJv|.*AJvtzQFS|.*yEOjKYYB|.*LizIINLL|.*JBRSsfcG|.*YPiUqqNl|.*IsdEbvee|.*MjEpGcBm|.*OxXZVgEQ|.*xClXGuxa|.*UzRCGFEb|.*buJbvfvA|.*IPZQxRet|.*oFYShsMc|.*oBHffuHO|.*bzzKrcBR|.*KAjzrGCl|.*IPUsAVls|.*OGMUMbIU|.*gyDccHuR|.*bjlalnDd|.*ZLWjeMna|.*fdsuIlxQ|.*dVXtiomV|.*XxedTjNg|.*XWMHlNoA|.*nnyqArQX|.*opfkWGhb|.*wYtnhdYb))", + // Quest ".?". + "fo.?", + "foo.?", + "f.?o", + ".*foo.?", + ".?foo.+", + "foo.?|bar", } + values = []string{ + "foo", " foo bar", "bar", "buzz\nbar", "bar foo", "bfoo", "\n", "\nfoo", "foo\n", "hello foo world", "hello foo\n world", "", + "FOO", "Foo", "OO", "Oo", "\nfoo\n", strings.Repeat("f", 20), "prometheus", "prometheus_api_v1", "prometheus_api_v1_foo", + "10.0.1.20", "10.0.2.10", "10.0.3.30", "10.0.4.40", + "foofoo0", "foofoo", - for _, c := range cases { - m, err := NewFastRegexMatcher(c.regex) - require.NoError(t, err) - require.Equal(t, c.expected, m.MatchString(c.value)) + // Values matching / not matching the test regexps on long alternations. + "zQPbMkNO", "zQPbMkNo", "jyyfj00j0061", "jyyfj00j006", "jyyfj00j00612", "NNSPdvMi", "NNSPdvMiXXX", "NNSPdvMixxx", "nnSPdvMi", "nnSPdvMiXXX", + } +) + +func TestFastRegexMatcher_MatchString(t *testing.T) { + // Run the test both against a set of predefined values and a set of random ones. + testValues := append([]string{}, values...) + testValues = append(testValues, generateRandomValues()...) + + for _, r := range regexes { + r := r + for _, v := range testValues { + v := v + t.Run(r+` on "`+v+`"`, func(t *testing.T) { + t.Parallel() + m, err := NewFastRegexMatcher(r) + require.NoError(t, err) + re := regexp.MustCompile("^(?:" + r + ")$") + require.Equal(t, re.MatchString(v), m.MatchString(v)) + }) + } } } @@ -85,6 +136,9 @@ func TestOptimizeConcatRegex(t *testing.T) { {regex: "(?i).*(?-i:abc)def", prefix: "", suffix: "", contains: "abc"}, {regex: ".*(?msU:abc).*", prefix: "", suffix: "", contains: "abc"}, {regex: "[aA]bc.*", prefix: "", suffix: "", contains: "bc"}, + {regex: "^5..$", prefix: "5", suffix: "", contains: ""}, + {regex: "^release.*", prefix: "release", suffix: "", contains: ""}, + {regex: "^env-[0-9]+laio[1]?[^0-9].*", prefix: "env-", suffix: "", contains: "laio"}, } for _, c := range cases { @@ -98,41 +152,906 @@ func TestOptimizeConcatRegex(t *testing.T) { } } -func BenchmarkFastRegexMatcher(b *testing.B) { - var ( - x = strings.Repeat("x", 50) - y = "foo" + x - z = x + "foo" - ) - regexes := []string{ - "foo", - "^foo", - "(foo|bar)", - "foo.*", - ".*foo", - "^.*foo$", - "^.+foo$", - ".*", - ".+", - "foo.+", - ".+foo", - ".*foo.*", - "(?i:foo)", - "(prometheus|api_prom)_api_v1_.+", - "((fo(bar))|.+foo)", - } - for _, r := range regexes { - r := r - b.Run(r, func(b *testing.B) { - m, err := NewFastRegexMatcher(r) - require.NoError(b, err) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = m.MatchString(x) - _ = m.MatchString(y) - _ = m.MatchString(z) +// Refer to https://github.com/prometheus/prometheus/issues/2651. +func TestFindSetMatches(t *testing.T) { + for _, c := range []struct { + pattern string + expMatches []string + expCaseSensitive bool + }{ + // Single value, coming from a `bar=~"foo"` selector. + {"foo", []string{"foo"}, true}, + {"^foo", []string{"foo"}, true}, + {"^foo$", []string{"foo"}, true}, + // Simple sets alternates. + {"foo|bar|zz", []string{"foo", "bar", "zz"}, true}, + // Simple sets alternate and concat (bar|baz is parsed as "ba[rz]"). + {"foo|bar|baz", []string{"foo", "bar", "baz"}, true}, + // Simple sets alternate and concat and capture + {"foo|bar|baz|(zz)", []string{"foo", "bar", "baz", "zz"}, true}, + // Simple sets alternate and concat and alternates with empty matches + // parsed as b(ar|(?:)|uzz) where b(?:) means literal b. + {"bar|b|buzz", []string{"bar", "b", "buzz"}, true}, + // Skip nested capture groups. + {"^((bar|b|buzz))$", []string{"bar", "b", "buzz"}, true}, + // Skip outer anchors (it's enforced anyway at the root). + {"^(bar|b|buzz)$", []string{"bar", "b", "buzz"}, true}, + {"^(?:prod|production)$", []string{"prod", "production"}, true}, + // Do not optimize regexp with inner anchors. + {"(bar|b|b^uz$z)", nil, false}, + // Do not optimize regexp with empty string matcher. + {"^$|Running", nil, false}, + // Simple sets containing escaped characters. + {"fo\\.o|bar\\?|\\^baz", []string{"fo.o", "bar?", "^baz"}, true}, + // using charclass + {"[abc]d", []string{"ad", "bd", "cd"}, true}, + // high low charset different => A(B[CD]|EF)|BC[XY] + {"ABC|ABD|AEF|BCX|BCY", []string{"ABC", "ABD", "AEF", "BCX", "BCY"}, true}, + // triple concat + {"api_(v1|prom)_push", []string{"api_v1_push", "api_prom_push"}, true}, + // triple concat with multiple alternates + {"(api|rpc)_(v1|prom)_push", []string{"api_v1_push", "api_prom_push", "rpc_v1_push", "rpc_prom_push"}, true}, + {"(api|rpc)_(v1|prom)_(push|query)", []string{"api_v1_push", "api_v1_query", "api_prom_push", "api_prom_query", "rpc_v1_push", "rpc_v1_query", "rpc_prom_push", "rpc_prom_query"}, true}, + // class starting with "-" + {"[-1-2][a-c]", []string{"-a", "-b", "-c", "1a", "1b", "1c", "2a", "2b", "2c"}, true}, + {"[1^3]", []string{"1", "3", "^"}, true}, + // OpPlus with concat + {"(.+)/(foo|bar)", nil, false}, + // Simple sets containing special characters without escaping. + {"fo.o|bar?|^baz", nil, false}, + // case sensitive wrapper. + {"(?i)foo", []string{"FOO"}, false}, + // case sensitive wrapper on alternate. + {"(?i)foo|bar|baz", []string{"FOO", "BAR", "BAZ", "BAr", "BAz"}, false}, + // mixed case sensitivity. + {"(api|rpc)_(v1|prom)_((?i)push|query)", nil, false}, + // mixed case sensitivity concatenation only without capture group. + {"api_v1_(?i)push", nil, false}, + // mixed case sensitivity alternation only without capture group. + {"api|(?i)rpc", nil, false}, + // case sensitive after unsetting insensitivity. + {"rpc|(?i)(?-i)api", []string{"rpc", "api"}, true}, + // case sensitive after unsetting insensitivity in all alternation options. + {"(?i)((?-i)api|(?-i)rpc)", []string{"api", "rpc"}, true}, + // mixed case sensitivity after unsetting insensitivity. + {"(?i)rpc|(?-i)api", nil, false}, + // too high charset combination + {"(api|rpc)_[^0-9]", nil, false}, + // too many combinations + {"[a-z][a-z]", nil, false}, + } { + c := c + t.Run(c.pattern, func(t *testing.T) { + t.Parallel() + parsed, err := syntax.Parse(c.pattern, syntax.Perl) + require.NoError(t, err) + matches, actualCaseSensitive := findSetMatches(parsed) + require.Equal(t, c.expMatches, matches) + require.Equal(t, c.expCaseSensitive, actualCaseSensitive) + + if c.expCaseSensitive { + // When the regexp is case sensitive, we want to ensure that the + // set matches are maintained in the final matcher. + r, err := NewFastRegexMatcher(c.pattern) + require.NoError(t, err) + require.Equal(t, c.expMatches, r.SetMatches()) } }) - + } +} + +func TestFastRegexMatcher_SetMatches_ShouldReturnACopy(t *testing.T) { + m, err := NewFastRegexMatcher("a|b") + require.NoError(t, err) + require.Equal(t, []string{"a", "b"}, m.SetMatches()) + + // Manipulate the returned slice. + matches := m.SetMatches() + matches[0] = "xxx" + matches[1] = "yyy" + + // Ensure that if we call SetMatches() again we get the original one. + require.Equal(t, []string{"a", "b"}, m.SetMatches()) +} + +func BenchmarkFastRegexMatcher(b *testing.B) { + texts := generateRandomValues() + + for _, r := range regexes { + b.Run(getTestNameFromRegexp(r), func(b *testing.B) { + m, err := NewFastRegexMatcher(r) + require.NoError(b, err) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, text := range texts { + _ = m.MatchString(text) + } + } + }) + } +} + +func TestStringMatcherFromRegexp(t *testing.T) { + for _, c := range []struct { + pattern string + exp StringMatcher + }{ + {".*", anyStringWithoutNewlineMatcher{}}, + {".*?", anyStringWithoutNewlineMatcher{}}, + {"(?s:.*)", trueMatcher{}}, + {"(.*)", anyStringWithoutNewlineMatcher{}}, + {"^.*$", anyStringWithoutNewlineMatcher{}}, + {".+", &anyNonEmptyStringMatcher{matchNL: false}}, + {"(?s:.+)", &anyNonEmptyStringMatcher{matchNL: true}}, + {"^.+$", &anyNonEmptyStringMatcher{matchNL: false}}, + {"(.+)", &anyNonEmptyStringMatcher{matchNL: false}}, + {"", emptyStringMatcher{}}, + {"^$", emptyStringMatcher{}}, + {"^foo$", &equalStringMatcher{s: "foo", caseSensitive: true}}, + {"^(?i:foo)$", &equalStringMatcher{s: "FOO", caseSensitive: false}}, + {"^((?i:foo)|(bar))$", orStringMatcher([]StringMatcher{&equalStringMatcher{s: "FOO", caseSensitive: false}, &equalStringMatcher{s: "bar", caseSensitive: true}})}, + {`(?i:((foo|bar)))`, orStringMatcher([]StringMatcher{&equalStringMatcher{s: "FOO", caseSensitive: false}, &equalStringMatcher{s: "BAR", caseSensitive: false}})}, + {`(?i:((foo1|foo2|bar)))`, orStringMatcher([]StringMatcher{orStringMatcher([]StringMatcher{&equalStringMatcher{s: "FOO1", caseSensitive: false}, &equalStringMatcher{s: "FOO2", caseSensitive: false}}), &equalStringMatcher{s: "BAR", caseSensitive: false}})}, + {"^((?i:foo|oo)|(bar))$", orStringMatcher([]StringMatcher{&equalStringMatcher{s: "FOO", caseSensitive: false}, &equalStringMatcher{s: "OO", caseSensitive: false}, &equalStringMatcher{s: "bar", caseSensitive: true}})}, + {"(?i:(foo1|foo2|bar))", orStringMatcher([]StringMatcher{orStringMatcher([]StringMatcher{&equalStringMatcher{s: "FOO1", caseSensitive: false}, &equalStringMatcher{s: "FOO2", caseSensitive: false}}), &equalStringMatcher{s: "BAR", caseSensitive: false}})}, + {".*foo.*", &containsStringMatcher{substrings: []string{"foo"}, left: anyStringWithoutNewlineMatcher{}, right: anyStringWithoutNewlineMatcher{}}}, + {"(.*)foo.*", &containsStringMatcher{substrings: []string{"foo"}, left: anyStringWithoutNewlineMatcher{}, right: anyStringWithoutNewlineMatcher{}}}, + {"(.*)foo(.*)", &containsStringMatcher{substrings: []string{"foo"}, left: anyStringWithoutNewlineMatcher{}, right: anyStringWithoutNewlineMatcher{}}}, + {"(.+)foo(.*)", &containsStringMatcher{substrings: []string{"foo"}, left: &anyNonEmptyStringMatcher{matchNL: false}, right: anyStringWithoutNewlineMatcher{}}}, + {"^.+foo.+", &containsStringMatcher{substrings: []string{"foo"}, left: &anyNonEmptyStringMatcher{matchNL: false}, right: &anyNonEmptyStringMatcher{matchNL: false}}}, + {"^(.*)(foo)(.*)$", &containsStringMatcher{substrings: []string{"foo"}, left: anyStringWithoutNewlineMatcher{}, right: anyStringWithoutNewlineMatcher{}}}, + {"^(.*)(foo|foobar)(.*)$", &containsStringMatcher{substrings: []string{"foo", "foobar"}, left: anyStringWithoutNewlineMatcher{}, right: anyStringWithoutNewlineMatcher{}}}, + {"^(.*)(foo|foobar)(.+)$", &containsStringMatcher{substrings: []string{"foo", "foobar"}, left: anyStringWithoutNewlineMatcher{}, right: &anyNonEmptyStringMatcher{matchNL: false}}}, + {"^(.*)(bar|b|buzz)(.+)$", &containsStringMatcher{substrings: []string{"bar", "b", "buzz"}, left: anyStringWithoutNewlineMatcher{}, right: &anyNonEmptyStringMatcher{matchNL: false}}}, + {"10\\.0\\.(1|2)\\.+", nil}, + {"10\\.0\\.(1|2).+", &containsStringMatcher{substrings: []string{"10.0.1", "10.0.2"}, left: nil, right: &anyNonEmptyStringMatcher{matchNL: false}}}, + {"^.+foo", &literalSuffixStringMatcher{left: &anyNonEmptyStringMatcher{}, suffix: "foo", suffixCaseSensitive: true}}, + {"foo-.*$", &literalPrefixStringMatcher{prefix: "foo-", prefixCaseSensitive: true, right: anyStringWithoutNewlineMatcher{}}}, + {"(prometheus|api_prom)_api_v1_.+", &containsStringMatcher{substrings: []string{"prometheus_api_v1_", "api_prom_api_v1_"}, left: nil, right: &anyNonEmptyStringMatcher{matchNL: false}}}, + {"^((.*)(bar|b|buzz)(.+)|foo)$", orStringMatcher([]StringMatcher{&containsStringMatcher{substrings: []string{"bar", "b", "buzz"}, left: anyStringWithoutNewlineMatcher{}, right: &anyNonEmptyStringMatcher{matchNL: false}}, &equalStringMatcher{s: "foo", caseSensitive: true}})}, + {"((fo(bar))|.+foo)", orStringMatcher([]StringMatcher{orStringMatcher([]StringMatcher{&equalStringMatcher{s: "fobar", caseSensitive: true}}), &literalSuffixStringMatcher{suffix: "foo", suffixCaseSensitive: true, left: &anyNonEmptyStringMatcher{matchNL: false}}})}, + {"(.+)/(gateway|cortex-gw|cortex-gw-internal)", &containsStringMatcher{substrings: []string{"/gateway", "/cortex-gw", "/cortex-gw-internal"}, left: &anyNonEmptyStringMatcher{matchNL: false}, right: nil}}, + // we don't support case insensitive matching for contains. + // This is because there's no strings.IndexOfFold function. + // We can revisit later if this is really popular by using strings.ToUpper. + {"^(.*)((?i)foo|foobar)(.*)$", nil}, + {"(api|rpc)_(v1|prom)_((?i)push|query)", nil}, + {"[a-z][a-z]", nil}, + {"[1^3]", nil}, + {".*foo.*bar.*", nil}, + {`\d*`, nil}, + {".", nil}, + {"/|/bar.*", &literalPrefixStringMatcher{prefix: "/", prefixCaseSensitive: true, right: orStringMatcher{emptyStringMatcher{}, &literalPrefixStringMatcher{prefix: "bar", prefixCaseSensitive: true, right: anyStringWithoutNewlineMatcher{}}}}}, + // This one is not supported because `stringMatcherFromRegexp` is not reentrant for syntax.OpConcat. + // It would make the code too complex to handle it. + {"(.+)/(foo.*|bar$)", nil}, + // Case sensitive alternate with same literal prefix and .* suffix. + {"(xyz-016a-ixb-dp.*|xyz-016a-ixb-op.*)", &literalPrefixStringMatcher{prefix: "xyz-016a-ixb-", prefixCaseSensitive: true, right: orStringMatcher{&literalPrefixStringMatcher{prefix: "dp", prefixCaseSensitive: true, right: anyStringWithoutNewlineMatcher{}}, &literalPrefixStringMatcher{prefix: "op", prefixCaseSensitive: true, right: anyStringWithoutNewlineMatcher{}}}}}, + // Case insensitive alternate with same literal prefix and .* suffix. + {"(?i:(xyz-016a-ixb-dp.*|xyz-016a-ixb-op.*))", &literalPrefixStringMatcher{prefix: "XYZ-016A-IXB-", prefixCaseSensitive: false, right: orStringMatcher{&literalPrefixStringMatcher{prefix: "DP", prefixCaseSensitive: false, right: anyStringWithoutNewlineMatcher{}}, &literalPrefixStringMatcher{prefix: "OP", prefixCaseSensitive: false, right: anyStringWithoutNewlineMatcher{}}}}}, + {"(?i)(xyz-016a-ixb-dp.*|xyz-016a-ixb-op.*)", &literalPrefixStringMatcher{prefix: "XYZ-016A-IXB-", prefixCaseSensitive: false, right: orStringMatcher{&literalPrefixStringMatcher{prefix: "DP", prefixCaseSensitive: false, right: anyStringWithoutNewlineMatcher{}}, &literalPrefixStringMatcher{prefix: "OP", prefixCaseSensitive: false, right: anyStringWithoutNewlineMatcher{}}}}}, + // Concatenated variable length selectors are not supported. + {"foo.*.*", nil}, + {"foo.+.+", nil}, + {".*.*foo", nil}, + {".+.+foo", nil}, + {"aaa.?.?", nil}, + {"aaa.?.*", nil}, + // Regexps with ".?". + {"ext.?|xfs", orStringMatcher{&literalPrefixStringMatcher{prefix: "ext", prefixCaseSensitive: true, right: &zeroOrOneCharacterStringMatcher{matchNL: false}}, &equalStringMatcher{s: "xfs", caseSensitive: true}}}, + {"(?s)(ext.?|xfs)", orStringMatcher{&literalPrefixStringMatcher{prefix: "ext", prefixCaseSensitive: true, right: &zeroOrOneCharacterStringMatcher{matchNL: true}}, &equalStringMatcher{s: "xfs", caseSensitive: true}}}, + {"foo.?", &literalPrefixStringMatcher{prefix: "foo", prefixCaseSensitive: true, right: &zeroOrOneCharacterStringMatcher{matchNL: false}}}, + {"f.?o", nil}, + } { + c := c + t.Run(c.pattern, func(t *testing.T) { + t.Parallel() + parsed, err := syntax.Parse(c.pattern, syntax.Perl) + require.NoError(t, err) + matches := stringMatcherFromRegexp(parsed) + require.Equal(t, c.exp, matches) + }) + } +} + +func TestStringMatcherFromRegexp_LiteralPrefix(t *testing.T) { + for _, c := range []struct { + pattern string + expectedLiteralPrefixMatchers int + expectedMatches []string + expectedNotMatches []string + }{ + // Case sensitive. + { + pattern: "(xyz-016a-ixb-dp.*|xyz-016a-ixb-op.*)", + expectedLiteralPrefixMatchers: 3, + expectedMatches: []string{"xyz-016a-ixb-dp", "xyz-016a-ixb-dpXXX", "xyz-016a-ixb-op", "xyz-016a-ixb-opXXX"}, + expectedNotMatches: []string{"XYZ-016a-ixb-dp", "xyz-016a-ixb-d", "XYZ-016a-ixb-op", "xyz-016a-ixb-o", "xyz", "dp", "xyz-016a-ixb-dp\n"}, + }, + + // Case insensitive. + { + pattern: "(?i)(xyz-016a-ixb-dp.*|xyz-016a-ixb-op.*)", + expectedLiteralPrefixMatchers: 3, + expectedMatches: []string{"xyz-016a-ixb-dp", "XYZ-016a-ixb-dpXXX", "xyz-016a-ixb-op", "XYZ-016a-ixb-opXXX"}, + expectedNotMatches: []string{"xyz-016a-ixb-d", "xyz", "dp", "xyz-016a-ixb-dp\n"}, + }, + + // Nested literal prefixes, case sensitive. + { + pattern: "(xyz-(aaa-(111.*)|bbb-(222.*)))|(xyz-(aaa-(333.*)|bbb-(444.*)))", + expectedLiteralPrefixMatchers: 10, + expectedMatches: []string{"xyz-aaa-111", "xyz-aaa-111XXX", "xyz-aaa-333", "xyz-aaa-333XXX", "xyz-bbb-222", "xyz-bbb-222XXX", "xyz-bbb-444", "xyz-bbb-444XXX"}, + expectedNotMatches: []string{"XYZ-aaa-111", "xyz-aaa-11", "xyz-aaa-222", "xyz-bbb-111"}, + }, + + // Nested literal prefixes, case insensitive. + { + pattern: "(?i)(xyz-(aaa-(111.*)|bbb-(222.*)))|(xyz-(aaa-(333.*)|bbb-(444.*)))", + expectedLiteralPrefixMatchers: 10, + expectedMatches: []string{"xyz-aaa-111", "XYZ-aaa-111XXX", "xyz-aaa-333", "xyz-AAA-333XXX", "xyz-bbb-222", "xyz-BBB-222XXX", "XYZ-bbb-444", "xyz-bbb-444XXX"}, + expectedNotMatches: []string{"xyz-aaa-11", "xyz-aaa-222", "xyz-bbb-111"}, + }, + + // Mixed case sensitivity. + { + pattern: "(xyz-((?i)(aaa.*|bbb.*)))", + expectedLiteralPrefixMatchers: 3, + expectedMatches: []string{"xyz-aaa", "xyz-AAA", "xyz-aaaXXX", "xyz-AAAXXX", "xyz-bbb", "xyz-BBBXXX"}, + expectedNotMatches: []string{"XYZ-aaa", "xyz-aa", "yz-aaa", "aaa"}, + }, + } { + t.Run(c.pattern, func(t *testing.T) { + parsed, err := syntax.Parse(c.pattern, syntax.Perl) + require.NoError(t, err) + + matcher := stringMatcherFromRegexp(parsed) + require.NotNil(t, matcher) + + re := regexp.MustCompile("^" + c.pattern + "$") + + // Pre-condition check: ensure it contains literalPrefixStringMatcher. + numPrefixMatchers := 0 + visitStringMatcher(matcher, func(matcher StringMatcher) { + if _, ok := matcher.(*literalPrefixStringMatcher); ok { + numPrefixMatchers++ + } + }) + + require.Equal(t, c.expectedLiteralPrefixMatchers, numPrefixMatchers) + + for _, value := range c.expectedMatches { + require.Truef(t, matcher.Matches(value), "Value: %s", value) + + // Ensure the golang regexp engine would return the same. + require.Truef(t, re.MatchString(value), "Value: %s", value) + } + + for _, value := range c.expectedNotMatches { + require.Falsef(t, matcher.Matches(value), "Value: %s", value) + + // Ensure the golang regexp engine would return the same. + require.Falsef(t, re.MatchString(value), "Value: %s", value) + } + }) + } +} + +func TestStringMatcherFromRegexp_LiteralSuffix(t *testing.T) { + for _, c := range []struct { + pattern string + expectedLiteralSuffixMatchers int + expectedMatches []string + expectedNotMatches []string + }{ + // Case sensitive. + { + pattern: "(.*xyz-016a-ixb-dp|.*xyz-016a-ixb-op)", + expectedLiteralSuffixMatchers: 2, + expectedMatches: []string{"xyz-016a-ixb-dp", "XXXxyz-016a-ixb-dp", "xyz-016a-ixb-op", "XXXxyz-016a-ixb-op"}, + expectedNotMatches: []string{"XYZ-016a-ixb-dp", "yz-016a-ixb-dp", "XYZ-016a-ixb-op", "xyz-016a-ixb-o", "xyz", "dp", "\nxyz-016a-ixb-dp"}, + }, + + // Case insensitive. + { + pattern: "(?i)(.*xyz-016a-ixb-dp|.*xyz-016a-ixb-op)", + expectedLiteralSuffixMatchers: 2, + expectedMatches: []string{"xyz-016a-ixb-dp", "XYZ-016a-ixb-dp", "XXXxyz-016a-ixb-dp", "XyZ-016a-ixb-op", "XXXxyz-016a-ixb-op"}, + expectedNotMatches: []string{"yz-016a-ixb-dp", "xyz-016a-ixb-o", "xyz", "dp", "\nxyz-016a-ixb-dp"}, + }, + + // Nested literal suffixes, case sensitive. + { + pattern: "(.*aaa|.*bbb(.*ccc|.*ddd))", + expectedLiteralSuffixMatchers: 3, + expectedMatches: []string{"aaa", "XXXaaa", "bbbccc", "XXXbbbccc", "XXXbbbXXXccc", "bbbddd", "bbbddd", "XXXbbbddd", "XXXbbbXXXddd", "bbbXXXccc", "aaabbbccc", "aaabbbddd"}, + expectedNotMatches: []string{"AAA", "aa", "Xaa", "BBBCCC", "bb", "Xbb", "bbccc", "bbbcc", "bbbdd"}, + }, + + // Mixed case sensitivity. + { + pattern: "(.*aaa|.*bbb((?i)(.*ccc|.*ddd)))", + expectedLiteralSuffixMatchers: 3, + expectedMatches: []string{"aaa", "XXXaaa", "bbbccc", "bbbCCC", "bbbXXXCCC", "bbbddd", "bbbDDD", "bbbXXXddd", "bbbXXXDDD"}, + expectedNotMatches: []string{"AAA", "XXXAAA", "BBBccc", "BBBCCC", "aaaBBB"}, + }, + } { + t.Run(c.pattern, func(t *testing.T) { + parsed, err := syntax.Parse(c.pattern, syntax.Perl) + require.NoError(t, err) + + matcher := stringMatcherFromRegexp(parsed) + require.NotNil(t, matcher) + + re := regexp.MustCompile("^" + c.pattern + "$") + + // Pre-condition check: ensure it contains literalSuffixStringMatcher. + numSuffixMatchers := 0 + visitStringMatcher(matcher, func(matcher StringMatcher) { + if _, ok := matcher.(*literalSuffixStringMatcher); ok { + numSuffixMatchers++ + } + }) + + require.Equal(t, c.expectedLiteralSuffixMatchers, numSuffixMatchers) + + for _, value := range c.expectedMatches { + require.Truef(t, matcher.Matches(value), "Value: %s", value) + + // Ensure the golang regexp engine would return the same. + require.Truef(t, re.MatchString(value), "Value: %s", value) + } + + for _, value := range c.expectedNotMatches { + require.Falsef(t, matcher.Matches(value), "Value: %s", value) + + // Ensure the golang regexp engine would return the same. + require.Falsef(t, re.MatchString(value), "Value: %s", value) + } + }) + } +} + +func TestStringMatcherFromRegexp_Quest(t *testing.T) { + for _, c := range []struct { + pattern string + expectedZeroOrOneMatchers int + expectedMatches []string + expectedNotMatches []string + }{ + // Not match newline. + { + pattern: "test.?", + expectedZeroOrOneMatchers: 1, + expectedMatches: []string{"test", "test!"}, + expectedNotMatches: []string{"test\n", "tes", "test!!"}, + }, + { + pattern: ".?test", + expectedZeroOrOneMatchers: 1, + expectedMatches: []string{"test", "!test"}, + expectedNotMatches: []string{"\ntest", "tes", "test!"}, + }, + { + pattern: "(aaa.?|bbb.?)", + expectedZeroOrOneMatchers: 2, + expectedMatches: []string{"aaa", "aaaX", "bbb", "bbbX"}, + expectedNotMatches: []string{"aa", "aaaXX", "aaa\n", "bb", "bbbXX", "bbb\n"}, + }, + { + pattern: ".*aaa.?", + expectedZeroOrOneMatchers: 1, + expectedMatches: []string{"aaa", "Xaaa", "aaaX", "XXXaaa", "XXXaaaX"}, + expectedNotMatches: []string{"aa", "aaaXX", "XXXaaaXXX", "XXXaaa\n"}, + }, + + // Match newline. + { + pattern: "(?s)test.?", + expectedZeroOrOneMatchers: 1, + expectedMatches: []string{"test", "test!", "test\n"}, + expectedNotMatches: []string{"tes", "test!!", "test\n\n"}, + }, + + // Mixed flags (a part matches newline another doesn't). + { + pattern: "(aaa.?|((?s).?bbb.+))", + expectedZeroOrOneMatchers: 2, + expectedMatches: []string{"aaa", "aaaX", "bbbX", "XbbbX", "bbbXXX", "\nbbbX"}, + expectedNotMatches: []string{"aa", "aaa\n", "Xbbb", "\nbbb"}, + }, + } { + t.Run(c.pattern, func(t *testing.T) { + parsed, err := syntax.Parse(c.pattern, syntax.Perl) + require.NoError(t, err) + + matcher := stringMatcherFromRegexp(parsed) + require.NotNil(t, matcher) + + re := regexp.MustCompile("^" + c.pattern + "$") + + // Pre-condition check: ensure it contains zeroOrOneCharacterStringMatcher. + numZeroOrOneMatchers := 0 + visitStringMatcher(matcher, func(matcher StringMatcher) { + if _, ok := matcher.(*zeroOrOneCharacterStringMatcher); ok { + numZeroOrOneMatchers++ + } + }) + + require.Equal(t, c.expectedZeroOrOneMatchers, numZeroOrOneMatchers) + + for _, value := range c.expectedMatches { + require.Truef(t, matcher.Matches(value), "Value: %s", value) + + // Ensure the golang regexp engine would return the same. + require.Truef(t, re.MatchString(value), "Value: %s", value) + } + + for _, value := range c.expectedNotMatches { + require.Falsef(t, matcher.Matches(value), "Value: %s", value) + + // Ensure the golang regexp engine would return the same. + require.Falsef(t, re.MatchString(value), "Value: %s", value) + } + }) + } +} + +func randString(randGenerator *rand.Rand, length int) string { + b := make([]rune, length) + for i := range b { + b[i] = asciiRunes[randGenerator.Intn(len(asciiRunes))] + } + return string(b) +} + +func randStrings(randGenerator *rand.Rand, many, length int) []string { + out := make([]string, 0, many) + for i := 0; i < many; i++ { + out = append(out, randString(randGenerator, length)) + } + return out +} + +func TestOptimizeEqualStringMatchers(t *testing.T) { + tests := map[string]struct { + input StringMatcher + expectedValues []string + expectedCaseSensitive bool + }{ + "should skip optimization on orStringMatcher with containsStringMatcher": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: true}, + &containsStringMatcher{substrings: []string{"a", "b", "c"}}, + }, + expectedValues: nil, + }, + "should run optimization on orStringMatcher with equalStringMatcher and same case sensitivity": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: true}, + &equalStringMatcher{s: "bar", caseSensitive: true}, + &equalStringMatcher{s: "baz", caseSensitive: true}, + }, + expectedValues: []string{"FOO", "bar", "baz"}, + expectedCaseSensitive: true, + }, + "should skip optimization on orStringMatcher with equalStringMatcher but different case sensitivity": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: true}, + &equalStringMatcher{s: "bar", caseSensitive: false}, + &equalStringMatcher{s: "baz", caseSensitive: true}, + }, + expectedValues: nil, + }, + "should run optimization on orStringMatcher with nested orStringMatcher and equalStringMatcher, and same case sensitivity": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: true}, + orStringMatcher{ + &equalStringMatcher{s: "bar", caseSensitive: true}, + &equalStringMatcher{s: "xxx", caseSensitive: true}, + }, + &equalStringMatcher{s: "baz", caseSensitive: true}, + }, + expectedValues: []string{"FOO", "bar", "xxx", "baz"}, + expectedCaseSensitive: true, + }, + "should skip optimization on orStringMatcher with nested orStringMatcher and equalStringMatcher, but different case sensitivity": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: true}, + orStringMatcher{ + // Case sensitivity is different within items at the same level. + &equalStringMatcher{s: "bar", caseSensitive: true}, + &equalStringMatcher{s: "xxx", caseSensitive: false}, + }, + &equalStringMatcher{s: "baz", caseSensitive: true}, + }, + expectedValues: nil, + }, + "should skip optimization on orStringMatcher with nested orStringMatcher and equalStringMatcher, but different case sensitivity in the nested one": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: true}, + // Case sensitivity is different between the parent and child. + orStringMatcher{ + &equalStringMatcher{s: "bar", caseSensitive: false}, + &equalStringMatcher{s: "xxx", caseSensitive: false}, + }, + &equalStringMatcher{s: "baz", caseSensitive: true}, + }, + expectedValues: nil, + }, + "should return unchanged values on few case insensitive matchers": { + input: orStringMatcher{ + &equalStringMatcher{s: "FOO", caseSensitive: false}, + orStringMatcher{ + &equalStringMatcher{s: "bAr", caseSensitive: false}, + }, + &equalStringMatcher{s: "baZ", caseSensitive: false}, + }, + expectedValues: []string{"FOO", "bAr", "baZ"}, + expectedCaseSensitive: false, + }, + } + + for testName, testData := range tests { + t.Run(testName, func(t *testing.T) { + actualMatcher := optimizeEqualStringMatchers(testData.input, 0) + + if testData.expectedValues == nil { + require.IsType(t, testData.input, actualMatcher) + } else { + require.IsType(t, &equalMultiStringSliceMatcher{}, actualMatcher) + require.Equal(t, testData.expectedValues, actualMatcher.(*equalMultiStringSliceMatcher).values) + require.Equal(t, testData.expectedCaseSensitive, actualMatcher.(*equalMultiStringSliceMatcher).caseSensitive) + } + }) + } +} + +func TestNewEqualMultiStringMatcher(t *testing.T) { + tests := map[string]struct { + values []string + caseSensitive bool + expectedValuesMap map[string]struct{} + expectedValuesList []string + }{ + "few case sensitive values": { + values: []string{"a", "B"}, + caseSensitive: true, + expectedValuesList: []string{"a", "B"}, + }, + "few case insensitive values": { + values: []string{"a", "B"}, + caseSensitive: false, + expectedValuesList: []string{"a", "B"}, + }, + "many case sensitive values": { + values: []string{"a", "B", "c", "D", "e", "F", "g", "H", "i", "L", "m", "N", "o", "P", "q", "r"}, + caseSensitive: true, + expectedValuesMap: map[string]struct{}{"a": {}, "B": {}, "c": {}, "D": {}, "e": {}, "F": {}, "g": {}, "H": {}, "i": {}, "L": {}, "m": {}, "N": {}, "o": {}, "P": {}, "q": {}, "r": {}}, + }, + "many case insensitive values": { + values: []string{"a", "B", "c", "D", "e", "F", "g", "H", "i", "L", "m", "N", "o", "P", "q", "r"}, + caseSensitive: false, + expectedValuesMap: map[string]struct{}{"a": {}, "b": {}, "c": {}, "d": {}, "e": {}, "f": {}, "g": {}, "h": {}, "i": {}, "l": {}, "m": {}, "n": {}, "o": {}, "p": {}, "q": {}, "r": {}}, + }, + } + + for testName, testData := range tests { + t.Run(testName, func(t *testing.T) { + matcher := newEqualMultiStringMatcher(testData.caseSensitive, len(testData.values)) + for _, v := range testData.values { + matcher.add(v) + } + if testData.expectedValuesMap != nil { + require.IsType(t, &equalMultiStringMapMatcher{}, matcher) + require.Equal(t, testData.expectedValuesMap, matcher.(*equalMultiStringMapMatcher).values) + require.Equal(t, testData.caseSensitive, matcher.(*equalMultiStringMapMatcher).caseSensitive) + } + if testData.expectedValuesList != nil { + require.IsType(t, &equalMultiStringSliceMatcher{}, matcher) + require.Equal(t, testData.expectedValuesList, matcher.(*equalMultiStringSliceMatcher).values) + require.Equal(t, testData.caseSensitive, matcher.(*equalMultiStringSliceMatcher).caseSensitive) + } + }) + } +} + +func TestEqualMultiStringMatcher_Matches(t *testing.T) { + tests := map[string]struct { + values []string + caseSensitive bool + expectedMatches []string + expectedNotMatches []string + }{ + "few case sensitive values": { + values: []string{"a", "B"}, + caseSensitive: true, + expectedMatches: []string{"a", "B"}, + expectedNotMatches: []string{"A", "b"}, + }, + "few case insensitive values": { + values: []string{"a", "B"}, + caseSensitive: false, + expectedMatches: []string{"a", "A", "b", "B"}, + expectedNotMatches: []string{"c", "C"}, + }, + "many case sensitive values": { + values: []string{"a", "B", "c", "D", "e", "F", "g", "H", "i", "L", "m", "N", "o", "P", "q", "r"}, + caseSensitive: true, + expectedMatches: []string{"a", "B"}, + expectedNotMatches: []string{"A", "b"}, + }, + "many case insensitive values": { + values: []string{"a", "B", "c", "D", "e", "F", "g", "H", "i", "L", "m", "N", "o", "P", "q", "r"}, + caseSensitive: false, + expectedMatches: []string{"a", "A", "b", "B"}, + expectedNotMatches: []string{"x", "X"}, + }, + } + + for testName, testData := range tests { + t.Run(testName, func(t *testing.T) { + matcher := newEqualMultiStringMatcher(testData.caseSensitive, len(testData.values)) + for _, v := range testData.values { + matcher.add(v) + } + + for _, v := range testData.expectedMatches { + require.True(t, matcher.Matches(v), "value: %s", v) + } + for _, v := range testData.expectedNotMatches { + require.False(t, matcher.Matches(v), "value: %s", v) + } + }) + } +} + +func TestFindEqualStringMatchers(t *testing.T) { + type match struct { + s string + caseSensitive bool + } + + // Utility to call findEqualStringMatchers() and collect all callback invocations. + findEqualStringMatchersAndCollectMatches := func(input StringMatcher) (matches []match, ok bool) { + ok = findEqualStringMatchers(input, func(matcher *equalStringMatcher) bool { + matches = append(matches, match{matcher.s, matcher.caseSensitive}) + return true + }) + return + } + + t.Run("empty matcher", func(t *testing.T) { + actualMatches, actualOk := findEqualStringMatchersAndCollectMatches(emptyStringMatcher{}) + require.False(t, actualOk) + require.Empty(t, actualMatches) + }) + + t.Run("concat of literal matchers (case sensitive)", func(t *testing.T) { + actualMatches, actualOk := findEqualStringMatchersAndCollectMatches( + orStringMatcher{ + &equalStringMatcher{s: "test-1", caseSensitive: true}, + &equalStringMatcher{s: "test-2", caseSensitive: true}, + }, + ) + + require.True(t, actualOk) + require.Equal(t, []match{{"test-1", true}, {"test-2", true}}, actualMatches) + }) + + t.Run("concat of literal matchers (case insensitive)", func(t *testing.T) { + actualMatches, actualOk := findEqualStringMatchersAndCollectMatches( + orStringMatcher{ + &equalStringMatcher{s: "test-1", caseSensitive: false}, + &equalStringMatcher{s: "test-2", caseSensitive: false}, + }, + ) + + require.True(t, actualOk) + require.Equal(t, []match{{"test-1", false}, {"test-2", false}}, actualMatches) + }) + + t.Run("concat of literal matchers (mixed case)", func(t *testing.T) { + actualMatches, actualOk := findEqualStringMatchersAndCollectMatches( + orStringMatcher{ + &equalStringMatcher{s: "test-1", caseSensitive: false}, + &equalStringMatcher{s: "test-2", caseSensitive: true}, + }, + ) + + require.True(t, actualOk) + require.Equal(t, []match{{"test-1", false}, {"test-2", true}}, actualMatches) + }) +} + +// This benchmark is used to find a good threshold to use to apply the optimization +// done by optimizeEqualStringMatchers(). +func BenchmarkOptimizeEqualStringMatchers(b *testing.B) { + randGenerator := rand.New(rand.NewSource(time.Now().UnixNano())) + + // Generate variable lengths random texts to match against. + texts := append([]string{}, randStrings(randGenerator, 10, 10)...) + texts = append(texts, randStrings(randGenerator, 5, 30)...) + texts = append(texts, randStrings(randGenerator, 1, 100)...) + + for numAlternations := 2; numAlternations <= 256; numAlternations *= 2 { + for _, caseSensitive := range []bool{true, false} { + b.Run(fmt.Sprintf("alternations: %d case sensitive: %t", numAlternations, caseSensitive), func(b *testing.B) { + // Generate a regex with the expected number of alternations. + re := strings.Join(randStrings(randGenerator, numAlternations, 10), "|") + if !caseSensitive { + re = "(?i:(" + re + "))" + } + + parsed, err := syntax.Parse(re, syntax.Perl) + require.NoError(b, err) + + unoptimized := stringMatcherFromRegexpInternal(parsed) + require.IsType(b, orStringMatcher{}, unoptimized) + + optimized := optimizeEqualStringMatchers(unoptimized, 0) + if numAlternations < minEqualMultiStringMatcherMapThreshold { + require.IsType(b, &equalMultiStringSliceMatcher{}, optimized) + } else { + require.IsType(b, &equalMultiStringMapMatcher{}, optimized) + } + + b.Run("without optimizeEqualStringMatchers()", func(b *testing.B) { + for n := 0; n < b.N; n++ { + for _, t := range texts { + unoptimized.Matches(t) + } + } + }) + + b.Run("with optimizeEqualStringMatchers()", func(b *testing.B) { + for n := 0; n < b.N; n++ { + for _, t := range texts { + optimized.Matches(t) + } + } + }) + }) + } + } +} + +func TestZeroOrOneCharacterStringMatcher(t *testing.T) { + matcher := &zeroOrOneCharacterStringMatcher{matchNL: true} + require.True(t, matcher.Matches("")) + require.True(t, matcher.Matches("x")) + require.True(t, matcher.Matches("\n")) + require.False(t, matcher.Matches("xx")) + require.False(t, matcher.Matches("\n\n")) + + matcher = &zeroOrOneCharacterStringMatcher{matchNL: false} + require.True(t, matcher.Matches("")) + require.True(t, matcher.Matches("x")) + require.False(t, matcher.Matches("\n")) + require.False(t, matcher.Matches("xx")) + require.False(t, matcher.Matches("\n\n")) +} + +func TestLiteralPrefixStringMatcher(t *testing.T) { + m := &literalPrefixStringMatcher{prefix: "mar", prefixCaseSensitive: true, right: &emptyStringMatcher{}} + require.True(t, m.Matches("mar")) + require.False(t, m.Matches("marco")) + require.False(t, m.Matches("ma")) + require.False(t, m.Matches("mAr")) + + m = &literalPrefixStringMatcher{prefix: "mar", prefixCaseSensitive: false, right: &emptyStringMatcher{}} + require.True(t, m.Matches("mar")) + require.False(t, m.Matches("marco")) + require.False(t, m.Matches("ma")) + require.True(t, m.Matches("mAr")) + + m = &literalPrefixStringMatcher{prefix: "mar", prefixCaseSensitive: true, right: &equalStringMatcher{s: "co", caseSensitive: false}} + require.True(t, m.Matches("marco")) + require.True(t, m.Matches("marCO")) + require.False(t, m.Matches("MARco")) + require.False(t, m.Matches("mar")) + require.False(t, m.Matches("marcopracucci")) +} + +func TestLiteralSuffixStringMatcher(t *testing.T) { + m := &literalSuffixStringMatcher{left: &emptyStringMatcher{}, suffix: "co", suffixCaseSensitive: true} + require.True(t, m.Matches("co")) + require.False(t, m.Matches("marco")) + require.False(t, m.Matches("coo")) + require.False(t, m.Matches("Co")) + + m = &literalSuffixStringMatcher{left: &emptyStringMatcher{}, suffix: "co", suffixCaseSensitive: false} + require.True(t, m.Matches("co")) + require.False(t, m.Matches("marco")) + require.False(t, m.Matches("coo")) + require.True(t, m.Matches("Co")) + + m = &literalSuffixStringMatcher{left: &equalStringMatcher{s: "mar", caseSensitive: false}, suffix: "co", suffixCaseSensitive: true} + require.True(t, m.Matches("marco")) + require.True(t, m.Matches("MARco")) + require.False(t, m.Matches("marCO")) + require.False(t, m.Matches("mar")) + require.False(t, m.Matches("marcopracucci")) + + m = &literalSuffixStringMatcher{left: &equalStringMatcher{s: "mar", caseSensitive: false}, suffix: "co", suffixCaseSensitive: false} + require.True(t, m.Matches("marco")) + require.True(t, m.Matches("MARco")) + require.True(t, m.Matches("marCO")) + require.False(t, m.Matches("mar")) + require.False(t, m.Matches("marcopracucci")) +} + +func TestHasPrefixCaseInsensitive(t *testing.T) { + require.True(t, hasPrefixCaseInsensitive("marco", "mar")) + require.True(t, hasPrefixCaseInsensitive("mArco", "mar")) + require.True(t, hasPrefixCaseInsensitive("marco", "MaR")) + require.True(t, hasPrefixCaseInsensitive("marco", "marco")) + require.True(t, hasPrefixCaseInsensitive("mArco", "marco")) + + require.False(t, hasPrefixCaseInsensitive("marco", "a")) + require.False(t, hasPrefixCaseInsensitive("marco", "abcdefghi")) +} + +func TestHasSuffixCaseInsensitive(t *testing.T) { + require.True(t, hasSuffixCaseInsensitive("marco", "rco")) + require.True(t, hasSuffixCaseInsensitive("marco", "RcO")) + require.True(t, hasSuffixCaseInsensitive("marco", "marco")) + require.False(t, hasSuffixCaseInsensitive("marco", "a")) + require.False(t, hasSuffixCaseInsensitive("marco", "abcdefghi")) +} + +func getTestNameFromRegexp(re string) string { + if len(re) > 32 { + return re[:32] + } + return re +} + +func generateRandomValues() []string { + // Init the random seed with a constant, so that it doesn't change between runs. + randGenerator := rand.New(rand.NewSource(1)) + + // Generate variable lengths random texts to match against. + texts := append([]string{}, randStrings(randGenerator, 10, 10)...) + texts = append(texts, randStrings(randGenerator, 5, 30)...) + texts = append(texts, randStrings(randGenerator, 1, 100)...) + texts = append(texts, "foo"+randString(randGenerator, 50)) + texts = append(texts, randString(randGenerator, 50)+"foo") + + return texts +} + +func visitStringMatcher(matcher StringMatcher, callback func(matcher StringMatcher)) { + callback(matcher) + + switch casted := matcher.(type) { + case *containsStringMatcher: + if casted.left != nil { + visitStringMatcher(casted.left, callback) + } + if casted.right != nil { + visitStringMatcher(casted.right, callback) + } + + case *literalPrefixStringMatcher: + visitStringMatcher(casted.right, callback) + + case *literalSuffixStringMatcher: + visitStringMatcher(casted.left, callback) + + case orStringMatcher: + for _, entry := range casted { + visitStringMatcher(entry, callback) + } + + // No nested matchers for the folling ones. + case emptyStringMatcher: + case *equalStringMatcher: + case *equalMultiStringSliceMatcher: + case *equalMultiStringMapMatcher: + case anyStringWithoutNewlineMatcher: + case *anyNonEmptyStringMatcher: + case trueMatcher: } } From f639d7794c456c4ec1b563d5bf1576bc2f6d832b Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Thu, 25 Jan 2024 14:57:43 +0100 Subject: [PATCH 005/253] Fix TestParseExpressions Signed-off-by: Marco Pracucci --- promql/parser/parse_test.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index 6c26445e38..7150891161 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -3568,7 +3568,31 @@ func TestParseExpressions(t *testing.T) { if !test.fail { require.NoError(t, err) - require.Equal(t, test.expected, expr, "error on input '%s'", test.input) + expected := test.expected + + // The FastRegexMatcher is not comparable with a deep equal, so only compare its String() version. + if actualVector, ok := expr.(*VectorSelector); ok { + require.IsType(t, &VectorSelector{}, test.expected, "error on input '%s'", test.input) + expectedVector := test.expected.(*VectorSelector) + + require.Len(t, actualVector.LabelMatchers, len(expectedVector.LabelMatchers), "error on input '%s'", test.input) + + for i := 0; i < len(actualVector.LabelMatchers); i++ { + expectedMatcher := expectedVector.LabelMatchers[i].String() + actualMatcher := actualVector.LabelMatchers[i].String() + + require.Equal(t, expectedMatcher, actualMatcher, "unexpected label matcher '%s' on input '%s'", actualMatcher, test.input) + } + + // Make a shallow copy of the expected expr (because the test cases are defined in a global variable) + // and then reset the LabelMatcher to not compared them with the following deep equal. + expectedCopy := *expectedVector + expectedCopy.LabelMatchers = nil + expected = &expectedCopy + actualVector.LabelMatchers = nil + } + + require.Equal(t, expected, expr, "error on input '%s'", test.input) } else { require.Error(t, err) require.Contains(t, err.Error(), test.errMsg, "unexpected error on input '%s', expected '%s', got '%s'", test.input, test.errMsg, err.Error()) From a1a45990a2eae1788d311f24166b2c780ee48b80 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Thu, 25 Jan 2024 14:59:39 +0100 Subject: [PATCH 006/253] Fix TestPostingsForMatcher Signed-off-by: Marco Pracucci --- tsdb/querier_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsdb/querier_test.go b/tsdb/querier_test.go index fcedc54621..ce59c0ee77 100644 --- a/tsdb/querier_test.go +++ b/tsdb/querier_test.go @@ -3304,7 +3304,7 @@ func TestPostingsForMatcher(t *testing.T) { { // Test case for double quoted regex matcher matcher: labels.MustNewMatcher(labels.MatchRegexp, "test", "^(?:a|b)$"), - hasError: true, + hasError: false, }, } From 515890ec5307a4e8448c50589ac3fc442e0e4671 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 26 Jan 2024 06:26:52 +0100 Subject: [PATCH 007/253] Use Matcher.SetMatches() Signed-off-by: Marco Pracucci --- tsdb/querier.go | 54 ++----------------------------------- tsdb/querier_test.go | 63 -------------------------------------------- 2 files changed, 2 insertions(+), 115 deletions(-) diff --git a/tsdb/querier.go b/tsdb/querier.go index a692c98f1a..4473323414 100644 --- a/tsdb/querier.go +++ b/tsdb/querier.go @@ -18,7 +18,6 @@ import ( "errors" "fmt" "math" - "strings" "unicode/utf8" "github.com/oklog/ulid" @@ -186,55 +185,6 @@ func (q *blockChunkQuerier) Select(ctx context.Context, sortSeries bool, hints * return NewBlockChunkSeriesSet(q.blockID, q.index, q.chunks, q.tombstones, p, mint, maxt, disableTrimming) } -func findSetMatches(pattern string) []string { - // Return empty matches if the wrapper from Prometheus is missing. - if len(pattern) < 6 || pattern[:4] != "^(?:" || pattern[len(pattern)-2:] != ")$" { - return nil - } - escaped := false - sets := []*strings.Builder{{}} - init := 4 - end := len(pattern) - 2 - // If the regex is wrapped in a group we can remove the first and last parentheses - if pattern[init] == '(' && pattern[end-1] == ')' { - init++ - end-- - } - for i := init; i < end; i++ { - if escaped { - switch { - case isRegexMetaCharacter(pattern[i]): - sets[len(sets)-1].WriteByte(pattern[i]) - case pattern[i] == '\\': - sets[len(sets)-1].WriteByte('\\') - default: - return nil - } - escaped = false - } else { - switch { - case isRegexMetaCharacter(pattern[i]): - if pattern[i] == '|' { - sets = append(sets, &strings.Builder{}) - } else { - return nil - } - case pattern[i] == '\\': - escaped = true - default: - sets[len(sets)-1].WriteByte(pattern[i]) - } - } - } - matches := make([]string, 0, len(sets)) - for _, s := range sets { - if s.Len() > 0 { - matches = append(matches, s.String()) - } - } - return matches -} - // PostingsForMatchers assembles a single postings iterator against the index reader // based on the given matchers. The resulting postings are not ordered by series. func PostingsForMatchers(ctx context.Context, ix IndexReader, ms ...*labels.Matcher) (index.Postings, error) { @@ -376,7 +326,7 @@ func postingsForMatcher(ctx context.Context, ix IndexReader, m *labels.Matcher) // Fast-path for set matching. if m.Type == labels.MatchRegexp { - setMatches := findSetMatches(m.GetRegexString()) + setMatches := m.SetMatches() if len(setMatches) > 0 { return ix.Postings(ctx, m.Name, setMatches...) } @@ -407,7 +357,7 @@ func inversePostingsForMatcher(ctx context.Context, ix IndexReader, m *labels.Ma // Inverse of a MatchNotRegexp is MatchRegexp (double negation). // Fast-path for set matching. if m.Type == labels.MatchNotRegexp { - setMatches := findSetMatches(m.GetRegexString()) + setMatches := m.SetMatches() if len(setMatches) > 0 { return ix.Postings(ctx, m.Name, setMatches...) } diff --git a/tsdb/querier_test.go b/tsdb/querier_test.go index ce59c0ee77..ed7e4e3404 100644 --- a/tsdb/querier_test.go +++ b/tsdb/querier_test.go @@ -2637,69 +2637,6 @@ func BenchmarkSetMatcher(b *testing.B) { } } -// Refer to https://github.com/prometheus/prometheus/issues/2651. -func TestFindSetMatches(t *testing.T) { - cases := []struct { - pattern string - exp []string - }{ - // Single value, coming from a `bar=~"foo"` selector. - { - pattern: "^(?:foo)$", - exp: []string{ - "foo", - }, - }, - // Simple sets. - { - pattern: "^(?:foo|bar|baz)$", - exp: []string{ - "foo", - "bar", - "baz", - }, - }, - // Simple sets containing escaped characters. - { - pattern: "^(?:fo\\.o|bar\\?|\\^baz)$", - exp: []string{ - "fo.o", - "bar?", - "^baz", - }, - }, - // Simple sets containing special characters without escaping. - { - pattern: "^(?:fo.o|bar?|^baz)$", - exp: nil, - }, - // Missing wrapper. - { - pattern: "foo|bar|baz", - exp: nil, - }, - } - - for _, c := range cases { - matches := findSetMatches(c.pattern) - if len(c.exp) == 0 { - if len(matches) != 0 { - t.Errorf("Evaluating %s, unexpected result %v", c.pattern, matches) - } - } else { - if len(matches) != len(c.exp) { - t.Errorf("Evaluating %s, length of result not equal to exp", c.pattern) - } else { - for i := 0; i < len(c.exp); i++ { - if c.exp[i] != matches[i] { - t.Errorf("Evaluating %s, unexpected result %s", c.pattern, matches[i]) - } - } - } - } - } -} - func TestPostingsForMatchers(t *testing.T) { ctx := context.Background() From ec9cada56e78a3332e64beafd2874229c7503fb2 Mon Sep 17 00:00:00 2001 From: Marco Pracucci Date: Fri, 26 Jan 2024 06:35:02 +0100 Subject: [PATCH 008/253] Remove unused isRegexMetaCharacter() Signed-off-by: Marco Pracucci --- tsdb/querier.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tsdb/querier.go b/tsdb/querier.go index 4473323414..899674ef12 100644 --- a/tsdb/querier.go +++ b/tsdb/querier.go @@ -18,7 +18,6 @@ import ( "errors" "fmt" "math" - "unicode/utf8" "github.com/oklog/ulid" "golang.org/x/exp/slices" @@ -34,20 +33,6 @@ import ( "github.com/prometheus/prometheus/util/annotations" ) -// Bitmap used by func isRegexMetaCharacter to check whether a character needs to be escaped. -var regexMetaCharacterBytes [16]byte - -// isRegexMetaCharacter reports whether byte b needs to be escaped. -func isRegexMetaCharacter(b byte) bool { - return b < utf8.RuneSelf && regexMetaCharacterBytes[b%16]&(1<<(b/16)) != 0 -} - -func init() { - for _, b := range []byte(`.+*?()|[]{}^$`) { - regexMetaCharacterBytes[b%16] |= 1 << (b / 16) - } -} - type blockBaseQuerier struct { blockID ulid.ULID index IndexReader From fdd5b85e06c3bd451af32906a185748bf451e35c Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 4 Feb 2024 11:08:20 +0100 Subject: [PATCH 009/253] promql: faster range-query of label_replace and label_join These functions act on the labels only, so don't need to go step by step over the samples in a range query. Signed-off-by: Bryan Boreham --- promql/engine.go | 9 ++++ promql/functions.go | 129 +++++++++++++++++--------------------------- 2 files changed, 57 insertions(+), 81 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 02004e5f96..36132295b3 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1409,6 +1409,15 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio break } } + + // Special handling for functions that work on series not samples. + switch e.Func.Name { + case "label_replace": + return ev.evalLabelReplace(e.Args) + case "label_join": + return ev.evalLabelJoin(e.Args) + } + if !matrixArg { // Does not have a matrix argument. return ev.rangeEval(nil, func(v []parser.Value, _ [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, annotations.Annotations) { diff --git a/promql/functions.go b/promql/functions.go index fe1a5644ec..eb3eb7e562 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1321,59 +1321,47 @@ func funcChanges(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelp return append(enh.Out, Sample{F: float64(changes)}), nil } -// === label_replace(Vector parser.ValueTypeVector, dst_label, replacement, src_labelname, regex parser.ValueTypeString) (Vector, Annotations) === -func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { +// label_replace function operates only on series; does not look at timestamps or values. +func (ev *evaluator) evalLabelReplace(args parser.Expressions) (parser.Value, annotations.Annotations) { var ( - vector = vals[0].(Vector) dst = stringFromArg(args[1]) repl = stringFromArg(args[2]) src = stringFromArg(args[3]) regexStr = stringFromArg(args[4]) ) - if enh.regex == nil { - var err error - enh.regex, err = regexp.Compile("^(?:" + regexStr + ")$") - if err != nil { - panic(fmt.Errorf("invalid regular expression in label_replace(): %s", regexStr)) - } - if !model.LabelNameRE.MatchString(dst) { - panic(fmt.Errorf("invalid destination label name in label_replace(): %s", dst)) - } - enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out)) + regex, err := regexp.Compile("^(?:" + regexStr + ")$") + if err != nil { + panic(fmt.Errorf("invalid regular expression in label_replace(): %s", regexStr)) + } + if !model.LabelNameRE.MatchString(dst) { + panic(fmt.Errorf("invalid destination label name in label_replace(): %s", dst)) } - for _, el := range vector { - h := el.Metric.Hash() - var outMetric labels.Labels - if l, ok := enh.Dmn[h]; ok { - outMetric = l - } else { - srcVal := el.Metric.Get(src) - indexes := enh.regex.FindStringSubmatchIndex(srcVal) - if indexes == nil { - // If there is no match, no replacement should take place. - outMetric = el.Metric - enh.Dmn[h] = outMetric - } else { - res := enh.regex.ExpandString([]byte{}, repl, srcVal, indexes) + val, ws := ev.eval(args[0]) + matrix := val.(Matrix) + lb := labels.NewBuilder(labels.EmptyLabels()) - lb := labels.NewBuilder(el.Metric).Del(dst) - if len(res) > 0 { - lb.Set(dst, string(res)) - } - outMetric = lb.Labels() - enh.Dmn[h] = outMetric - } + for i, el := range matrix { + srcVal := el.Metric.Get(src) + indexes := regex.FindStringSubmatchIndex(srcVal) + if indexes != nil { // Only replace when regexp matches. + res := regex.ExpandString([]byte{}, repl, srcVal, indexes) + lb.Reset(el.Metric) + lb.Set(dst, string(res)) + matrix[i].Metric = lb.Labels() } - - enh.Out = append(enh.Out, Sample{ - Metric: outMetric, - F: el.F, - H: el.H, - }) } - return enh.Out, nil + if matrix.ContainsSameLabelset() { + ev.errorf("vector cannot contain metrics with the same labelset") + } + + return matrix, ws +} + +// === label_replace(Vector parser.ValueTypeVector, dst_label, replacement, src_labelname, regex parser.ValueTypeString) (Vector, Annotations) === +func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { + panic("funcLabelReplace wrong implementation called") } // === Vector(s Scalar) (Vector, Annotations) === @@ -1385,19 +1373,13 @@ func funcVector(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe }), nil } -// === label_join(vector model.ValVector, dest_labelname, separator, src_labelname...) (Vector, Annotations) === -func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { +// label_join function operates only on series; does not look at timestamps or values. +func (ev *evaluator) evalLabelJoin(args parser.Expressions) (parser.Value, annotations.Annotations) { var ( - vector = vals[0].(Vector) dst = stringFromArg(args[1]) sep = stringFromArg(args[2]) srcLabels = make([]string, len(args)-3) ) - - if enh.Dmn == nil { - enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out)) - } - for i := 3; i < len(args); i++ { src := stringFromArg(args[i]) if !model.LabelName(src).IsValid() { @@ -1406,42 +1388,27 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe srcLabels[i-3] = src } - if !model.LabelName(dst).IsValid() { - panic(fmt.Errorf("invalid destination label name in label_join(): %s", dst)) - } - + val, ws := ev.eval(args[0]) + matrix := val.(Matrix) srcVals := make([]string, len(srcLabels)) - for _, el := range vector { - h := el.Metric.Hash() - var outMetric labels.Labels - if l, ok := enh.Dmn[h]; ok { - outMetric = l - } else { + lb := labels.NewBuilder(labels.EmptyLabels()) - for i, src := range srcLabels { - srcVals[i] = el.Metric.Get(src) - } - - lb := labels.NewBuilder(el.Metric) - - strval := strings.Join(srcVals, sep) - if strval == "" { - lb.Del(dst) - } else { - lb.Set(dst, strval) - } - - outMetric = lb.Labels() - enh.Dmn[h] = outMetric + for i, el := range matrix { + for i, src := range srcLabels { + srcVals[i] = el.Metric.Get(src) } - - enh.Out = append(enh.Out, Sample{ - Metric: outMetric, - F: el.F, - H: el.H, - }) + strval := strings.Join(srcVals, sep) + lb.Reset(el.Metric) + lb.Set(dst, strval) + matrix[i].Metric = lb.Labels() } - return enh.Out, nil + + return matrix, ws +} + +// === label_join(vector model.ValVector, dest_labelname, separator, src_labelname...) (Vector, Annotations) === +func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { + panic("funcLabelReplace wrong implementation called") } // Common code for date related functions. From d3c1f0d8e061ea098ff209103e90069dc7612a5d Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 4 Feb 2024 11:32:26 +0100 Subject: [PATCH 010/253] promql: can now remove regex field from EvalNodeHelper Signed-off-by: Bryan Boreham --- promql/engine.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 36132295b3..cc2a54318a 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -30,7 +30,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" - "github.com/grafana/regexp" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" "go.opentelemetry.io/otel" @@ -1080,8 +1079,6 @@ type EvalNodeHelper struct { Dmn map[uint64]labels.Labels // funcHistogramQuantile for classic histograms. signatureToMetricWithBuckets map[string]*metricWithBuckets - // label_replace. - regex *regexp.Regexp lb *labels.Builder lblBuf []byte From 452f4c96b790f2ed1d25c2f7daff2ac92a92448c Mon Sep 17 00:00:00 2001 From: Augustin Husson Date: Tue, 13 Feb 2024 10:21:23 +0100 Subject: [PATCH 011/253] Cut v2.50.0-rc.0 (#13465) Signed-off-by: Augustin Husson --- CHANGELOG.md | 27 ++++++++++++++++++++ VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 +-- 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f71eb49ba..c1f8bf8003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## 2.50.0-rc.0 / 2024-02-07 + +* [CHANGE] Remote Write: Error `storage.ErrTooOldSample` is now generating HTTP error 400 instead of HTTP error 500. #13335 +* [FEATURE] Remote Write: Drop old inmemory samples. Activated using the config entry `sample_age_limit`. #13002 +* [FEATURE] **Experimental**: Add support for ingesting zeros as created timestamps. (enabled under the feature-flag `created-timestamp-zero-ingestion`). #12733 #13279 +* [FEATURE] Promtool: Add `analyze` histograms command. #12331 +* [FEATURE] TSDB/compaction: Add a way to enable overlapping compaction. #13282 #13393 #13398 +* [FEATURE] Add automatic memory limit handling. Activated using the feature flag. `auto-gomemlimit` #13395 +* [ENHANCEMENT] Promtool: allow specifying multiple matchers in `promtool tsdb dump`. #13296 +* [ENHANCEMENT] PromQL: Restore more efficient version of `NewPossibleNonCounterInfo` annotation. #13022 +* [ENHANCEMENT] Kuma SD: Extend configuration to allow users to specify client ID. #13278 +* [ENHANCEMENT] PromQL: Use natural sort in `sort_by_label` and `sort_by_label_desc`. This is **experimental**. #13411 +* [ENHANCEMENT] Native Histograms: support `native_histogram_min_bucket_factor` in scrape_config. #13222 +* [ENHANCEMENT] Native Histograms: Issue warning if histogramRate is applied to the wrong kind of histogram. #13392 +* [ENHANCEMENT] TSDB: Make transaction isolation data structures smaller. #13015 +* [ENHANCEMENT] TSDB/postings: Optimize merge using Loser Tree. #12878 +* [ENHANCEMENT] TSDB: Simplify internal series delete function. #13261 +* [ENHANCEMENT] Agent: Performance improvement by making the global hash lookup table smaller. #13262 +* [ENHANCEMENT] PromQL: faster execution of metric functions, e.g. abs(), rate() #13446 +* [ENHANCEMENT] TSDB: Optimize label values with matchers by taking shortcuts. #13426 +* [ENHANCEMENT] Kubernetes SD: Check preconditions earlier and avoid unnecessary checks or iterations in kube_sd. #13408 +* [ENHANCEMENT] Promtool: Improve visibility for `promtool test rules` with JSON colored formatting. #13342 +* [ENHANCEMENT] Consoles: Exclude iowait and steal from CPU Utilisation. #9593 +* [ENHANCEMENT] Various improvements and optimizations on Native Histograms. #13267, #13215, #13276 #13289, #13340 +* [BUGFIX] Scraping: Fix quality value in HTTP Accept header. #13313 +* [BUGFIX] UI: Fix usage of the function `time()` that was crashing. #13371 + ## 2.49.1 / 2024-01-15 * [BUGFIX] TSDB: Fixed a wrong `q=` value in scrape accept header #13313 diff --git a/VERSION b/VERSION index f5518081bd..9f02570d13 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.49.1 +2.50.0-rc.0 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index fb13605825..bfbdd56e23 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.49.1", + "version": "0.50.0-rc.0", "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.49.1", + "@prometheus-io/lezer-promql": "0.50.0-rc.0", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index a6bb3f3eb8..aca68a67a0 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.49.1", + "version": "0.50.0-rc.0", "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 5f1db6ce0a..b2d136ceb9 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.49.1", + "version": "0.50.0-rc.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.49.1", + "version": "0.50.0-rc.0", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.49.1", + "version": "0.50.0-rc.0", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.49.1", + "@prometheus-io/lezer-promql": "0.50.0-rc.0", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.49.1", + "version": "0.50.0-rc.0", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.49.1", + "version": "0.50.0-rc.0", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.49.1", + "@prometheus-io/codemirror-promql": "0.50.0-rc.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index 026c1663b3..86a18f466a 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.49.1" + "version": "0.50.0-rc.0" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index 33fccf5c7c..4bd707e98b 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.49.1", + "version": "0.50.0-rc.0", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.49.1", + "@prometheus-io/codemirror-promql": "0.50.0-rc.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 0e8a2e44a4c54f70d1de052d52bb1304148ddfa5 Mon Sep 17 00:00:00 2001 From: Darshan Chaudhary Date: Wed, 14 Feb 2024 22:29:01 +0530 Subject: [PATCH 012/253] Azure SD: check for nil before accessing and dereferencing (#13578) Signed-off-by: darshanime --- discovery/azure/azure.go | 16 +++++- discovery/azure/azure_test.go | 101 ++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index e5e6109b25..a5d81f4ff6 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -569,7 +569,7 @@ func (client *azureClient) getScaleSetVMs(ctx context.Context, scaleSet armcompu } func mapFromVM(vm armcompute.VirtualMachine) virtualMachine { - osType := string(*vm.Properties.StorageProfile.OSDisk.OSType) + var osType string tags := map[string]*string{} networkInterfaces := []string{} var computerName string @@ -580,6 +580,12 @@ func mapFromVM(vm armcompute.VirtualMachine) virtualMachine { } if vm.Properties != nil { + if vm.Properties.StorageProfile != nil && + vm.Properties.StorageProfile.OSDisk != nil && + vm.Properties.StorageProfile.OSDisk.OSType != nil { + osType = string(*vm.Properties.StorageProfile.OSDisk.OSType) + } + if vm.Properties.NetworkProfile != nil { for _, vmNIC := range vm.Properties.NetworkProfile.NetworkInterfaces { networkInterfaces = append(networkInterfaces, *vmNIC.ID) @@ -608,7 +614,7 @@ func mapFromVM(vm armcompute.VirtualMachine) virtualMachine { } func mapFromVMScaleSetVM(vm armcompute.VirtualMachineScaleSetVM, scaleSetName string) virtualMachine { - osType := string(*vm.Properties.StorageProfile.OSDisk.OSType) + var osType string tags := map[string]*string{} networkInterfaces := []string{} var computerName string @@ -619,6 +625,12 @@ func mapFromVMScaleSetVM(vm armcompute.VirtualMachineScaleSetVM, scaleSetName st } if vm.Properties != nil { + if vm.Properties.StorageProfile != nil && + vm.Properties.StorageProfile.OSDisk != nil && + vm.Properties.StorageProfile.OSDisk.OSType != nil { + osType = string(*vm.Properties.StorageProfile.OSDisk.OSType) + } + if vm.Properties.NetworkProfile != nil { for _, vmNIC := range vm.Properties.NetworkProfile.NetworkInterfaces { networkInterfaces = append(networkInterfaces, *vmNIC.ID) diff --git a/discovery/azure/azure_test.go b/discovery/azure/azure_test.go index 4ff937e0bc..1e437c75f2 100644 --- a/discovery/azure/azure_test.go +++ b/discovery/azure/azure_test.go @@ -79,6 +79,55 @@ func TestMapFromVMWithEmptyTags(t *testing.T) { require.Equal(t, expectedVM, actualVM) } +func TestMapFromVMWithEmptyOSType(t *testing.T) { + id := "test" + name := "name" + size := "size" + vmSize := armcompute.VirtualMachineSizeTypes(size) + vmType := "type" + location := "westeurope" + computerName := "computer_name" + networkProfile := armcompute.NetworkProfile{ + NetworkInterfaces: []*armcompute.NetworkInterfaceReference{}, + } + properties := &armcompute.VirtualMachineProperties{ + OSProfile: &armcompute.OSProfile{ + ComputerName: &computerName, + }, + StorageProfile: &armcompute.StorageProfile{ + OSDisk: &armcompute.OSDisk{}, + }, + NetworkProfile: &networkProfile, + HardwareProfile: &armcompute.HardwareProfile{ + VMSize: &vmSize, + }, + } + + testVM := armcompute.VirtualMachine{ + ID: &id, + Name: &name, + Type: &vmType, + Location: &location, + Tags: nil, + Properties: properties, + } + + expectedVM := virtualMachine{ + ID: id, + Name: name, + ComputerName: computerName, + Type: vmType, + Location: location, + Tags: map[string]*string{}, + NetworkInterfaces: []string{}, + Size: size, + } + + actualVM := mapFromVM(testVM) + + require.Equal(t, expectedVM, actualVM) +} + func TestMapFromVMWithTags(t *testing.T) { id := "test" name := "name" @@ -193,6 +242,58 @@ func TestMapFromVMScaleSetVMWithEmptyTags(t *testing.T) { require.Equal(t, expectedVM, actualVM) } +func TestMapFromVMScaleSetVMWithEmptyOSType(t *testing.T) { + id := "test" + name := "name" + size := "size" + vmSize := armcompute.VirtualMachineSizeTypes(size) + vmType := "type" + instanceID := "123" + location := "westeurope" + computerName := "computer_name" + networkProfile := armcompute.NetworkProfile{ + NetworkInterfaces: []*armcompute.NetworkInterfaceReference{}, + } + properties := &armcompute.VirtualMachineScaleSetVMProperties{ + OSProfile: &armcompute.OSProfile{ + ComputerName: &computerName, + }, + StorageProfile: &armcompute.StorageProfile{}, + NetworkProfile: &networkProfile, + HardwareProfile: &armcompute.HardwareProfile{ + VMSize: &vmSize, + }, + } + + testVM := armcompute.VirtualMachineScaleSetVM{ + ID: &id, + Name: &name, + Type: &vmType, + InstanceID: &instanceID, + Location: &location, + Tags: nil, + Properties: properties, + } + + scaleSet := "testSet" + expectedVM := virtualMachine{ + ID: id, + Name: name, + ComputerName: computerName, + Type: vmType, + Location: location, + Tags: map[string]*string{}, + NetworkInterfaces: []string{}, + ScaleSet: scaleSet, + InstanceID: instanceID, + Size: size, + } + + actualVM := mapFromVMScaleSetVM(testVM, scaleSet) + + require.Equal(t, expectedVM, actualVM) +} + func TestMapFromVMScaleSetVMWithTags(t *testing.T) { id := "test" name := "name" From 92544c00bf9d43eecd7161911d541a3fbe7af8cc Mon Sep 17 00:00:00 2001 From: machine424 Date: Fri, 16 Feb 2024 14:21:10 +0100 Subject: [PATCH 013/253] discovery: kubernetes: Avoid creating unnecessary Kubernetes indexers in RoleEndpointSlice This was due to a missing "return", see https://github.com/prometheus/prometheus/pull/13554#discussion_r1490965817 Signed-off-by: machine424 --- discovery/kubernetes/endpointslice_test.go | 39 ++++++++++++++++++++++ discovery/kubernetes/kubernetes.go | 2 +- discovery/kubernetes/kubernetes_test.go | 14 ++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/discovery/kubernetes/endpointslice_test.go b/discovery/kubernetes/endpointslice_test.go index f23c9e6557..a6579b9543 100644 --- a/discovery/kubernetes/endpointslice_test.go +++ b/discovery/kubernetes/endpointslice_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/prometheus/common/model" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/discovery/v1" "k8s.io/api/discovery/v1beta1" @@ -1405,3 +1406,41 @@ func TestEndpointSliceDiscoveryEmptyPodStatus(t *testing.T) { expectedRes: map[string]*targetgroup.Group{}, }.Run(t) } + +// TestEndpointSliceInfIndexersCount makes sure that RoleEndpointSlice discovery +// sets up indexing for the main Kube informer only when needed. +// See: https://github.com/prometheus/prometheus/pull/13554#discussion_r1490965817 +func TestEndpointSliceInfIndexersCount(t *testing.T) { + tests := []struct { + name string + withNodeMetadata bool + }{ + {"with node metadata", true}, + {"without node metadata", false}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var ( + n *Discovery + mainInfIndexersCount int + ) + if tc.withNodeMetadata { + mainInfIndexersCount = 1 + n, _ = makeDiscoveryWithMetadata(RoleEndpointSlice, NamespaceDiscovery{}, AttachMetadataConfig{Node: true}) + } else { + n, _ = makeDiscovery(RoleEndpointSlice, NamespaceDiscovery{}) + } + + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + n.RLock() + defer n.RUnlock() + require.Len(t, n.discoverers, 1) + require.Len(t, n.discoverers[0].(*EndpointSlice).endpointSliceInf.GetIndexer().GetIndexers(), mainInfIndexersCount) + }, + }.Run(t) + }) + } +} diff --git a/discovery/kubernetes/kubernetes.go b/discovery/kubernetes/kubernetes.go index 489365fa46..d6b8115848 100644 --- a/discovery/kubernetes/kubernetes.go +++ b/discovery/kubernetes/kubernetes.go @@ -815,7 +815,7 @@ func (d *Discovery) newEndpointsByNodeInformer(plw *cache.ListWatch) cache.Share func (d *Discovery) newEndpointSlicesByNodeInformer(plw *cache.ListWatch, object runtime.Object) cache.SharedIndexInformer { indexers := make(map[string]cache.IndexFunc) if !d.attachMetadata.Node { - cache.NewSharedIndexInformer(plw, &disv1.EndpointSlice{}, resyncDisabled, indexers) + return cache.NewSharedIndexInformer(plw, object, resyncDisabled, indexers) } indexers[nodeIndex] = func(obj interface{}) ([]string, error) { diff --git a/discovery/kubernetes/kubernetes_test.go b/discovery/kubernetes/kubernetes_test.go index f1f8070e88..e3dd093009 100644 --- a/discovery/kubernetes/kubernetes_test.go +++ b/discovery/kubernetes/kubernetes_test.go @@ -128,7 +128,7 @@ func (d k8sDiscoveryTest) Run(t *testing.T) { } resChan := make(chan map[string]*targetgroup.Group) - go readResultWithTimeout(t, ch, d.expectedMaxItems, time.Second, resChan) + go readResultWithTimeout(t, ctx, ch, d.expectedMaxItems, time.Second, resChan) dd, ok := d.discovery.(hasSynced) require.True(t, ok, "discoverer does not implement hasSynced interface") @@ -141,13 +141,18 @@ func (d k8sDiscoveryTest) Run(t *testing.T) { if d.expectedRes != nil { res := <-resChan requireTargetGroups(t, d.expectedRes, res) + } else { + // Stop readResultWithTimeout and wait for it. + cancel() + <-resChan } } // readResultWithTimeout reads all targetgroups from channel with timeout. // It merges targetgroups by source and sends the result to result channel. -func readResultWithTimeout(t *testing.T, ch <-chan []*targetgroup.Group, max int, timeout time.Duration, resChan chan<- map[string]*targetgroup.Group) { +func readResultWithTimeout(t *testing.T, ctx context.Context, ch <-chan []*targetgroup.Group, max int, stopAfter time.Duration, resChan chan<- map[string]*targetgroup.Group) { res := make(map[string]*targetgroup.Group) + timeout := time.After(stopAfter) Loop: for { select { @@ -162,12 +167,15 @@ Loop: // Reached max target groups we may get, break fast. break Loop } - case <-time.After(timeout): + case <-timeout: // Because we use queue, an object that is created then // deleted or updated may be processed only once. // So possibly we may skip events, timed out here. t.Logf("timed out, got %d (max: %d) items, some events are skipped", len(res), max) break Loop + case <-ctx.Done(): + t.Logf("stopped, got %d (max: %d) items", len(res), max) + break Loop } } From ebb91bc111a933c6d6c325cc43d69e374289f5d4 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 19 Feb 2024 20:40:00 +0900 Subject: [PATCH 014/253] ci: bump Go from 1.21 to 1.22 Signed-off-by: junya koyama --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/codeql-analysis.yml | 2 +- .promu.yml | 2 +- scripts/golangci-lint.yml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1e2b66bf1..de0163526d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: # Whenever the Go version is updated here, .promu.yml # should also be updated. container: - image: quay.io/prometheus/golang-builder:1.21-base + image: quay.io/prometheus/golang-builder:1.22-base steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 @@ -32,7 +32,7 @@ jobs: # Whenever the Go version is updated here, .promu.yml # should also be updated. container: - image: quay.io/prometheus/golang-builder:1.21-base + image: quay.io/prometheus/golang-builder:1.22-base steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -55,7 +55,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: 1.21.x + go-version: 1.22.x - run: | $TestTargets = go list ./... | Where-Object { $_ -NotMatch "(github.com/prometheus/prometheus/discovery.*|github.com/prometheus/prometheus/config|github.com/prometheus/prometheus/web)"} go test $TestTargets -vet=off -v @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-latest # The go verson in this image should be N-1 wrt test_go. container: - image: quay.io/prometheus/golang-builder:1.20-base + image: quay.io/prometheus/golang-builder:1.21-base steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - run: make build @@ -79,7 +79,7 @@ jobs: # Whenever the Go version is updated here, .promu.yml # should also be updated. container: - image: quay.io/prometheus/golang-builder:1.20-base + image: quay.io/prometheus/golang-builder:1.21-base steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - run: go install ./cmd/promtool/. @@ -143,7 +143,7 @@ jobs: uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: cache: false - go-version: 1.21.x + go-version: 1.22.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fd1ef19ef3..ec6ae25c64 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,7 +27,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - go-version: 1.21.x + go-version: 1.22.x - name: Initialize CodeQL uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 diff --git a/.promu.yml b/.promu.yml index e5e01181cc..d8cdc4209a 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,7 +1,7 @@ go: # Whenever the Go version is updated here, # .circle/config.yml should also be updated. - version: 1.21 + version: 1.22 repository: path: github.com/prometheus/prometheus build: diff --git a/scripts/golangci-lint.yml b/scripts/golangci-lint.yml index 8f25279111..0e8515722f 100644 --- a/scripts/golangci-lint.yml +++ b/scripts/golangci-lint.yml @@ -28,7 +28,7 @@ jobs: - name: install Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: - go-version: 1.21.x + go-version: 1.22.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' From 39e858e5244735c3de33c96e6e42bd67f6ae18f1 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 19 Feb 2024 20:40:55 +0900 Subject: [PATCH 015/253] go: bump go from 1.20 to 1.21 Signed-off-by: junya koyama --- documentation/examples/remote_storage/go.mod | 2 +- documentation/examples/remote_storage/go.sum | 82 ++++++++++++++++++++ go.mod | 2 +- go.sum | 19 +++++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index 6faa5efc27..e5c1c4e4cb 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.20 +go 1.21.7 require ( github.com/alecthomas/kingpin/v2 v2.4.0 diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index da503b74aa..9b8208baa2 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -5,11 +5,14 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -20,6 +23,7 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= @@ -31,6 +35,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -39,19 +44,31 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= +github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= 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/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= +github.com/docker/docker v24.0.6+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= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= +github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= +github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -68,11 +85,16 @@ github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= +github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -94,43 +116,65 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= 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.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 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/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= +github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= +github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= +github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= +github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= +github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= 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.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok= +github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= 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/influxdata/influxdb v1.11.4 h1:H3pVW+/tWQ4lkHhZxVQ13Ov1hmhHYaAzz8L5aq3ZNtw= github.com/influxdata/influxdb v1.11.4/go.mod h1:VO6X2zlamfmEf+Esc9dR+7UQhdE/krspWNEZPwxCrp0= github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= +github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -145,11 +189,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= +github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -157,13 +203,20 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= +github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -172,13 +225,18 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= +github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -216,14 +274,18 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -231,6 +293,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= +github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -251,6 +314,7 @@ go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmY 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/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -266,6 +330,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -296,6 +361,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -321,6 +387,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= 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= @@ -337,6 +404,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -346,7 +414,9 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= +google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a h1:myvhA4is3vrit1a6NZCWBIwN0kNEnX21DJOJX/NvIfI= +google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= @@ -365,8 +435,11 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks 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= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -379,12 +452,21 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= +k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= +sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/go.mod b/go.mod index faf9c26274..7ec59e99ed 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/prometheus -go 1.20 +go 1.21.7 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 diff --git a/go.sum b/go.sum index 8c362eb867..0b0bf4d987 100644 --- a/go.sum +++ b/go.sum @@ -43,9 +43,11 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNic github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= @@ -148,6 +150,7 @@ github.com/digitalocean/godo v1.108.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH1 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 v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= github.com/docker/docker v25.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -186,6 +189,7 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= @@ -254,6 +258,7 @@ github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -331,6 +336,7 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -400,6 +406,7 @@ github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJO github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.15.1 h1:kKIGxc7CZtflcF5DLfHeq7rOQmRq3vk7kwISN9bif8Q= +github.com/hashicorp/consul/sdk v0.15.1/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -417,6 +424,7 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -429,10 +437,12 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -464,6 +474,7 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= +github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -506,6 +517,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -543,6 +555,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= +github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -555,6 +568,7 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -601,8 +615,10 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= +github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -644,6 +660,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= github.com/prometheus/alertmanager v0.26.0/go.mod h1:rVcnARltVjavgVaNnmevxK7kOn7IZavyf0KNgHkbEpU= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -693,6 +710,7 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -701,6 +719,7 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22/go.mod h1:fCa7OJZ/9DRTnOKmxvT github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shoenig/test v0.6.6 h1:Oe8TPH9wAbv++YPNDKJWUnI8Q4PPWCx3UbOfH+FxiMU= +github.com/shoenig/test v0.6.6/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= From 93591ec5cc00a4459c74c777bd06b58af8857e23 Mon Sep 17 00:00:00 2001 From: Augustin Husson Date: Mon, 19 Feb 2024 14:15:03 +0100 Subject: [PATCH 016/253] Cut v2.50.0-rc.1 (#13602) Signed-off-by: Augustin Husson --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 ++-- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f8bf8003..4b3f13b432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 2.50.0-rc.1 / 2024-02-19 + +[BUGFIX] Azure SD: Fix SD crashing when it finds a VM scale set. #13578 + ## 2.50.0-rc.0 / 2024-02-07 * [CHANGE] Remote Write: Error `storage.ErrTooOldSample` is now generating HTTP error 400 instead of HTTP error 500. #13335 diff --git a/VERSION b/VERSION index 9f02570d13..782980c611 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.50.0-rc.0 +2.50.0-rc.1 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index bfbdd56e23..3975c7a4b4 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.50.0-rc.0", + "version": "0.50.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.50.0-rc.0", + "@prometheus-io/lezer-promql": "0.50.0-rc.1", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index aca68a67a0..0eb5b3473f 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.50.0-rc.0", + "version": "0.50.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 b2d136ceb9..dab335a77b 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.50.0-rc.0", + "version": "0.50.0-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.50.0-rc.0", + "version": "0.50.0-rc.1", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.50.0-rc.0", + "version": "0.50.0-rc.1", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.50.0-rc.0", + "@prometheus-io/lezer-promql": "0.50.0-rc.1", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.50.0-rc.0", + "version": "0.50.0-rc.1", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.50.0-rc.0", + "version": "0.50.0-rc.1", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.0-rc.0", + "@prometheus-io/codemirror-promql": "0.50.0-rc.1", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index 86a18f466a..5b2cb68e5d 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.50.0-rc.0" + "version": "0.50.0-rc.1" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index 4bd707e98b..ab75cda784 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.50.0-rc.0", + "version": "0.50.0-rc.1", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.0-rc.0", + "@prometheus-io/codemirror-promql": "0.50.0-rc.1", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 52389647b2ab4e52d86c97089cf5f4260839f984 Mon Sep 17 00:00:00 2001 From: Fiona Liao Date: Mon, 19 Feb 2024 15:08:14 +0000 Subject: [PATCH 017/253] Add type label to outOfOrderSamplesAppended metric Signed-off-by: Fiona Liao --- tsdb/db_test.go | 14 +++++++---- tsdb/head.go | 6 ++--- tsdb/head_append.go | 57 ++++++++++++++++++++++++--------------------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/tsdb/db_test.go b/tsdb/db_test.go index fd20c0e205..3f9097c087 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -4945,7 +4945,7 @@ func Test_Querier_OOOQuery(t *testing.T) { require.NotNil(t, seriesSet[series1.String()]) require.Len(t, seriesSet, 1) require.Equal(t, expSamples, seriesSet[series1.String()]) - require.GreaterOrEqual(t, float64(oooSamples), prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamplesAppended), "number of ooo appended samples mismatch") + requireEqualOOOSamples(t, oooSamples, db) }) } } @@ -5028,7 +5028,7 @@ func Test_ChunkQuerier_OOOQuery(t *testing.T) { chks := queryChunks(t, querier, labels.MustNewMatcher(labels.MatchEqual, "foo", "bar1")) require.NotNil(t, chks[series1.String()]) require.Len(t, chks, 1) - require.Equal(t, float64(oooSamples), prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamplesAppended), "number of ooo appended samples mismatch") + requireEqualOOOSamples(t, oooSamples, db) var gotSamples []chunks.Sample for _, chunk := range chks[series1.String()] { it := chunk.Chunk.Iterator(nil) @@ -5107,7 +5107,7 @@ func TestOOOAppendAndQuery(t *testing.T) { } } require.Equal(t, expSamples, seriesSet) - require.Equal(t, float64(totalSamples-2), prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamplesAppended), "number of ooo appended samples mismatch") + requireEqualOOOSamples(t, totalSamples-2, db) } verifyOOOMinMaxTimes := func(expMin, expMax int64) { @@ -5216,7 +5216,7 @@ func TestOOODisabled(t *testing.T) { seriesSet := query(t, querier, labels.MustNewMatcher(labels.MatchRegexp, "foo", "bar.")) require.Equal(t, expSamples, seriesSet) - require.Equal(t, float64(0), prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamplesAppended), "number of ooo appended samples mismatch") + requireEqualOOOSamples(t, 0, db) require.Equal(t, float64(failedSamples), prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamples.WithLabelValues(sampleMetricTypeFloat))+prom_testutil.ToFloat64(db.head.metrics.outOfBoundSamples.WithLabelValues(sampleMetricTypeFloat)), "number of ooo/oob samples mismatch") @@ -6943,3 +6943,9 @@ Outer: require.NoError(t, writerErr) } + +func requireEqualOOOSamples(t *testing.T, expectedSamples int, db *DB) { + require.Equal(t, float64(expectedSamples), + prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamplesAppended.WithLabelValues(sampleMetricTypeFloat)), + "number of ooo appended samples mismatch") +} diff --git a/tsdb/head.go b/tsdb/head.go index ac4aa52d76..b3ca0a1488 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -340,7 +340,7 @@ type headMetrics struct { chunksRemoved prometheus.Counter gcDuration prometheus.Summary samplesAppended *prometheus.CounterVec - outOfOrderSamplesAppended prometheus.Counter + outOfOrderSamplesAppended *prometheus.CounterVec outOfBoundSamples *prometheus.CounterVec outOfOrderSamples *prometheus.CounterVec tooOldSamples *prometheus.CounterVec @@ -420,10 +420,10 @@ func newHeadMetrics(h *Head, r prometheus.Registerer) *headMetrics { Name: "prometheus_tsdb_head_samples_appended_total", Help: "Total number of appended samples.", }, []string{"type"}), - outOfOrderSamplesAppended: prometheus.NewCounter(prometheus.CounterOpts{ + outOfOrderSamplesAppended: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "prometheus_tsdb_head_out_of_order_samples_appended_total", Help: "Total number of appended out of order samples.", - }), + }, []string{"type"}), outOfBoundSamples: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "prometheus_tsdb_out_of_bound_samples_total", Help: "Total number of out of bound samples ingestion failed attempts with out of order support disabled.", diff --git a/tsdb/head_append.go b/tsdb/head_append.go index 801beb3777..7f04d61182 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -835,11 +835,17 @@ func (a *headAppender) Commit() (err error) { defer a.head.iso.closeAppend(a.appendID) var ( - samplesAppended = len(a.samples) - oooAccepted int // number of samples out of order but accepted: with ooo enabled and within time window - oooRejected int // number of samples rejected due to: out of order but OOO support disabled. - tooOldRejected int // number of samples rejected due to: that are out of order but too old (OOO support enabled, but outside time window) - oobRejected int // number of samples rejected due to: out of bounds: with t < minValidTime (OOO support disabled) + floatsAppended = len(a.samples) + // number of samples out of order but accepted: with ooo enabled and within time window + floatOOOAccepted int + // number of samples rejected due to: out of order but OOO support disabled. + floatOOORejected int + histoOOORejected int + // number of samples rejected due to: that are out of order but too old (OOO support enabled, but outside time window) + floatTooOldRejected int + // number of samples rejected due to: out of bounds: with t < minValidTime (OOO support disabled) + floatOOBRejected int + inOrderMint int64 = math.MaxInt64 inOrderMaxt int64 = math.MinInt64 ooomint int64 = math.MaxInt64 @@ -902,16 +908,16 @@ func (a *headAppender) Commit() (err error) { case err == nil: // Do nothing. case errors.Is(err, storage.ErrOutOfOrderSample): - samplesAppended-- - oooRejected++ + floatsAppended-- + floatOOORejected++ case errors.Is(err, storage.ErrOutOfBounds): - samplesAppended-- - oobRejected++ + floatsAppended-- + floatOOBRejected++ case errors.Is(err, storage.ErrTooOldSample): - samplesAppended-- - tooOldRejected++ + floatsAppended-- + floatTooOldRejected++ default: - samplesAppended-- + floatsAppended-- } var ok, chunkCreated bool @@ -949,13 +955,13 @@ func (a *headAppender) Commit() (err error) { if s.T > ooomaxt { ooomaxt = s.T } - oooAccepted++ + floatOOOAccepted++ } else { // Sample is an exact duplicate of the last sample. // NOTE: We can only detect updates if they clash with a sample in the OOOHeadChunk, // not with samples in already flushed OOO chunks. // TODO(codesome): Add error reporting? It depends on addressing https://github.com/prometheus/prometheus/discussions/10305. - samplesAppended-- + floatsAppended-- } default: ok, chunkCreated = series.append(s.T, s.V, a.appendID, appendChunkOpts) @@ -968,7 +974,7 @@ func (a *headAppender) Commit() (err error) { } } else { // The sample is an exact duplicate, and should be silently dropped. - samplesAppended-- + floatsAppended-- } } @@ -982,8 +988,7 @@ func (a *headAppender) Commit() (err error) { series.Unlock() } - histogramsTotal := len(a.histograms) - histoOOORejected := 0 + histogramsAppended := len(a.histograms) for i, s := range a.histograms { series = a.histogramSeries[i] series.Lock() @@ -1000,7 +1005,7 @@ func (a *headAppender) Commit() (err error) { inOrderMaxt = s.T } } else { - histogramsTotal-- + histogramsAppended-- histoOOORejected++ } if chunkCreated { @@ -1009,7 +1014,7 @@ func (a *headAppender) Commit() (err error) { } } - histogramsTotal += len(a.floatHistograms) + histogramsAppended += len(a.floatHistograms) for i, s := range a.floatHistograms { series = a.floatHistogramSeries[i] series.Lock() @@ -1026,7 +1031,7 @@ func (a *headAppender) Commit() (err error) { inOrderMaxt = s.T } } else { - histogramsTotal-- + histogramsAppended-- histoOOORejected++ } if chunkCreated { @@ -1042,13 +1047,13 @@ func (a *headAppender) Commit() (err error) { series.Unlock() } - a.head.metrics.outOfOrderSamples.WithLabelValues(sampleMetricTypeFloat).Add(float64(oooRejected)) + a.head.metrics.outOfOrderSamples.WithLabelValues(sampleMetricTypeFloat).Add(float64(floatOOORejected)) a.head.metrics.outOfOrderSamples.WithLabelValues(sampleMetricTypeHistogram).Add(float64(histoOOORejected)) - a.head.metrics.outOfBoundSamples.WithLabelValues(sampleMetricTypeFloat).Add(float64(oobRejected)) - a.head.metrics.tooOldSamples.WithLabelValues(sampleMetricTypeFloat).Add(float64(tooOldRejected)) - a.head.metrics.samplesAppended.WithLabelValues(sampleMetricTypeFloat).Add(float64(samplesAppended)) - a.head.metrics.samplesAppended.WithLabelValues(sampleMetricTypeHistogram).Add(float64(histogramsTotal)) - a.head.metrics.outOfOrderSamplesAppended.Add(float64(oooAccepted)) + a.head.metrics.outOfBoundSamples.WithLabelValues(sampleMetricTypeFloat).Add(float64(floatOOBRejected)) + a.head.metrics.tooOldSamples.WithLabelValues(sampleMetricTypeFloat).Add(float64(floatTooOldRejected)) + a.head.metrics.samplesAppended.WithLabelValues(sampleMetricTypeFloat).Add(float64(floatsAppended)) + a.head.metrics.samplesAppended.WithLabelValues(sampleMetricTypeHistogram).Add(float64(histogramsAppended)) + a.head.metrics.outOfOrderSamplesAppended.WithLabelValues(sampleMetricTypeFloat).Add(float64(floatOOOAccepted)) a.head.updateMinMaxTime(inOrderMint, inOrderMaxt) a.head.updateMinOOOMaxOOOTime(ooomint, ooomaxt) From 841a133514297cfeb2ea09277d168d1c7d107815 Mon Sep 17 00:00:00 2001 From: Fiona Liao Date: Wed, 21 Feb 2024 11:14:49 +0000 Subject: [PATCH 018/253] Move histogramsAppended to be more consistent Signed-off-by: Fiona Liao --- tsdb/head_append.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tsdb/head_append.go b/tsdb/head_append.go index 7f04d61182..a0bf987160 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -835,7 +835,8 @@ func (a *headAppender) Commit() (err error) { defer a.head.iso.closeAppend(a.appendID) var ( - floatsAppended = len(a.samples) + floatsAppended = len(a.samples) + histogramsAppended = len(a.histograms) + len(a.floatHistograms) // number of samples out of order but accepted: with ooo enabled and within time window floatOOOAccepted int // number of samples rejected due to: out of order but OOO support disabled. @@ -988,7 +989,6 @@ func (a *headAppender) Commit() (err error) { series.Unlock() } - histogramsAppended := len(a.histograms) for i, s := range a.histograms { series = a.histogramSeries[i] series.Lock() @@ -1014,7 +1014,6 @@ func (a *headAppender) Commit() (err error) { } } - histogramsAppended += len(a.floatHistograms) for i, s := range a.floatHistograms { series = a.floatHistogramSeries[i] series.Lock() From 14e48cd3ce256e85c47f52d8063a708ab74e5216 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 21 Feb 2024 11:39:23 +0000 Subject: [PATCH 019/253] Docs: update remote-write defaults Signed-off-by: Bryan Boreham --- docs/configuration/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index e62d61b099..d228468655 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -3643,13 +3643,13 @@ queue_config: # samples from the WAL. It is recommended to have enough capacity in each # shard to buffer several requests to keep throughput up while processing # occasional slow remote requests. - [ capacity: | default = 2500 ] + [ capacity: | default = 10000 ] # Maximum number of shards, i.e. amount of concurrency. - [ max_shards: | default = 200 ] + [ max_shards: | default = 50 ] # Minimum number of shards, i.e. amount of concurrency. [ min_shards: | default = 1 ] # Maximum number of samples per send. - [ max_samples_per_send: | default = 500] + [ max_samples_per_send: | default = 2000] # Maximum time a sample will wait in buffer. [ batch_send_deadline: | default = 5s ] # Initial retry delay. Gets doubled for every retry. From e22b564049b74ecf007c15a7e7d33ba5128ab1c4 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Wed, 21 Feb 2024 15:09:21 +0100 Subject: [PATCH 020/253] Always align scrapes even if tolerance is bigger than 1% of scrape interval When the scrape tolerance is bigger than 1% of the scrape interval, take 1% of the scrape interval as the tolerance instead of not aligning the scrape at all. Signed-off-by: Julien Pivotto --- scrape/scrape.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index dfa945852c..383c262e0c 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -1192,14 +1192,18 @@ mainLoop: // Calling Round ensures the time used is the wall clock, as otherwise .Sub // and .Add on time.Time behave differently (see time package docs). scrapeTime := time.Now().Round(0) - if AlignScrapeTimestamps && sl.interval > 100*ScrapeTimestampTolerance { + if AlignScrapeTimestamps { + tolerance := ScrapeTimestampTolerance + if maxTolerance := sl.interval / 100; tolerance < maxTolerance { + tolerance = maxTolerance + } // For some reason, a tick might have been skipped, in which case we // would call alignedScrapeTime.Add(interval) multiple times. for scrapeTime.Sub(alignedScrapeTime) >= sl.interval { alignedScrapeTime = alignedScrapeTime.Add(sl.interval) } // Align the scrape time if we are in the tolerance boundaries. - if scrapeTime.Sub(alignedScrapeTime) <= ScrapeTimestampTolerance { + if scrapeTime.Sub(alignedScrapeTime) <= tolerance { scrapeTime = alignedScrapeTime } } From 0c71230784368da829f1f02d412d181d7a06aee6 Mon Sep 17 00:00:00 2001 From: Callum Styan Date: Wed, 21 Feb 2024 17:09:07 -0800 Subject: [PATCH 021/253] fix bug that would cause us to endlessly fall behind (#13583) * fix bug that would cause us to only read from the WAL on the 15s fallback timer if remote write had fallen behind and is no longer reading from the WAL segment that is currently being written to Signed-off-by: Callum Styan * remove unintended logging, fix lint, plus allow test to take slightly longer because cloud CI Signed-off-by: Callum Styan * address review feedback Signed-off-by: Callum Styan * fix watcher sleeps in test, flu brain is smooth Signed-off-by: Callum Styan * increase timeout, unfortunately cloud CI can require a longer timeout Signed-off-by: Callum Styan --------- Signed-off-by: Callum Styan --- tsdb/wlog/watcher.go | 16 +++-- tsdb/wlog/watcher_test.go | 125 +++++++++++++++++++++++++++++++++++--- 2 files changed, 128 insertions(+), 13 deletions(-) diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index 1c76e38877..525515221d 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -262,10 +262,8 @@ func (w *Watcher) loop() { // Run the watcher, which will tail the WAL until the quit channel is closed // or an error case is hit. func (w *Watcher) Run() error { - _, lastSegment, err := w.firstAndLast() - if err != nil { - return fmt.Errorf("wal.Segments: %w", err) - } + var lastSegment int + var err error // We want to ensure this is false across iterations since // Run will be called again if there was a failure to read the WAL. @@ -296,9 +294,17 @@ func (w *Watcher) Run() error { w.currentSegmentMetric.Set(float64(currentSegment)) level.Debug(w.logger).Log("msg", "Processing segment", "currentSegment", currentSegment) + // Reset the value of lastSegment each iteration, this is to avoid having to wait too long for + // between reads if we're reading a segment that is not the most recent segment after startup. + _, lastSegment, err = w.firstAndLast() + if err != nil { + return fmt.Errorf("wal.Segments: %w", err) + } + tail := currentSegment >= lastSegment + // On start, after reading the existing WAL for series records, we have a pointer to what is the latest segment. // On subsequent calls to this function, currentSegment will have been incremented and we should open that segment. - if err := w.watch(currentSegment, currentSegment >= lastSegment); err != nil && !errors.Is(err, ErrIgnorable) { + if err := w.watch(currentSegment, tail); err != nil && !errors.Is(err, ErrIgnorable) { return err } diff --git a/tsdb/wlog/watcher_test.go b/tsdb/wlog/watcher_test.go index b10f8f8f8c..871640a7cf 100644 --- a/tsdb/wlog/watcher_test.go +++ b/tsdb/wlog/watcher_test.go @@ -58,29 +58,47 @@ type writeToMock struct { floatHistogramsAppended int seriesLock sync.Mutex seriesSegmentIndexes map[chunks.HeadSeriesRef]int + + // delay reads with a short sleep + delay time.Duration } func (wtm *writeToMock) Append(s []record.RefSample) bool { + if wtm.delay > 0 { + time.Sleep(wtm.delay) + } wtm.samplesAppended += len(s) return true } func (wtm *writeToMock) AppendExemplars(e []record.RefExemplar) bool { + if wtm.delay > 0 { + time.Sleep(wtm.delay) + } wtm.exemplarsAppended += len(e) return true } func (wtm *writeToMock) AppendHistograms(h []record.RefHistogramSample) bool { + if wtm.delay > 0 { + time.Sleep(wtm.delay) + } wtm.histogramsAppended += len(h) return true } func (wtm *writeToMock) AppendFloatHistograms(fh []record.RefFloatHistogramSample) bool { + if wtm.delay > 0 { + time.Sleep(wtm.delay) + } wtm.floatHistogramsAppended += len(fh) return true } func (wtm *writeToMock) StoreSeries(series []record.RefSeries, index int) { + if wtm.delay > 0 { + time.Sleep(wtm.delay) + } wtm.UpdateSeriesSegment(series, index) } @@ -110,9 +128,10 @@ func (wtm *writeToMock) checkNumSeries() int { return len(wtm.seriesSegmentIndexes) } -func newWriteToMock() *writeToMock { +func newWriteToMock(delay time.Duration) *writeToMock { return &writeToMock{ seriesSegmentIndexes: make(map[chunks.HeadSeriesRef]int), + delay: delay, } } @@ -209,7 +228,7 @@ func TestTailSamples(t *testing.T) { first, last, err := Segments(w.Dir()) require.NoError(t, err) - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, true, true) watcher.SetStartTime(now) @@ -294,7 +313,7 @@ func TestReadToEndNoCheckpoint(t *testing.T) { _, _, err = Segments(w.Dir()) require.NoError(t, err) - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) go watcher.Start() @@ -383,7 +402,7 @@ func TestReadToEndWithCheckpoint(t *testing.T) { _, _, err = Segments(w.Dir()) require.NoError(t, err) readTimeout = time.Second - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) go watcher.Start() @@ -454,7 +473,7 @@ func TestReadCheckpoint(t *testing.T) { _, _, err = Segments(w.Dir()) require.NoError(t, err) - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) go watcher.Start() @@ -523,7 +542,7 @@ func TestReadCheckpointMultipleSegments(t *testing.T) { require.NoError(t, err) } - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) watcher.MaxSegment = -1 @@ -596,7 +615,7 @@ func TestCheckpointSeriesReset(t *testing.T) { require.NoError(t, err) readTimeout = time.Second - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) watcher.MaxSegment = -1 go watcher.Start() @@ -675,7 +694,7 @@ func TestRun_StartupTime(t *testing.T) { } require.NoError(t, w.Close()) - wt := newWriteToMock() + wt := newWriteToMock(0) watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) watcher.MaxSegment = segments @@ -688,3 +707,93 @@ func TestRun_StartupTime(t *testing.T) { }) } } + +func TestRun_AvoidNotifyWhenBehind(t *testing.T) { + const pageSize = 32 * 1024 + const segments = 10 + const seriesCount = 20 + const samplesCount = 300 + + // This test can take longer than intended to finish in cloud CI. + readTimeout := 10 * time.Second + + for _, compress := range []CompressionType{CompressionNone, CompressionSnappy, CompressionZstd} { + t.Run(string(compress), func(t *testing.T) { + dir := t.TempDir() + + wdir := path.Join(dir, "wal") + err := os.Mkdir(wdir, 0o777) + require.NoError(t, err) + + enc := record.Encoder{} + w, err := NewSize(nil, nil, wdir, pageSize, compress) + require.NoError(t, err) + var wg sync.WaitGroup + // add one segment initially to ensure there's a value > 0 for the last segment id + for i := 0; i < 1; i++ { + for j := 0; j < seriesCount; j++ { + ref := j + (i * 100) + series := enc.Series([]record.RefSeries{ + { + Ref: chunks.HeadSeriesRef(ref), + Labels: labels.FromStrings("__name__", fmt.Sprintf("metric_%d", i)), + }, + }, nil) + require.NoError(t, w.Log(series)) + + for k := 0; k < samplesCount; k++ { + inner := rand.Intn(ref + 1) + sample := enc.Samples([]record.RefSample{ + { + Ref: chunks.HeadSeriesRef(inner), + T: int64(i), + V: float64(i), + }, + }, nil) + require.NoError(t, w.Log(sample)) + } + } + } + wg.Add(1) + go func() { + defer wg.Done() + for i := 1; i < segments; i++ { + for j := 0; j < seriesCount; j++ { + ref := j + (i * 100) + series := enc.Series([]record.RefSeries{ + { + Ref: chunks.HeadSeriesRef(ref), + Labels: labels.FromStrings("__name__", fmt.Sprintf("metric_%d", i)), + }, + }, nil) + require.NoError(t, w.Log(series)) + + for k := 0; k < samplesCount; k++ { + inner := rand.Intn(ref + 1) + sample := enc.Samples([]record.RefSample{ + { + Ref: chunks.HeadSeriesRef(inner), + T: int64(i), + V: float64(i), + }, + }, nil) + require.NoError(t, w.Log(sample)) + } + } + } + }() + + wt := newWriteToMock(time.Millisecond) + watcher := NewWatcher(wMetrics, nil, nil, "", wt, dir, false, false) + watcher.MaxSegment = segments + + watcher.setMetrics() + startTime := time.Now() + err = watcher.Run() + wg.Wait() + require.Less(t, time.Since(startTime), readTimeout) + require.NoError(t, err) + require.NoError(t, w.Close()) + }) + } +} From bf5ca8cf38f48196028935568ec3c9f63aeee1a1 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Thu, 22 Feb 2024 09:09:41 +0100 Subject: [PATCH 022/253] otlptranslator: Upgrade to v0.95.0 Signed-off-by: Arve Knudsen --- .../prometheusremotewrite/helper.go | 80 +++++++++---------- .../prometheusremotewrite/histograms.go | 17 +++- .../prometheusremotewrite/metrics_to_prw.go | 16 ++-- .../number_data_points.go | 34 ++++---- .../otlp_to_openmetrics_metadata.go | 66 +++++++++++++++ storage/remote/otlptranslator/update-copy.sh | 2 +- 6 files changed, 145 insertions(+), 70 deletions(-) create mode 100644 storage/remote/otlptranslator/prometheusremotewrite/otlp_to_openmetrics_metadata.go diff --git a/storage/remote/otlptranslator/prometheusremotewrite/helper.go b/storage/remote/otlptranslator/prometheusremotewrite/helper.go index 09b39d29d9..817cbaba7d 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/helper.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/helper.go @@ -28,7 +28,6 @@ import ( ) const ( - nameStr = "__name__" sumStr = "_sum" countStr = "_count" bucketStr = "_bucket" @@ -72,15 +71,14 @@ func (a ByLabelName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // tsMap will be unmodified if either labels or sample is nil, but can still be modified if the exemplar is nil. func addSample(tsMap map[string]*prompb.TimeSeries, sample *prompb.Sample, labels []prompb.Label, datatype string) string { - if sample == nil || labels == nil || tsMap == nil { + // This shouldn't happen return "" } - sig := timeSeriesSignature(datatype, &labels) - ts, ok := tsMap[sig] - - if ok { + sig := timeSeriesSignature(datatype, labels) + ts := tsMap[sig] + if ts != nil { ts.Samples = append(ts.Samples, *sample) } else { newTs := &prompb.TimeSeries{ @@ -97,7 +95,7 @@ func addSample(tsMap map[string]*prompb.TimeSeries, sample *prompb.Sample, label // we only add exemplars if samples are presents // tsMap is unmodified if either of its parameters is nil and samples are nil. func addExemplars(tsMap map[string]*prompb.TimeSeries, exemplars []prompb.Exemplar, bucketBoundsData []bucketBoundsData) { - if tsMap == nil || bucketBoundsData == nil || exemplars == nil { + if len(tsMap) == 0 || len(bucketBoundsData) == 0 || len(exemplars) == 0 { return } @@ -113,14 +111,10 @@ func addExemplar(tsMap map[string]*prompb.TimeSeries, bucketBounds []bucketBound sig := bucketBound.sig bound := bucketBound.bound - _, ok := tsMap[sig] - if ok { - if tsMap[sig].Samples != nil { - if exemplar.Value <= bound { - tsMap[sig].Exemplars = append(tsMap[sig].Exemplars, exemplar) - return - } - } + ts := tsMap[sig] + if ts != nil && len(ts.Samples) > 0 && exemplar.Value <= bound { + ts.Exemplars = append(ts.Exemplars, exemplar) + return } } } @@ -131,10 +125,10 @@ func addExemplar(tsMap map[string]*prompb.TimeSeries, bucketBounds []bucketBound // // the label slice should not contain duplicate label names; this method sorts the slice by label name before creating // the signature. -func timeSeriesSignature(datatype string, labels *[]prompb.Label) string { +func timeSeriesSignature(datatype string, labels []prompb.Label) string { length := len(datatype) - for _, lb := range *labels { + for _, lb := range labels { length += 2 + len(lb.GetName()) + len(lb.GetValue()) } @@ -142,9 +136,9 @@ func timeSeriesSignature(datatype string, labels *[]prompb.Label) string { b.Grow(length) b.WriteString(datatype) - sort.Sort(ByLabelName(*labels)) + sort.Sort(ByLabelName(labels)) - for _, lb := range *labels { + for _, lb := range labels { b.WriteString("-") b.WriteString(lb.GetName()) b.WriteString("-") @@ -154,9 +148,9 @@ func timeSeriesSignature(datatype string, labels *[]prompb.Label) string { return b.String() } -// createAttributes creates a slice of Cortex Label with OTLP attributes and pairs of string values. -// Unpaired string value is ignored. String pairs overwrites OTLP labels if collision happens, and the overwrite is -// logged. Resultant label names are sanitized. +// createAttributes creates a slice of Prometheus Labels with OTLP attributes and pairs of string values. +// Unpaired string values are ignored. String pairs overwrite OTLP labels if collisions happen, and overwrites are +// logged. Resulting label names are sanitized. func createAttributes(resource pcommon.Resource, attributes pcommon.Map, externalLabels map[string]string, extras ...string) []prompb.Label { serviceName, haveServiceName := resource.Attributes().Get(conventions.AttributeServiceName) instance, haveInstanceID := resource.Attributes().Get(conventions.AttributeServiceInstanceID) @@ -186,8 +180,8 @@ func createAttributes(resource pcommon.Resource, attributes pcommon.Map, externa for _, label := range labels { var finalKey = prometheustranslator.NormalizeLabel(label.Name) - if existingLabel, alreadyExists := l[finalKey]; alreadyExists { - l[finalKey] = existingLabel + ";" + label.Value + if existingValue, alreadyExists := l[finalKey]; alreadyExists { + l[finalKey] = existingValue + ";" + label.Value } else { l[finalKey] = label.Value } @@ -257,10 +251,8 @@ func isValidAggregationTemporality(metric pmetric.Metric) bool { // addSingleHistogramDataPoint converts pt to 2 + min(len(ExplicitBounds), len(BucketCount)) + 1 samples. It // ignore extra buckets if len(ExplicitBounds) > len(BucketCounts) -func addSingleHistogramDataPoint(pt pmetric.HistogramDataPoint, resource pcommon.Resource, metric pmetric.Metric, settings Settings, tsMap map[string]*prompb.TimeSeries) { +func addSingleHistogramDataPoint(pt pmetric.HistogramDataPoint, resource pcommon.Resource, metric pmetric.Metric, settings Settings, tsMap map[string]*prompb.TimeSeries, baseName string) { timestamp := convertTimeStamp(pt.Timestamp()) - // sum, count, and buckets of the histogram should append suffix to baseName - baseName := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes) baseLabels := createAttributes(resource, pt.Attributes(), settings.ExternalLabels) createLabels := func(nameSuffix string, extras ...string) []prompb.Label { @@ -272,7 +264,8 @@ func addSingleHistogramDataPoint(pt pmetric.HistogramDataPoint, resource pcommon labels = append(labels, prompb.Label{Name: extras[extrasIdx], Value: extras[extrasIdx+1]}) } - labels = append(labels, prompb.Label{Name: nameStr, Value: baseName + nameSuffix}) + // sum, count, and buckets of the histogram should append suffix to baseName + labels = append(labels, prompb.Label{Name: model.MetricNameLabel, Value: baseName + nameSuffix}) return labels } @@ -349,7 +342,7 @@ func addSingleHistogramDataPoint(pt pmetric.HistogramDataPoint, resource pcommon startTimestamp := pt.StartTimestamp() if settings.ExportCreatedMetric && startTimestamp != 0 { labels := createLabels(createdSuffix) - addCreatedTimeSeriesIfNeeded(tsMap, labels, startTimestamp, metric.Type().String()) + addCreatedTimeSeriesIfNeeded(tsMap, labels, startTimestamp, pt.Timestamp(), metric.Type().String()) } } @@ -359,13 +352,12 @@ type exemplarType interface { } func getPromExemplars[T exemplarType](pt T) []prompb.Exemplar { - var promExemplars []prompb.Exemplar - + promExemplars := make([]prompb.Exemplar, 0, pt.Exemplars().Len()) for i := 0; i < pt.Exemplars().Len(); i++ { exemplar := pt.Exemplars().At(i) exemplarRunes := 0 - promExemplar := &prompb.Exemplar{ + promExemplar := prompb.Exemplar{ Value: exemplar.DoubleValue(), Timestamp: timestamp.FromTime(exemplar.Timestamp().AsTime()), } @@ -387,9 +379,10 @@ func getPromExemplars[T exemplarType](pt T) []prompb.Exemplar { } promExemplar.Labels = append(promExemplar.Labels, promLabel) } - var labelsFromAttributes []prompb.Label - exemplar.FilteredAttributes().Range(func(key string, value pcommon.Value) bool { + attrs := exemplar.FilteredAttributes() + labelsFromAttributes := make([]prompb.Label, 0, attrs.Len()) + attrs.Range(func(key string, value pcommon.Value) bool { val := value.AsString() exemplarRunes += utf8.RuneCountInString(key) + utf8.RuneCountInString(val) promLabel := prompb.Label{ @@ -407,7 +400,7 @@ func getPromExemplars[T exemplarType](pt T) []prompb.Exemplar { promExemplar.Labels = append(promExemplar.Labels, labelsFromAttributes...) } - promExemplars = append(promExemplars, *promExemplar) + promExemplars = append(promExemplars, promExemplar) } return promExemplars @@ -457,10 +450,8 @@ func maxTimestamp(a, b pcommon.Timestamp) pcommon.Timestamp { // addSingleSummaryDataPoint converts pt to len(QuantileValues) + 2 samples. func addSingleSummaryDataPoint(pt pmetric.SummaryDataPoint, resource pcommon.Resource, metric pmetric.Metric, settings Settings, - tsMap map[string]*prompb.TimeSeries) { + tsMap map[string]*prompb.TimeSeries, baseName string) { timestamp := convertTimeStamp(pt.Timestamp()) - // sum and count of the summary should append suffix to baseName - baseName := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes) baseLabels := createAttributes(resource, pt.Attributes(), settings.ExternalLabels) createLabels := func(name string, extras ...string) []prompb.Label { @@ -472,7 +463,7 @@ func addSingleSummaryDataPoint(pt pmetric.SummaryDataPoint, resource pcommon.Res labels = append(labels, prompb.Label{Name: extras[extrasIdx], Value: extras[extrasIdx+1]}) } - labels = append(labels, prompb.Label{Name: nameStr, Value: name}) + labels = append(labels, prompb.Label{Name: model.MetricNameLabel, Value: name}) return labels } @@ -485,6 +476,7 @@ func addSingleSummaryDataPoint(pt pmetric.SummaryDataPoint, resource pcommon.Res if pt.Flags().NoRecordedValue() { sum.Value = math.Float64frombits(value.StaleNaN) } + // sum and count of the summary should append suffix to baseName sumlabels := createLabels(baseName + sumStr) addSample(tsMap, sum, sumlabels, metric.Type().String()) @@ -518,7 +510,7 @@ func addSingleSummaryDataPoint(pt pmetric.SummaryDataPoint, resource pcommon.Res startTimestamp := pt.StartTimestamp() if settings.ExportCreatedMetric && startTimestamp != 0 { createdLabels := createLabels(baseName + createdSuffix) - addCreatedTimeSeriesIfNeeded(tsMap, createdLabels, startTimestamp, metric.Type().String()) + addCreatedTimeSeriesIfNeeded(tsMap, createdLabels, startTimestamp, pt.Timestamp(), metric.Type().String()) } } @@ -528,15 +520,17 @@ func addCreatedTimeSeriesIfNeeded( series map[string]*prompb.TimeSeries, labels []prompb.Label, startTimestamp pcommon.Timestamp, + timestamp pcommon.Timestamp, metricType string, ) { - sig := timeSeriesSignature(metricType, &labels) + sig := timeSeriesSignature(metricType, labels) if _, ok := series[sig]; !ok { series[sig] = &prompb.TimeSeries{ Labels: labels, Samples: []prompb.Sample{ { // convert ns to ms - Value: float64(convertTimeStamp(startTimestamp)), + Value: float64(convertTimeStamp(startTimestamp)), + Timestamp: convertTimeStamp(timestamp), }, }, } @@ -570,7 +564,7 @@ func addResourceTargetInfo(resource pcommon.Resource, settings Settings, timesta if len(settings.Namespace) > 0 { name = settings.Namespace + "_" + name } - labels := createAttributes(resource, attributes, settings.ExternalLabels, nameStr, name) + labels := createAttributes(resource, attributes, settings.ExternalLabels, model.MetricNameLabel, name) sample := &prompb.Sample{ Value: float64(1), // convert ns to ms diff --git a/storage/remote/otlptranslator/prometheusremotewrite/histograms.go b/storage/remote/otlptranslator/prometheusremotewrite/histograms.go index 0a528f6074..14cea32c37 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/histograms.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/histograms.go @@ -29,12 +29,13 @@ func addSingleExponentialHistogramDataPoint( resource, pt.Attributes(), settings.ExternalLabels, - model.MetricNameLabel, metric, + model.MetricNameLabel, + metric, ) sig := timeSeriesSignature( pmetric.MetricTypeExponentialHistogram.String(), - &labels, + labels, ) ts, ok := series[sig] if !ok { @@ -76,7 +77,17 @@ func exponentialToNativeHistogram(p pmetric.ExponentialHistogramDataPoint) (prom nSpans, nDeltas := convertBucketsLayout(p.Negative(), scaleDown) h := prompb.Histogram{ - Schema: scale, + // The counter reset detection must be compatible with Prometheus to + // safely set ResetHint to NO. This is not ensured currently. + // Sending a sample that triggers counter reset but with ResetHint==NO + // would lead to Prometheus panic as it does not double check the hint. + // Thus we're explicitly saying UNKNOWN here, which is always safe. + // TODO: using created time stamp should be accurate, but we + // need to know here if it was used for the detection. + // Ref: https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/28663#issuecomment-1810577303 + // Counter reset detection in Prometheus: https://github.com/prometheus/prometheus/blob/f997c72f294c0f18ca13fa06d51889af04135195/tsdb/chunkenc/histogram.go#L232 + ResetHint: prompb.Histogram_UNKNOWN, + Schema: scale, ZeroCount: &prompb.Histogram_ZeroCountInt{ZeroCountInt: p.ZeroCount()}, // TODO use zero_threshold, if set, see diff --git a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go index 6e8f42fae0..fb141034ad 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/metrics_to_prw.go @@ -23,9 +23,10 @@ type Settings struct { DisableTargetInfo bool ExportCreatedMetric bool AddMetricSuffixes bool + SendMetadata bool } -// FromMetrics converts pmetric.Metrics to prometheus remote write format. +// FromMetrics converts pmetric.Metrics to Prometheus remote write format. func FromMetrics(md pmetric.Metrics, settings Settings) (tsMap map[string]*prompb.TimeSeries, errs error) { tsMap = make(map[string]*prompb.TimeSeries) @@ -51,6 +52,8 @@ func FromMetrics(md pmetric.Metrics, settings Settings) (tsMap map[string]*promp continue } + promName := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes) + // handle individual metric based on type //exhaustive:enforce switch metric.Type() { @@ -60,7 +63,7 @@ func FromMetrics(md pmetric.Metrics, settings Settings) (tsMap map[string]*promp errs = multierr.Append(errs, fmt.Errorf("empty data points. %s is dropped", metric.Name())) } for x := 0; x < dataPoints.Len(); x++ { - addSingleGaugeNumberDataPoint(dataPoints.At(x), resource, metric, settings, tsMap) + addSingleGaugeNumberDataPoint(dataPoints.At(x), resource, metric, settings, tsMap, promName) } case pmetric.MetricTypeSum: dataPoints := metric.Sum().DataPoints() @@ -68,7 +71,7 @@ func FromMetrics(md pmetric.Metrics, settings Settings) (tsMap map[string]*promp errs = multierr.Append(errs, fmt.Errorf("empty data points. %s is dropped", metric.Name())) } for x := 0; x < dataPoints.Len(); x++ { - addSingleSumNumberDataPoint(dataPoints.At(x), resource, metric, settings, tsMap) + addSingleSumNumberDataPoint(dataPoints.At(x), resource, metric, settings, tsMap, promName) } case pmetric.MetricTypeHistogram: dataPoints := metric.Histogram().DataPoints() @@ -76,19 +79,18 @@ func FromMetrics(md pmetric.Metrics, settings Settings) (tsMap map[string]*promp errs = multierr.Append(errs, fmt.Errorf("empty data points. %s is dropped", metric.Name())) } for x := 0; x < dataPoints.Len(); x++ { - addSingleHistogramDataPoint(dataPoints.At(x), resource, metric, settings, tsMap) + addSingleHistogramDataPoint(dataPoints.At(x), resource, metric, settings, tsMap, promName) } case pmetric.MetricTypeExponentialHistogram: dataPoints := metric.ExponentialHistogram().DataPoints() if dataPoints.Len() == 0 { errs = multierr.Append(errs, fmt.Errorf("empty data points. %s is dropped", metric.Name())) } - name := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes) for x := 0; x < dataPoints.Len(); x++ { errs = multierr.Append( errs, addSingleExponentialHistogramDataPoint( - name, + promName, dataPoints.At(x), resource, settings, @@ -102,7 +104,7 @@ func FromMetrics(md pmetric.Metrics, settings Settings) (tsMap map[string]*promp errs = multierr.Append(errs, fmt.Errorf("empty data points. %s is dropped", metric.Name())) } for x := 0; x < dataPoints.Len(); x++ { - addSingleSummaryDataPoint(dataPoints.At(x), resource, metric, settings, tsMap) + addSingleSummaryDataPoint(dataPoints.At(x), resource, metric, settings, tsMap, promName) } default: errs = multierr.Append(errs, errors.New("unsupported metric type")) diff --git a/storage/remote/otlptranslator/prometheusremotewrite/number_data_points.go b/storage/remote/otlptranslator/prometheusremotewrite/number_data_points.go index 85684ad6de..b5bd8765fe 100644 --- a/storage/remote/otlptranslator/prometheusremotewrite/number_data_points.go +++ b/storage/remote/otlptranslator/prometheusremotewrite/number_data_points.go @@ -13,11 +13,9 @@ import ( "github.com/prometheus/prometheus/prompb" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - - prometheustranslator "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus" ) -// addSingleSumNumberDataPoint converts the Gauge metric data point to a +// addSingleGaugeNumberDataPoint converts the Gauge metric data point to a // Prometheus time series with samples and labels. The result is stored in the // series map. func addSingleGaugeNumberDataPoint( @@ -26,13 +24,14 @@ func addSingleGaugeNumberDataPoint( metric pmetric.Metric, settings Settings, series map[string]*prompb.TimeSeries, + name string, ) { - name := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes) labels := createAttributes( resource, pt.Attributes(), settings.ExternalLabels, - model.MetricNameLabel, name, + model.MetricNameLabel, + name, ) sample := &prompb.Sample{ // convert ns to ms @@ -59,8 +58,8 @@ func addSingleSumNumberDataPoint( metric pmetric.Metric, settings Settings, series map[string]*prompb.TimeSeries, + name string, ) { - name := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes) labels := createAttributes( resource, pt.Attributes(), @@ -82,7 +81,7 @@ func addSingleSumNumberDataPoint( } sig := addSample(series, sample, labels, metric.Type().String()) - if ts, ok := series[sig]; sig != "" && ok { + if ts := series[sig]; sig != "" && ts != nil { exemplars := getPromExemplars[pmetric.NumberDataPoint](pt) ts.Exemplars = append(ts.Exemplars, exemplars...) } @@ -90,15 +89,18 @@ func addSingleSumNumberDataPoint( // add _created time series if needed if settings.ExportCreatedMetric && metric.Sum().IsMonotonic() { startTimestamp := pt.StartTimestamp() - if startTimestamp != 0 { - createdLabels := createAttributes( - resource, - pt.Attributes(), - settings.ExternalLabels, - nameStr, - name+createdSuffix, - ) - addCreatedTimeSeriesIfNeeded(series, createdLabels, startTimestamp, metric.Type().String()) + if startTimestamp == 0 { + return } + + createdLabels := make([]prompb.Label, len(labels)) + copy(createdLabels, labels) + for i, l := range createdLabels { + if l.Name == model.MetricNameLabel { + createdLabels[i].Value = name + createdSuffix + break + } + } + addCreatedTimeSeriesIfNeeded(series, createdLabels, startTimestamp, pt.Timestamp(), metric.Type().String()) } } diff --git a/storage/remote/otlptranslator/prometheusremotewrite/otlp_to_openmetrics_metadata.go b/storage/remote/otlptranslator/prometheusremotewrite/otlp_to_openmetrics_metadata.go new file mode 100644 index 0000000000..e43797212e --- /dev/null +++ b/storage/remote/otlptranslator/prometheusremotewrite/otlp_to_openmetrics_metadata.go @@ -0,0 +1,66 @@ +// DO NOT EDIT. COPIED AS-IS. SEE ../README.md + +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package prometheusremotewrite // import "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheusremotewrite" + +import ( + "github.com/prometheus/prometheus/prompb" + "go.opentelemetry.io/collector/pdata/pmetric" + + prometheustranslator "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus" +) + +func otelMetricTypeToPromMetricType(otelMetric pmetric.Metric) prompb.MetricMetadata_MetricType { + switch otelMetric.Type() { + case pmetric.MetricTypeGauge: + return prompb.MetricMetadata_GAUGE + case pmetric.MetricTypeSum: + metricType := prompb.MetricMetadata_GAUGE + if otelMetric.Sum().IsMonotonic() { + metricType = prompb.MetricMetadata_COUNTER + } + return metricType + case pmetric.MetricTypeHistogram: + return prompb.MetricMetadata_HISTOGRAM + case pmetric.MetricTypeSummary: + return prompb.MetricMetadata_SUMMARY + case pmetric.MetricTypeExponentialHistogram: + return prompb.MetricMetadata_HISTOGRAM + } + return prompb.MetricMetadata_UNKNOWN +} + +func OtelMetricsToMetadata(md pmetric.Metrics, addMetricSuffixes bool) []*prompb.MetricMetadata { + resourceMetricsSlice := md.ResourceMetrics() + + metadataLength := 0 + for i := 0; i < resourceMetricsSlice.Len(); i++ { + scopeMetricsSlice := resourceMetricsSlice.At(i).ScopeMetrics() + for j := 0; j < scopeMetricsSlice.Len(); j++ { + metadataLength += scopeMetricsSlice.At(j).Metrics().Len() + } + } + + var metadata = make([]*prompb.MetricMetadata, 0, metadataLength) + for i := 0; i < resourceMetricsSlice.Len(); i++ { + resourceMetrics := resourceMetricsSlice.At(i) + scopeMetricsSlice := resourceMetrics.ScopeMetrics() + + for j := 0; j < scopeMetricsSlice.Len(); j++ { + scopeMetrics := scopeMetricsSlice.At(j) + for k := 0; k < scopeMetrics.Metrics().Len(); k++ { + metric := scopeMetrics.Metrics().At(k) + entry := prompb.MetricMetadata{ + Type: otelMetricTypeToPromMetricType(metric), + MetricFamilyName: prometheustranslator.BuildCompliantName(metric, "", addMetricSuffixes), + Help: metric.Description(), + } + metadata = append(metadata, &entry) + } + } + } + + return metadata +} diff --git a/storage/remote/otlptranslator/update-copy.sh b/storage/remote/otlptranslator/update-copy.sh index 10dc194d04..f90be5eedc 100755 --- a/storage/remote/otlptranslator/update-copy.sh +++ b/storage/remote/otlptranslator/update-copy.sh @@ -1,7 +1,7 @@ #!/bin/bash set -xe -OTEL_VERSION=v0.88.0 +OTEL_VERSION=v0.95.0 git clone https://github.com/open-telemetry/opentelemetry-collector-contrib ./tmp cd ./tmp From 78f46bcccaf7b08306e5d5482ce5306d6662db5d Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 22 Feb 2024 09:14:52 +0000 Subject: [PATCH 023/253] tsdb/wlog tests: remove unnecessary sleep check Sleep() is documented to return immediately on negative or zero input. Signed-off-by: Bryan Boreham --- tsdb/wlog/watcher_test.go | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/tsdb/wlog/watcher_test.go b/tsdb/wlog/watcher_test.go index 871640a7cf..ff006cb817 100644 --- a/tsdb/wlog/watcher_test.go +++ b/tsdb/wlog/watcher_test.go @@ -59,46 +59,36 @@ type writeToMock struct { seriesLock sync.Mutex seriesSegmentIndexes map[chunks.HeadSeriesRef]int - // delay reads with a short sleep + // If nonzero, delay reads with a short sleep. delay time.Duration } func (wtm *writeToMock) Append(s []record.RefSample) bool { - if wtm.delay > 0 { - time.Sleep(wtm.delay) - } + time.Sleep(wtm.delay) wtm.samplesAppended += len(s) return true } func (wtm *writeToMock) AppendExemplars(e []record.RefExemplar) bool { - if wtm.delay > 0 { - time.Sleep(wtm.delay) - } + time.Sleep(wtm.delay) wtm.exemplarsAppended += len(e) return true } func (wtm *writeToMock) AppendHistograms(h []record.RefHistogramSample) bool { - if wtm.delay > 0 { - time.Sleep(wtm.delay) - } + time.Sleep(wtm.delay) wtm.histogramsAppended += len(h) return true } func (wtm *writeToMock) AppendFloatHistograms(fh []record.RefFloatHistogramSample) bool { - if wtm.delay > 0 { - time.Sleep(wtm.delay) - } + time.Sleep(wtm.delay) wtm.floatHistogramsAppended += len(fh) return true } func (wtm *writeToMock) StoreSeries(series []record.RefSeries, index int) { - if wtm.delay > 0 { - time.Sleep(wtm.delay) - } + time.Sleep(wtm.delay) wtm.UpdateSeriesSegment(series, index) } From a975a830796aa4ff2b6b9aa688d12eb4a3a6cdf8 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 22 Feb 2024 09:19:18 +0000 Subject: [PATCH 024/253] tsdb: clean up Watcher debug messages Print lastSegment after it gets initialized. Move variable declaration to first use. Signed-off-by: Bryan Boreham --- tsdb/wlog/watcher.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index 525515221d..bd74c1b024 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -262,9 +262,6 @@ func (w *Watcher) loop() { // Run the watcher, which will tail the WAL until the quit channel is closed // or an error case is hit. func (w *Watcher) Run() error { - var lastSegment int - var err error - // We want to ensure this is false across iterations since // Run will be called again if there was a failure to read the WAL. w.sendSamples = false @@ -289,19 +286,19 @@ func (w *Watcher) Run() error { return err } - level.Debug(w.logger).Log("msg", "Tailing WAL", "lastCheckpoint", lastCheckpoint, "checkpointIndex", checkpointIndex, "currentSegment", currentSegment, "lastSegment", lastSegment) + level.Debug(w.logger).Log("msg", "Tailing WAL", "lastCheckpoint", lastCheckpoint, "checkpointIndex", checkpointIndex, "currentSegment", currentSegment) for !isClosed(w.quit) { w.currentSegmentMetric.Set(float64(currentSegment)) - level.Debug(w.logger).Log("msg", "Processing segment", "currentSegment", currentSegment) // Reset the value of lastSegment each iteration, this is to avoid having to wait too long for // between reads if we're reading a segment that is not the most recent segment after startup. - _, lastSegment, err = w.firstAndLast() + _, lastSegment, err := w.firstAndLast() if err != nil { return fmt.Errorf("wal.Segments: %w", err) } tail := currentSegment >= lastSegment + level.Debug(w.logger).Log("msg", "Processing segment", "currentSegment", currentSegment, "lastSegment", lastSegment) // On start, after reading the existing WAL for series records, we have a pointer to what is the latest segment. // On subsequent calls to this function, currentSegment will have been incremented and we should open that segment. if err := w.watch(currentSegment, tail); err != nil && !errors.Is(err, ErrIgnorable) { From 814b920e8a6345d35712b5857ebd4cb5e90fc107 Mon Sep 17 00:00:00 2001 From: Augustin Husson Date: Thu, 22 Feb 2024 10:21:59 +0100 Subject: [PATCH 025/253] Cut v2.50.0 (#13612) Signed-off-by: Augustin Husson --- CHANGELOG.md | 7 ++----- VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 ++-- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3f13b432..0b8a42c8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,6 @@ # Changelog -## 2.50.0-rc.1 / 2024-02-19 - -[BUGFIX] Azure SD: Fix SD crashing when it finds a VM scale set. #13578 - -## 2.50.0-rc.0 / 2024-02-07 +## 2.50.0 / 2024-02-22 * [CHANGE] Remote Write: Error `storage.ErrTooOldSample` is now generating HTTP error 400 instead of HTTP error 500. #13335 * [FEATURE] Remote Write: Drop old inmemory samples. Activated using the config entry `sample_age_limit`. #13002 @@ -30,6 +26,7 @@ * [ENHANCEMENT] Various improvements and optimizations on Native Histograms. #13267, #13215, #13276 #13289, #13340 * [BUGFIX] Scraping: Fix quality value in HTTP Accept header. #13313 * [BUGFIX] UI: Fix usage of the function `time()` that was crashing. #13371 +* [BUGFIX] Azure SD: Fix SD crashing when it finds a VM scale set. #13578 ## 2.49.1 / 2024-01-15 diff --git a/VERSION b/VERSION index 782980c611..9e29315acb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.50.0-rc.1 +2.50.0 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index 3975c7a4b4..fb199ff5db 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.50.0-rc.1", + "version": "0.50.0", "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.50.0-rc.1", + "@prometheus-io/lezer-promql": "0.50.0", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index 0eb5b3473f..8490a37208 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.50.0-rc.1", + "version": "0.50.0", "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 dab335a77b..62aad79727 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.50.0-rc.1", + "version": "0.50.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.50.0-rc.1", + "version": "0.50.0", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.50.0-rc.1", + "version": "0.50.0", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.50.0-rc.1", + "@prometheus-io/lezer-promql": "0.50.0", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.50.0-rc.1", + "version": "0.50.0", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.50.0-rc.1", + "version": "0.50.0", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.0-rc.1", + "@prometheus-io/codemirror-promql": "0.50.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index 5b2cb68e5d..af6bc6ddd0 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.50.0-rc.1" + "version": "0.50.0" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index ab75cda784..1164b0f774 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.50.0-rc.1", + "version": "0.50.0", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.0-rc.1", + "@prometheus-io/codemirror-promql": "0.50.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 545c28d92347508b0b97498518dca260ba523c7b Mon Sep 17 00:00:00 2001 From: Augustin Husson Date: Thu, 22 Feb 2024 10:23:26 +0100 Subject: [PATCH 026/253] update v2.51 release date (#13606) * update v2.51 release date Signed-off-by: Augustin Husson * add Bryan as a next release shepherd Signed-off-by: Augustin Husson --------- Signed-off-by: Augustin Husson --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 6815308f47..2dfa9cc451 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -55,7 +55,7 @@ Release cadence of first pre-releases being cut is 6 weeks. | v2.48 | 2023-10-04 | Levi Harrison (GitHub: @LeviHarrison) | | v2.49 | 2023-12-05 | Bartek Plotka (GitHub: @bwplotka) | | v2.50 | 2024-01-16 | Augustin Husson (GitHub: @nexucis) | -| v2.51 | 2024-02-13 | **searching for volunteer** | +| v2.51 | 2024-04-01 | Bryan Boreham (GitHub: @bboreham) | If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice. From 6ed56c9f0496459da1ad127feca4a2d45eb6e53e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 22 Feb 2024 09:32:46 +0000 Subject: [PATCH 027/253] WAL watcher: improve comments Clarify in the first comment that it is `watch()` that waits, and reduce verbiage. The second comment was slightly contradictory to the first and otherwise didn't seem to add much, since `currentSegment` was incremented just a few lines later. Signed-off-by: Bryan Boreham --- tsdb/wlog/watcher.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index bd74c1b024..6994d2dd8a 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -290,8 +290,8 @@ func (w *Watcher) Run() error { for !isClosed(w.quit) { w.currentSegmentMetric.Set(float64(currentSegment)) - // Reset the value of lastSegment each iteration, this is to avoid having to wait too long for - // between reads if we're reading a segment that is not the most recent segment after startup. + // Re-check on each iteration in case a new segment was added, + // because watch() will wait for notifications on the last segment. _, lastSegment, err := w.firstAndLast() if err != nil { return fmt.Errorf("wal.Segments: %w", err) @@ -299,8 +299,6 @@ func (w *Watcher) Run() error { tail := currentSegment >= lastSegment level.Debug(w.logger).Log("msg", "Processing segment", "currentSegment", currentSegment, "lastSegment", lastSegment) - // On start, after reading the existing WAL for series records, we have a pointer to what is the latest segment. - // On subsequent calls to this function, currentSegment will have been incremented and we should open that segment. if err := w.watch(currentSegment, tail); err != nil && !errors.Is(err, ErrIgnorable) { return err } From 92e381b8a3dd2cf9936130c2e3bd3646880d01f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 31 May 2022 10:31:20 +0100 Subject: [PATCH 028/253] Add a scrape benchmark with gzipped responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Łukasz Mierzwa --- scrape/scrape_test.go | 74 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index badeee2d1c..eefa7be66f 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -25,6 +25,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "strconv" "strings" "sync" "testing" @@ -3518,3 +3519,76 @@ func TestPickSchema(t *testing.T) { require.Equal(t, tc.schema, schema) } } + +func BenchmarkTargetScraperGzip(b *testing.B) { + scenarios := []struct { + metricsCount int + body []byte + }{ + {metricsCount: 1}, + {metricsCount: 100}, + {metricsCount: 1000}, + {metricsCount: 10000}, + {metricsCount: 100000}, + } + + for i := 0; i < len(scenarios); i++ { + var buf bytes.Buffer + var name string + gw := gzip.NewWriter(&buf) + for j := 0; j < scenarios[i].metricsCount; j++ { + name = fmt.Sprintf("go_memstats_alloc_bytes_total_%d", j) + fmt.Fprintf(gw, "# HELP %s Total number of bytes allocated, even if freed.\n", name) + fmt.Fprintf(gw, "# TYPE %s counter\n", name) + fmt.Fprintf(gw, "%s %d\n", name, i*j) + } + gw.Close() + scenarios[i].body = buf.Bytes() + } + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", `text/plain; version=0.0.4`) + w.Header().Set("Content-Encoding", "gzip") + for _, scenario := range scenarios { + if strconv.Itoa(scenario.metricsCount) == r.URL.Query()["count"][0] { + w.Write(scenario.body) + return + } + } + w.WriteHeader(http.StatusBadRequest) + }) + + server := httptest.NewServer(handler) + defer server.Close() + + serverURL, err := url.Parse(server.URL) + if err != nil { + panic(err) + } + + client, err := config_util.NewClientFromConfig(config_util.DefaultHTTPClientConfig, "test_job") + if err != nil { + panic(err) + } + + for _, scenario := range scenarios { + b.Run(fmt.Sprintf("metrics=%d", scenario.metricsCount), func(b *testing.B) { + ts := &targetScraper{ + Target: &Target{ + labels: labels.FromStrings( + model.SchemeLabel, serverURL.Scheme, + model.AddressLabel, serverURL.Host, + ), + params: url.Values{"count": []string{strconv.Itoa(scenario.metricsCount)}}, + }, + client: client, + timeout: time.Second, + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err = ts.scrape(context.Background()) + require.NoError(b, err) + } + }) + } +} From 5597020a608f32fc6a5f1c081585bb8c9516d627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 31 May 2022 10:46:49 +0100 Subject: [PATCH 029/253] Use github.com/klauspost/compress for gzip and zlib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit klauspost/compress is a high quality drop-in replacement for common Go compression libraries. Since Prometheus sends out a lot of HTTP requests that often return compressed output having improved compression libraries helps to save cpu & memory resources. On a test Prometheus server I was able to see cpu reduction from 31 to 30 cores. Benchmark results: name old time/op new time/op delta TargetScraperGzip/metrics=1-8 69.4µs ± 4% 69.2µs ± 3% ~ (p=0.122 n=50+50) TargetScraperGzip/metrics=100-8 84.3µs ± 2% 80.9µs ± 2% -4.02% (p=0.000 n=48+46) TargetScraperGzip/metrics=1000-8 296µs ± 1% 274µs ±14% -7.35% (p=0.000 n=47+45) TargetScraperGzip/metrics=10000-8 2.06ms ± 1% 1.66ms ± 2% -19.34% (p=0.000 n=47+45) TargetScraperGzip/metrics=100000-8 20.9ms ± 2% 17.5ms ± 3% -16.50% (p=0.000 n=49+50) name old alloc/op new alloc/op delta TargetScraperGzip/metrics=1-8 6.06kB ± 0% 6.07kB ± 0% +0.24% (p=0.000 n=48+48) TargetScraperGzip/metrics=100-8 7.04kB ± 0% 6.89kB ± 0% -2.17% (p=0.000 n=49+50) TargetScraperGzip/metrics=1000-8 9.02kB ± 0% 8.35kB ± 1% -7.49% (p=0.000 n=50+50) TargetScraperGzip/metrics=10000-8 18.1kB ± 1% 16.1kB ± 2% -10.87% (p=0.000 n=47+47) TargetScraperGzip/metrics=100000-8 1.21MB ± 0% 1.01MB ± 2% -16.69% (p=0.000 n=36+50) name old allocs/op new allocs/op delta TargetScraperGzip/metrics=1-8 71.0 ± 0% 72.0 ± 0% +1.41% (p=0.000 n=50+50) TargetScraperGzip/metrics=100-8 81.0 ± 0% 76.0 ± 0% -6.17% (p=0.000 n=50+50) TargetScraperGzip/metrics=1000-8 92.0 ± 0% 83.0 ± 0% -9.78% (p=0.000 n=50+50) TargetScraperGzip/metrics=10000-8 93.0 ± 0% 91.0 ± 0% -2.15% (p=0.000 n=50+50) TargetScraperGzip/metrics=100000-8 111 ± 0% 135 ± 1% +21.89% (p=0.000 n=40+50) Signed-off-by: Łukasz Mierzwa --- cmd/promtool/archive.go | 3 ++- model/textparse/promparse_test.go | 5 +++-- scrape/scrape.go | 2 +- util/httputil/compression.go | 5 +++-- util/httputil/compression_test.go | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cmd/promtool/archive.go b/cmd/promtool/archive.go index 6edb741acd..7b565c57cc 100644 --- a/cmd/promtool/archive.go +++ b/cmd/promtool/archive.go @@ -15,9 +15,10 @@ package main import ( "archive/tar" - "compress/gzip" "fmt" "os" + + "github.com/klauspost/compress/gzip" ) const filePerm = 0o666 diff --git a/model/textparse/promparse_test.go b/model/textparse/promparse_test.go index d82bfe598d..cbfc8aa6cc 100644 --- a/model/textparse/promparse_test.go +++ b/model/textparse/promparse_test.go @@ -15,15 +15,16 @@ package textparse import ( "bytes" - "compress/gzip" "errors" "io" "os" "testing" + "github.com/klauspost/compress/gzip" + "github.com/stretchr/testify/require" + "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" - "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/util/testutil" diff --git a/scrape/scrape.go b/scrape/scrape.go index dfa945852c..de35b9e408 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -16,7 +16,6 @@ package scrape import ( "bufio" "bytes" - "compress/gzip" "context" "errors" "fmt" @@ -31,6 +30,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/klauspost/compress/gzip" config_util "github.com/prometheus/common/config" "github.com/prometheus/common/model" "github.com/prometheus/common/version" diff --git a/util/httputil/compression.go b/util/httputil/compression.go index b96c088cbb..9a8a666453 100644 --- a/util/httputil/compression.go +++ b/util/httputil/compression.go @@ -14,11 +14,12 @@ package httputil import ( - "compress/gzip" - "compress/zlib" "io" "net/http" "strings" + + "github.com/klauspost/compress/gzip" + "github.com/klauspost/compress/zlib" ) const ( diff --git a/util/httputil/compression_test.go b/util/httputil/compression_test.go index 8512797613..2db6810bd7 100644 --- a/util/httputil/compression_test.go +++ b/util/httputil/compression_test.go @@ -15,13 +15,13 @@ package httputil import ( "bytes" - "compress/gzip" - "compress/zlib" "io" "net/http" "net/http/httptest" "testing" + "github.com/klauspost/compress/gzip" + "github.com/klauspost/compress/zlib" "github.com/stretchr/testify/require" ) From daeef6ffc383d44d3518fc1ff91990febc62dc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Mon, 13 Jun 2022 13:04:15 +0100 Subject: [PATCH 030/253] Add lint checks for gzip/zlib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we want to use a faster gzip/zlib libraries we should add a lint check so that it's used everywhere Signed-off-by: Łukasz Mierzwa --- .golangci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index 166b2e0d48..cc290b3343 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -60,6 +60,10 @@ linters-settings: desc: "Use github.com/grafana/regexp instead of regexp" - pkg: "github.com/pkg/errors" desc: "Use 'errors' or 'fmt' instead of github.com/pkg/errors" + - pkg: "gzip" + desc: "Use github.com/klauspost/compress instead of gzip" + - pkg: "zlib" + desc: "Use github.com/klauspost/compress instead of zlib" errcheck: exclude-functions: # Don't flag lines such as "io.Copy(io.Discard, resp.Body)". From 08832e2db87886f9965999e76f1921ff10ce39d0 Mon Sep 17 00:00:00 2001 From: Manik Rana Date: Fri, 23 Feb 2024 05:31:39 -0500 Subject: [PATCH 031/253] histogram: add UI tests for rendering histogram (#13631) * histogram: add tests for rendering histograms Signed-off-by: Manik Rana * histogram: add tests for rendering histograms Signed-off-by: Manik Rana * chore: remove unused import Signed-off-by: Manik Rana --------- Signed-off-by: Manik Rana --- .../src/pages/graph/DataTable.test.tsx | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/web/ui/react-app/src/pages/graph/DataTable.test.tsx b/web/ui/react-app/src/pages/graph/DataTable.test.tsx index 1252b5bfcf..61bc55486b 100755 --- a/web/ui/react-app/src/pages/graph/DataTable.test.tsx +++ b/web/ui/react-app/src/pages/graph/DataTable.test.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; -import { shallow } from 'enzyme'; +import { mount, shallow } from 'enzyme'; import DataTable, { DataTableProps } from './DataTable'; -import HistogramString, { HistogramStringProps } from './DataTable'; import { Alert, Table } from 'reactstrap'; import SeriesName from './SeriesName'; @@ -130,7 +129,7 @@ describe('DataTable', () => { }, useLocalTime: false, }; - const dataTable = shallow(); + const dataTable = mount(); it('renders a table', () => { const table = dataTable.find(Table); @@ -142,10 +141,30 @@ describe('DataTable', () => { it('renders rows', () => { const table = dataTable.find(Table); + const histogramData = [{ + count: '10', + sum: '3.3', + buckets: [ + [1, '-1', '-0.5', '2'], + [3, '-0.5', '0.5', '3'], + [0, '0.5', '1', '5'], + ] + }, + { + count: '5', + sum: '1.11', + buckets: [ + [0, '0.5', '1', '2'], + [0, '1', '2', '3'], + ], + }]; table.find('tr').forEach((row, idx) => { - expect(row.find(SeriesName)).toHaveLength(1); - // TODO(beorn7): This doesn't actually test the rendoring yet. Need to trigger it somehow. - expect(row.find('td').at(1).text()).toEqual(` `); + const seriesNameComponent = dataTable.find('SeriesName'); + expect(seriesNameComponent).toHaveLength(dataTableProps.data?.result.length as number); + + const histogramStringComponent = row.find('HistogramString'); + expect(histogramStringComponent).toHaveLength(1); + expect(histogramStringComponent.prop('h')).toEqual(histogramData[idx]); }); }); }); From cc5dc6a61b7aff425740e181c994e0ae1590e1ee Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 24 Mar 2023 17:58:25 +0000 Subject: [PATCH 032/253] labels: use Equal instead of DeepEqual This will work better with a different data structure. Signed-off-by: Bryan Boreham --- model/labels/labels_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index 0221c66eb4..043f9ae751 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -114,7 +114,7 @@ func TestLabels_MatchLabels(t *testing.T) { for i, test := range tests { got := labels.MatchLabels(test.on, test.providedNames...) - require.Equal(t, test.expected, got, "unexpected labelset for test case %d", i) + require.True(t, Equal(test.expected, got), "unexpected labelset for test case %d", i) } } @@ -207,7 +207,7 @@ func TestLabels_WithoutEmpty(t *testing.T) { }, } { t.Run("", func(t *testing.T) { - require.Equal(t, test.expected, test.input.WithoutEmpty()) + require.True(t, Equal(test.expected, test.input.WithoutEmpty())) }) } } @@ -647,7 +647,7 @@ func TestBuilder(t *testing.T) { b.Keep(tcase.keep...) } b.Del(tcase.del...) - require.Equal(t, tcase.want, b.Labels()) + require.True(t, Equal(tcase.want, b.Labels())) // Check what happens when we call Range and mutate the builder. b.Range(func(l Label) { @@ -694,14 +694,14 @@ func TestScratchBuilder(t *testing.T) { }, } { t.Run(fmt.Sprint(i), func(t *testing.T) { - b := ScratchBuilder{} + b := NewScratchBuilder(len(tcase.add)) for _, lbl := range tcase.add { b.Add(lbl.Name, lbl.Value) } b.Sort() - require.Equal(t, tcase.want, b.Labels()) + require.True(t, Equal(tcase.want, b.Labels())) b.Assign(tcase.want) - require.Equal(t, tcase.want, b.Labels()) + require.True(t, Equal(tcase.want, b.Labels())) }) } } From bb82a57e640ec903a4d747b21d1fcb81d431166d Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 23 Nov 2023 17:10:44 +0000 Subject: [PATCH 033/253] Labels: Call NewScratchBuilder in test_utils Signed-off-by: Bryan Boreham --- model/labels/test_utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/labels/test_utils.go b/model/labels/test_utils.go index 05b8168825..d060def481 100644 --- a/model/labels/test_utils.go +++ b/model/labels/test_utils.go @@ -50,7 +50,7 @@ func ReadLabels(fn string, n int) ([]Labels, error) { defer f.Close() scanner := bufio.NewScanner(f) - b := ScratchBuilder{} + b := NewScratchBuilder(0) var mets []Labels hashes := map[uint64]struct{}{} From 5aa44738947fed58ab2800b32d6fdd558dcc0a5e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 5 Dec 2023 18:31:19 +0000 Subject: [PATCH 034/253] labels tests: extend TestBuilder Start with empty base labels, also check new and re-used symbol tables Signed-off-by: Bryan Boreham --- model/labels/labels_test.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index 043f9ae751..c2ac6d63a0 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -569,6 +569,7 @@ func TestLabels_BytesWithoutLabels(t *testing.T) { } func TestBuilder(t *testing.T) { + reuseBuilder := NewBuilderWithSymbolTable(NewSymbolTable()) for i, tcase := range []struct { base Labels del []string @@ -580,6 +581,11 @@ func TestBuilder(t *testing.T) { base: FromStrings("aaa", "111"), want: FromStrings("aaa", "111"), }, + { + base: EmptyLabels(), + set: []Label{{"aaa", "444"}, {"bbb", "555"}, {"ccc", "666"}}, + want: FromStrings("aaa", "444", "bbb", "555", "ccc", "666"), + }, { base: FromStrings("aaa", "111", "bbb", "222", "ccc", "333"), set: []Label{{"aaa", "444"}, {"bbb", "555"}, {"ccc", "666"}}, @@ -638,8 +644,7 @@ func TestBuilder(t *testing.T) { want: FromStrings("aaa", "111", "ddd", "444"), }, } { - t.Run(fmt.Sprint(i), func(t *testing.T) { - b := NewBuilder(tcase.base) + test := func(t *testing.T, b *Builder) { for _, lbl := range tcase.set { b.Set(lbl.Name, lbl.Value) } @@ -656,6 +661,18 @@ func TestBuilder(t *testing.T) { } }) require.Equal(t, tcase.want.BytesWithoutLabels(nil, "aaa", "bbb"), b.Labels().Bytes(nil)) + } + t.Run(fmt.Sprintf("NewBuilder %d", i), func(t *testing.T) { + test(t, NewBuilder(tcase.base)) + }) + t.Run(fmt.Sprintf("NewSymbolTable %d", i), func(t *testing.T) { + b := NewBuilderWithSymbolTable(NewSymbolTable()) + b.Reset(tcase.base) + test(t, b) + }) + t.Run(fmt.Sprintf("reuseBuilder %d", i), func(t *testing.T) { + reuseBuilder.Reset(tcase.base) + test(t, reuseBuilder) }) } t.Run("set_after_del", func(t *testing.T) { From d1af84f6ee52398cf4bf76f490466a687d03e130 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 24 Nov 2023 12:17:28 +0000 Subject: [PATCH 035/253] Labels: move Builder and Reset out of common New internstrings implementation is different. Signed-off-by: Bryan Boreham --- model/labels/labels.go | 19 +++++++++++++++++++ model/labels/labels_common.go | 19 ------------------- model/labels/labels_stringlabels.go | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/model/labels/labels.go b/model/labels/labels.go index b6663dad24..9e74b3d31b 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -371,6 +371,25 @@ func (ls Labels) ReleaseStrings(release func(string)) { } } +// Builder allows modifying Labels. +type Builder struct { + base Labels + del []string + add []Label +} + +// Reset clears all current state for the builder. +func (b *Builder) Reset(base Labels) { + b.base = base + b.del = b.del[:0] + b.add = b.add[:0] + b.base.Range(func(l Label) { + if l.Value == "" { + b.del = append(b.del, l.Name) + } + }) +} + // Labels returns the labels from the builder. // If no modifications were made, the original labels are returned. func (b *Builder) Labels() Labels { diff --git a/model/labels/labels_common.go b/model/labels/labels_common.go index 2a722b84cc..e51001e7d7 100644 --- a/model/labels/labels_common.go +++ b/model/labels/labels_common.go @@ -123,13 +123,6 @@ func FromMap(m map[string]string) Labels { return New(l...) } -// Builder allows modifying Labels. -type Builder struct { - base Labels - del []string - add []Label -} - // NewBuilder returns a new LabelsBuilder. func NewBuilder(base Labels) *Builder { b := &Builder{ @@ -140,18 +133,6 @@ func NewBuilder(base Labels) *Builder { return b } -// Reset clears all current state for the builder. -func (b *Builder) Reset(base Labels) { - b.base = base - b.del = b.del[:0] - b.add = b.add[:0] - b.base.Range(func(l Label) { - if l.Value == "" { - b.del = append(b.del, l.Name) - } - }) -} - // Del deletes the label of the given name. func (b *Builder) Del(ns ...string) *Builder { for _, n := range ns { diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index 3e0488bd07..b84964776c 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -458,6 +458,25 @@ func (ls *Labels) InternStrings(intern func(string) string) { func (ls Labels) ReleaseStrings(release func(string)) { } +// Builder allows modifying Labels. +type Builder struct { + base Labels + del []string + add []Label +} + +// Reset clears all current state for the builder. +func (b *Builder) Reset(base Labels) { + b.base = base + b.del = b.del[:0] + b.add = b.add[:0] + b.base.Range(func(l Label) { + if l.Value == "" { + b.del = append(b.del, l.Name) + } + }) +} + // Labels returns the labels from the builder. // If no modifications were made, the original labels are returned. func (b *Builder) Labels() Labels { From 28191109a80f7290ae6f680733c9856b53dd05b0 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 23 Nov 2023 18:17:45 +0000 Subject: [PATCH 036/253] Labels: add fake versions of SymbolTable apis So we can use them where necessary for internlabels implementation. Signed-off-by: Bryan Boreham --- model/labels/labels.go | 21 +++++++++++++++++++++ model/labels/labels_stringlabels.go | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/model/labels/labels.go b/model/labels/labels.go index 9e74b3d31b..f145dfc5f8 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -420,11 +420,32 @@ type ScratchBuilder struct { add Labels } +// Symbol-table is no-op, just for api parity with dedupelabels. +type SymbolTable struct{} + +func NewSymbolTable() *SymbolTable { return nil } + +func (t *SymbolTable) Len() int { return 0 } + // NewScratchBuilder creates a ScratchBuilder initialized for Labels with n entries. func NewScratchBuilder(n int) ScratchBuilder { return ScratchBuilder{add: make([]Label, 0, n)} } +// NewBuilderWithSymbolTable creates a Builder, for api parity with dedupelabels. +func NewBuilderWithSymbolTable(_ *SymbolTable) *Builder { + return NewBuilder(EmptyLabels()) +} + +// NewScratchBuilderWithSymbolTable creates a ScratchBuilder, for api parity with dedupelabels. +func NewScratchBuilderWithSymbolTable(_ *SymbolTable, n int) ScratchBuilder { + return NewScratchBuilder(n) +} + +func (b *ScratchBuilder) SetSymbolTable(_ *SymbolTable) { + // no-op +} + func (b *ScratchBuilder) Reset() { b.add = b.add[:0] } diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index b84964776c..9ac4e46503 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -681,3 +681,24 @@ func (b *ScratchBuilder) Overwrite(ls *Labels) { marshalLabelsToSizedBuffer(b.add, b.overwriteBuffer) ls.data = yoloString(b.overwriteBuffer) } + +// Symbol-table is no-op, just for api parity with dedupelabels. +type SymbolTable struct{} + +func NewSymbolTable() *SymbolTable { return nil } + +func (t *SymbolTable) Len() int { return 0 } + +// NewBuilderWithSymbolTable creates a Builder, for api parity with dedupelabels. +func NewBuilderWithSymbolTable(_ *SymbolTable) *Builder { + return NewBuilder(EmptyLabels()) +} + +// NewScratchBuilderWithSymbolTable creates a ScratchBuilder, for api parity with dedupelabels. +func NewScratchBuilderWithSymbolTable(_ *SymbolTable, n int) ScratchBuilder { + return NewScratchBuilder(n) +} + +func (b *ScratchBuilder) SetSymbolTable(_ *SymbolTable) { + // no-op +} From d51a5344cd6be0fa058af5e85c4fb42d7737d9ff Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 22 Jan 2024 21:39:24 +0000 Subject: [PATCH 037/253] labels: new version de-duplicating strings in SymbolTables The individual strings for label names and values are held in a table, and each Labels value is a run of varint-encoded indexes into that table. When creating new labels, a sync.Mutex is locked around reads and writes. When reading labels, there is no locking because the table of strings used by those labels is immutable. Signed-off-by: Bryan Boreham --- model/labels/labels_dedupelabels.go | 808 ++++++++++++++++++++++++++ model/labels/sharding_dedupelabels.go | 52 ++ 2 files changed, 860 insertions(+) create mode 100644 model/labels/labels_dedupelabels.go create mode 100644 model/labels/sharding_dedupelabels.go diff --git a/model/labels/labels_dedupelabels.go b/model/labels/labels_dedupelabels.go new file mode 100644 index 0000000000..db6c56b337 --- /dev/null +++ b/model/labels/labels_dedupelabels.go @@ -0,0 +1,808 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build dedupelabels + +package labels + +import ( + "bytes" + "strings" + "sync" + "unsafe" + + "github.com/cespare/xxhash/v2" + "golang.org/x/exp/slices" +) + +// Labels is implemented by a SymbolTable and string holding name/value +// pairs encoded as indexes into the table in varint encoding. +// Names are in alphabetical order. +type Labels struct { + syms *nameTable + data string +} + +// Split SymbolTable into the part used by Labels and the part used by Builder. Only the latter needs the map. + +// This part is used by Labels. All fields are immutable after construction. +type nameTable struct { + byNum []string // This slice header is never changed, even while we are building the symbol table. + symbolTable *SymbolTable // If we need to use it in a Builder. +} + +// SymbolTable is used to map strings into numbers so they can be packed together. +type SymbolTable struct { + mx sync.Mutex + *nameTable + nextNum int + byName map[string]int +} + +const defaultSymbolTableSize = 1024 + +func NewSymbolTable() *SymbolTable { + t := &SymbolTable{ + nameTable: &nameTable{byNum: make([]string, defaultSymbolTableSize)}, + byName: make(map[string]int, defaultSymbolTableSize), + } + t.nameTable.symbolTable = t + return t +} + +func (t *SymbolTable) Len() int { + t.mx.Lock() + defer t.mx.Unlock() + return len(t.byName) +} + +// ToNum maps a string to an integer, adding the string to the table if it is not already there. +// Note: copies the string before adding, in case the caller passed part of +// a buffer that should not be kept alive by this SymbolTable. +func (t *SymbolTable) ToNum(name string) int { + t.mx.Lock() + defer t.mx.Unlock() + return t.toNumUnlocked(name) +} + +func (t *SymbolTable) toNumUnlocked(name string) int { + if i, found := t.byName[name]; found { + return i + } + i := t.nextNum + if t.nextNum == cap(t.byNum) { + // Name table is full; copy to a new one. Don't touch the existing slice. + oldSlice := t.byNum + t.nameTable = &nameTable{byNum: make([]string, cap(oldSlice)*2), symbolTable: t} + copy(t.nameTable.byNum, oldSlice) + } + name = strings.Clone(name) + t.byNum[i] = name + t.byName[name] = i + t.nextNum++ + return i +} + +func (t *SymbolTable) checkNum(name string) (int, bool) { + t.mx.Lock() + defer t.mx.Unlock() + i, bool := t.byName[name] + return i, bool +} + +// ToName maps an integer to a string. +func (t *nameTable) ToName(num int) string { + return t.byNum[num] +} + +func decodeVarint(data string, index int) (int, int) { + // Fast-path for common case of a single byte, value 0..127. + b := data[index] + index++ + if b < 0x80 { + return int(b), index + } + size := int(b & 0x7F) + for shift := uint(7); ; shift += 7 { + // Just panic if we go of the end of data, since all Labels strings are constructed internally and + // malformed data indicates a bug, or memory corruption. + b := data[index] + index++ + size |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + return size, index +} + +func decodeString(t *nameTable, data string, index int) (string, int) { + var num int + num, index = decodeVarint(data, index) + return t.ToName(num), index +} + +// Bytes returns ls as a byte slice. +// It uses non-printing characters and so should not be used for printing. +func (ls Labels) Bytes(buf []byte) []byte { + b := bytes.NewBuffer(buf[:0]) + for i := 0; i < len(ls.data); { + if i > 0 { + b.WriteByte(seps[0]) + } + var name, value string + name, i = decodeString(ls.syms, ls.data, i) + value, i = decodeString(ls.syms, ls.data, i) + b.WriteString(name) + b.WriteByte(seps[0]) + b.WriteString(value) + } + return b.Bytes() +} + +// IsZero implements yaml.IsZeroer - if we don't have this then 'omitempty' fields are always omitted. +func (ls Labels) IsZero() bool { + return len(ls.data) == 0 +} + +// MatchLabels returns a subset of Labels that matches/does not match with the provided label names based on the 'on' boolean. +// If on is set to true, it returns the subset of labels that match with the provided label names and its inverse when 'on' is set to false. +// TODO: This is only used in printing an error message +func (ls Labels) MatchLabels(on bool, names ...string) Labels { + b := NewBuilder(ls) + if on { + b.Keep(names...) + } else { + b.Del(MetricName) + b.Del(names...) + } + return b.Labels() +} + +// Hash returns a hash value for the label set. +// Note: the result is not guaranteed to be consistent across different runs of Prometheus. +func (ls Labels) Hash() uint64 { + // Use xxhash.Sum64(b) for fast path as it's faster. + b := make([]byte, 0, 1024) + for pos := 0; pos < len(ls.data); { + name, newPos := decodeString(ls.syms, ls.data, pos) + value, newPos := decodeString(ls.syms, ls.data, newPos) + if len(b)+len(name)+len(value)+2 >= cap(b) { + // If labels entry is 1KB+, hash the rest of them via Write(). + h := xxhash.New() + _, _ = h.Write(b) + for pos < len(ls.data) { + name, pos = decodeString(ls.syms, ls.data, pos) + value, pos = decodeString(ls.syms, ls.data, pos) + _, _ = h.WriteString(name) + _, _ = h.Write(seps) + _, _ = h.WriteString(value) + _, _ = h.Write(seps) + } + return h.Sum64() + } + + b = append(b, name...) + b = append(b, seps[0]) + b = append(b, value...) + b = append(b, seps[0]) + pos = newPos + } + return xxhash.Sum64(b) +} + +// HashForLabels returns a hash value for the labels matching the provided names. +// 'names' have to be sorted in ascending order. +func (ls Labels) HashForLabels(b []byte, names ...string) (uint64, []byte) { + b = b[:0] + j := 0 + for i := 0; i < len(ls.data); { + var name, value string + name, i = decodeString(ls.syms, ls.data, i) + value, i = decodeString(ls.syms, ls.data, i) + for j < len(names) && names[j] < name { + j++ + } + if j == len(names) { + break + } + if name == names[j] { + b = append(b, name...) + b = append(b, seps[0]) + b = append(b, value...) + b = append(b, seps[0]) + } + } + + return xxhash.Sum64(b), b +} + +// HashWithoutLabels returns a hash value for all labels except those matching +// the provided names. +// 'names' have to be sorted in ascending order. +func (ls Labels) HashWithoutLabels(b []byte, names ...string) (uint64, []byte) { + b = b[:0] + j := 0 + for i := 0; i < len(ls.data); { + var name, value string + name, i = decodeString(ls.syms, ls.data, i) + value, i = decodeString(ls.syms, ls.data, i) + for j < len(names) && names[j] < name { + j++ + } + if name == MetricName || (j < len(names) && name == names[j]) { + continue + } + b = append(b, name...) + b = append(b, seps[0]) + b = append(b, value...) + b = append(b, seps[0]) + } + return xxhash.Sum64(b), b +} + +// BytesWithLabels is just as Bytes(), but only for labels matching names. +// 'names' have to be sorted in ascending order. +func (ls Labels) BytesWithLabels(buf []byte, names ...string) []byte { + b := bytes.NewBuffer(buf[:0]) + j := 0 + for pos := 0; pos < len(ls.data); { + lName, newPos := decodeString(ls.syms, ls.data, pos) + lValue, newPos := decodeString(ls.syms, ls.data, newPos) + for j < len(names) && names[j] < lName { + j++ + } + if j == len(names) { + break + } + if lName == names[j] { + if b.Len() > 1 { + b.WriteByte(seps[0]) + } + b.WriteString(lName) + b.WriteByte(seps[0]) + b.WriteString(lValue) + } + pos = newPos + } + return b.Bytes() +} + +// BytesWithoutLabels is just as Bytes(), but only for labels not matching names. +// 'names' have to be sorted in ascending order. +func (ls Labels) BytesWithoutLabels(buf []byte, names ...string) []byte { + b := bytes.NewBuffer(buf[:0]) + j := 0 + for pos := 0; pos < len(ls.data); { + lName, newPos := decodeString(ls.syms, ls.data, pos) + lValue, newPos := decodeString(ls.syms, ls.data, newPos) + for j < len(names) && names[j] < lName { + j++ + } + if j == len(names) || lName != names[j] { + if b.Len() > 1 { + b.WriteByte(seps[0]) + } + b.WriteString(lName) + b.WriteByte(seps[0]) + b.WriteString(lValue) + } + pos = newPos + } + return b.Bytes() +} + +// Copy returns a copy of the labels. +func (ls Labels) Copy() Labels { + buf := append([]byte{}, ls.data...) + return Labels{syms: ls.syms, data: yoloString(buf)} +} + +// Get returns the value for the label with the given name. +// Returns an empty string if the label doesn't exist. +func (ls Labels) Get(name string) string { + if name == "" { // Avoid crash in loop if someone asks for "". + return "" // Prometheus does not store blank label names. + } + for i := 0; i < len(ls.data); { + var lName, lValue string + lName, i = decodeString(ls.syms, ls.data, i) + if lName == name { + lValue, _ = decodeString(ls.syms, ls.data, i) + return lValue + } else if lName[0] > name[0] { // Stop looking if we've gone past. + break + } + _, i = decodeVarint(ls.data, i) + } + return "" +} + +// Has returns true if the label with the given name is present. +func (ls Labels) Has(name string) bool { + if name == "" { // Avoid crash in loop if someone asks for "". + return false // Prometheus does not store blank label names. + } + for i := 0; i < len(ls.data); { + var lName string + lName, i = decodeString(ls.syms, ls.data, i) + if lName == name { + return true + } else if lName[0] > name[0] { // Stop looking if we've gone past. + break + } + _, i = decodeVarint(ls.data, i) + } + return false +} + +// HasDuplicateLabelNames returns whether ls has duplicate label names. +// It assumes that the labelset is sorted. +func (ls Labels) HasDuplicateLabelNames() (string, bool) { + prevNum := -1 + for i := 0; i < len(ls.data); { + var lNum int + lNum, i = decodeVarint(ls.data, i) + _, i = decodeVarint(ls.data, i) + if lNum == prevNum { + return ls.syms.ToName(lNum), true + } + prevNum = lNum + } + return "", false +} + +// WithoutEmpty returns the labelset without empty labels. +// May return the same labelset. +func (ls Labels) WithoutEmpty() Labels { + if ls.IsEmpty() { + return ls + } + // Idea: have a constant symbol for blank, then we don't have to look it up. + blank, ok := ls.syms.symbolTable.checkNum("") + if !ok { // Symbol table has no entry for blank - none of the values can be blank. + return ls + } + for pos := 0; pos < len(ls.data); { + _, newPos := decodeVarint(ls.data, pos) + lValue, newPos := decodeVarint(ls.data, newPos) + if lValue != blank { + pos = newPos + continue + } + // Do not copy the slice until it's necessary. + // TODO: could optimise the case where all blanks are at the end. + // Note: we size the new buffer on the assumption there is exactly one blank value. + buf := make([]byte, pos, pos+(len(ls.data)-newPos)) + copy(buf, ls.data[:pos]) // copy the initial non-blank labels + pos = newPos // move past the first blank value + for pos < len(ls.data) { + var newPos int + _, newPos = decodeVarint(ls.data, pos) + lValue, newPos = decodeVarint(ls.data, newPos) + if lValue != blank { + buf = append(buf, ls.data[pos:newPos]...) + } + pos = newPos + } + return Labels{syms: ls.syms, data: yoloString(buf)} + } + return ls +} + +// Equal returns whether the two label sets are equal. +func Equal(a, b Labels) bool { + if a.syms == b.syms { + return a.data == b.data + } + + la, lb := len(a.data), len(b.data) + ia, ib := 0, 0 + for ia < la && ib < lb { + var aValue, bValue string + aValue, ia = decodeString(a.syms, a.data, ia) + bValue, ib = decodeString(b.syms, b.data, ib) + if aValue != bValue { + return false + } + } + if ia != la || ib != lb { + return false + } + return true +} + +// EmptyLabels returns an empty Labels value, for convenience. +func EmptyLabels() Labels { + return Labels{} +} + +func yoloString(b []byte) string { + return *((*string)(unsafe.Pointer(&b))) +} + +// New returns a sorted Labels from the given labels. +// The caller has to guarantee that all label names are unique. +// Note this function is not efficient; should not be used in performance-critical places. +func New(ls ...Label) Labels { + slices.SortFunc(ls, func(a, b Label) int { return strings.Compare(a.Name, b.Name) }) + syms := NewSymbolTable() + var stackSpace [16]int + size, nums := mapLabelsToNumbers(syms, ls, stackSpace[:]) + buf := make([]byte, size) + marshalNumbersToSizedBuffer(nums, buf) + return Labels{syms: syms.nameTable, data: yoloString(buf)} +} + +// FromStrings creates new labels from pairs of strings. +func FromStrings(ss ...string) Labels { + if len(ss)%2 != 0 { + panic("invalid number of strings") + } + ls := make([]Label, 0, len(ss)/2) + for i := 0; i < len(ss); i += 2 { + ls = append(ls, Label{Name: ss[i], Value: ss[i+1]}) + } + + return New(ls...) +} + +// Compare compares the two label sets. +// The result will be 0 if a==b, <0 if a < b, and >0 if a > b. +func Compare(a, b Labels) int { + la, lb := len(a.data), len(b.data) + ia, ib := 0, 0 + for ia < la && ib < lb { + var aName, bName string + aName, ia = decodeString(a.syms, a.data, ia) + bName, ib = decodeString(b.syms, b.data, ib) + if aName != bName { + if aName < bName { + return -1 + } + return 1 + } + var aValue, bValue string + aValue, ia = decodeString(a.syms, a.data, ia) + bValue, ib = decodeString(b.syms, b.data, ib) + if aValue != bValue { + if aValue < bValue { + return -1 + } + return 1 + } + } + // If all labels so far were in common, the set with fewer labels comes first. + return (la - ia) - (lb - ib) +} + +// Copy labels from b on top of whatever was in ls previously, reusing memory or expanding if needed. +func (ls *Labels) CopyFrom(b Labels) { + *ls = b // Straightforward memberwise copy is all we need. +} + +// IsEmpty returns true if ls represents an empty set of labels. +func (ls Labels) IsEmpty() bool { + return len(ls.data) == 0 +} + +// Len returns the number of labels; it is relatively slow. +func (ls Labels) Len() int { + count := 0 + for i := 0; i < len(ls.data); { + _, i = decodeVarint(ls.data, i) + _, i = decodeVarint(ls.data, i) + count++ + } + return count +} + +// Range calls f on each label. +func (ls Labels) Range(f func(l Label)) { + for i := 0; i < len(ls.data); { + var lName, lValue string + lName, i = decodeString(ls.syms, ls.data, i) + lValue, i = decodeString(ls.syms, ls.data, i) + f(Label{Name: lName, Value: lValue}) + } +} + +// Validate calls f on each label. If f returns a non-nil error, then it returns that error cancelling the iteration. +func (ls Labels) Validate(f func(l Label) error) error { + for i := 0; i < len(ls.data); { + var lName, lValue string + lName, i = decodeString(ls.syms, ls.data, i) + lValue, i = decodeString(ls.syms, ls.data, i) + err := f(Label{Name: lName, Value: lValue}) + if err != nil { + return err + } + } + return nil +} + +// InternStrings calls intern on every string value inside ls, replacing them with what it returns. +func (ls *Labels) InternStrings(intern func(string) string) { + // TODO: remove these calls as there is nothing to do. +} + +// ReleaseStrings calls release on every string value inside ls. +func (ls Labels) ReleaseStrings(release func(string)) { + // TODO: remove these calls as there is nothing to do. +} + +// DropMetricName returns Labels with "__name__" removed. +func (ls Labels) DropMetricName() Labels { + for i := 0; i < len(ls.data); { + lName, i2 := decodeString(ls.syms, ls.data, i) + _, i2 = decodeVarint(ls.data, i2) + if lName == MetricName { + if i == 0 { // Make common case fast with no allocations. + ls.data = ls.data[i2:] + } else { + ls.data = ls.data[:i] + ls.data[i2:] + } + break + } else if lName[0] > MetricName[0] { // Stop looking if we've gone past. + break + } + i = i2 + } + return ls +} + +// Builder allows modifying Labels. +type Builder struct { + syms *SymbolTable + nums []int + base Labels + del []string + add []Label +} + +// NewBuilderWithSymbolTable returns a new LabelsBuilder not based on any labels, but with the SymbolTable. +func NewBuilderWithSymbolTable(s *SymbolTable) *Builder { + return &Builder{ + syms: s, + } +} + +// Reset clears all current state for the builder. +func (b *Builder) Reset(base Labels) { + if base.syms != nil { // If base has a symbol table, use that. + b.syms = base.syms.symbolTable + } else if b.syms == nil { // Or continue using previous symbol table in builder. + b.syms = NewSymbolTable() // Don't do this in performance-sensitive code. + } + + b.base = base + b.del = b.del[:0] + b.add = b.add[:0] + base.Range(func(l Label) { + if l.Value == "" { + b.del = append(b.del, l.Name) + } + }) +} + +// Labels returns the labels from the builder. +// If no modifications were made, the original labels are returned. +func (b *Builder) Labels() Labels { + if len(b.del) == 0 && len(b.add) == 0 { + return b.base + } + + slices.SortFunc(b.add, func(a, b Label) int { return strings.Compare(a.Name, b.Name) }) + slices.Sort(b.del) + a, d, newSize := 0, 0, 0 + + newSize, b.nums = mapLabelsToNumbers(b.syms, b.add, b.nums) + bufSize := len(b.base.data) + newSize + buf := make([]byte, 0, bufSize) + for pos := 0; pos < len(b.base.data); { + oldPos := pos + var lName string + lName, pos = decodeString(b.base.syms, b.base.data, pos) + _, pos = decodeVarint(b.base.data, pos) + for d < len(b.del) && b.del[d] < lName { + d++ + } + if d < len(b.del) && b.del[d] == lName { + continue // This label has been deleted. + } + for ; a < len(b.add) && b.add[a].Name < lName; a++ { + buf = appendLabelTo(b.nums[a*2], b.nums[a*2+1], buf) // Insert label that was not in the base set. + } + if a < len(b.add) && b.add[a].Name == lName { + buf = appendLabelTo(b.nums[a*2], b.nums[a*2+1], buf) + a++ + continue // This label has been replaced. + } + buf = append(buf, b.base.data[oldPos:pos]...) // If base had a symbol-table we are using it, so we don't need to look up these symbols. + } + // We have come to the end of the base set; add any remaining labels. + for ; a < len(b.add); a++ { + buf = appendLabelTo(b.nums[a*2], b.nums[a*2+1], buf) + } + return Labels{syms: b.syms.nameTable, data: yoloString(buf)} +} + +func marshalNumbersToSizedBuffer(nums []int, data []byte) int { + i := len(data) + for index := len(nums) - 1; index >= 0; index-- { + i = encodeVarint(data, i, nums[index]) + } + return len(data) - i +} + +func sizeVarint(x uint64) (n int) { + // Most common case first + if x < 1<<7 { + return 1 + } + if x >= 1<<56 { + return 9 + } + if x >= 1<<28 { + x >>= 28 + n = 4 + } + if x >= 1<<14 { + x >>= 14 + n += 2 + } + if x >= 1<<7 { + n++ + } + return n + 1 +} + +func encodeVarintSlow(data []byte, offset int, v uint64) int { + offset -= sizeVarint(v) + base := offset + for v >= 1<<7 { + data[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + data[offset] = uint8(v) + return base +} + +// Special code for the common case that a value is less than 128 +func encodeVarint(data []byte, offset, v int) int { + if v < 1<<7 { + offset-- + data[offset] = uint8(v) + return offset + } + return encodeVarintSlow(data, offset, uint64(v)) +} + +// Map all the strings in lbls to the symbol table; return the total size required to hold them and all the individual mappings. +func mapLabelsToNumbers(t *SymbolTable, lbls []Label, buf []int) (totalSize int, nums []int) { + nums = buf[:0] + t.mx.Lock() + defer t.mx.Unlock() + // we just encode name/value/name/value, without any extra tags or length bytes + for _, m := range lbls { + // strings are encoded as a single varint, the index into the symbol table. + i := t.toNumUnlocked(m.Name) + nums = append(nums, i) + totalSize += sizeVarint(uint64(i)) + i = t.toNumUnlocked(m.Value) + nums = append(nums, i) + totalSize += sizeVarint(uint64(i)) + } + return totalSize, nums +} + +func appendLabelTo(nameNum, valueNum int, buf []byte) []byte { + size := sizeVarint(uint64(nameNum)) + sizeVarint(uint64(valueNum)) + sizeRequired := len(buf) + size + if cap(buf) >= sizeRequired { + buf = buf[:sizeRequired] + } else { + bufSize := cap(buf) + // Double size of buffer each time it needs to grow, to amortise copying cost. + for bufSize < sizeRequired { + bufSize = bufSize*2 + 1 + } + newBuf := make([]byte, sizeRequired, bufSize) + copy(newBuf, buf) + buf = newBuf + } + i := sizeRequired + i = encodeVarint(buf, i, valueNum) + i = encodeVarint(buf, i, nameNum) + return buf +} + +// ScratchBuilder allows efficient construction of a Labels from scratch. +type ScratchBuilder struct { + syms *SymbolTable + nums []int + add []Label + output Labels + overwriteBuffer []byte +} + +// NewScratchBuilder creates a ScratchBuilder initialized for Labels with n entries. +// Warning: expensive; don't call in tight loops. +func NewScratchBuilder(n int) ScratchBuilder { + return ScratchBuilder{syms: NewSymbolTable(), add: make([]Label, 0, n)} +} + +// NewScratchBuilderWithSymbolTable creates a ScratchBuilder initialized for Labels with n entries. +func NewScratchBuilderWithSymbolTable(s *SymbolTable, n int) ScratchBuilder { + return ScratchBuilder{syms: s, add: make([]Label, 0, n)} +} + +func (b *ScratchBuilder) SetSymbolTable(s *SymbolTable) { + b.syms = s +} + +func (b *ScratchBuilder) Reset() { + b.add = b.add[:0] + b.output = EmptyLabels() +} + +// Add a name/value pair. +// Note if you Add the same name twice you will get a duplicate label, which is invalid. +func (b *ScratchBuilder) Add(name, value string) { + b.add = append(b.add, Label{Name: name, Value: value}) +} + +// Add a name/value pair, using []byte instead of string to reduce memory allocations. +// The values must remain live until Labels() is called. +func (b *ScratchBuilder) UnsafeAddBytes(name, value []byte) { + b.add = append(b.add, Label{Name: yoloString(name), Value: yoloString(value)}) +} + +// Sort the labels added so far by name. +func (b *ScratchBuilder) Sort() { + slices.SortFunc(b.add, func(a, b Label) int { return strings.Compare(a.Name, b.Name) }) +} + +// Assign is for when you already have a Labels which you want this ScratchBuilder to return. +func (b *ScratchBuilder) Assign(l Labels) { + b.output = l +} + +// Labels returns the name/value pairs added as a Labels object. Calling Add() after Labels() has no effect. +// Note: if you want them sorted, call Sort() first. +func (b *ScratchBuilder) Labels() Labels { + if b.output.IsEmpty() { + var size int + size, b.nums = mapLabelsToNumbers(b.syms, b.add, b.nums) + buf := make([]byte, size) + marshalNumbersToSizedBuffer(b.nums, buf) + b.output = Labels{syms: b.syms.nameTable, data: yoloString(buf)} + } + return b.output +} + +// Write the newly-built Labels out to ls, reusing an internal buffer. +// Callers must ensure that there are no other references to ls, or any strings fetched from it. +func (b *ScratchBuilder) Overwrite(ls *Labels) { + var size int + size, b.nums = mapLabelsToNumbers(b.syms, b.add, b.nums) + if size <= cap(b.overwriteBuffer) { + b.overwriteBuffer = b.overwriteBuffer[:size] + } else { + b.overwriteBuffer = make([]byte, size) + } + marshalNumbersToSizedBuffer(b.nums, b.overwriteBuffer) + ls.syms = b.syms.nameTable + ls.data = yoloString(b.overwriteBuffer) +} diff --git a/model/labels/sharding_dedupelabels.go b/model/labels/sharding_dedupelabels.go new file mode 100644 index 0000000000..a4ff285123 --- /dev/null +++ b/model/labels/sharding_dedupelabels.go @@ -0,0 +1,52 @@ +// Copyright 2020 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build dedupelabels + +package labels + +import ( + "github.com/cespare/xxhash/v2" +) + +// StableHash is a labels hashing implementation which is guaranteed to not change over time. +// This function should be used whenever labels hashing backward compatibility must be guaranteed. +func StableHash(ls Labels) uint64 { + // Use xxhash.Sum64(b) for fast path as it's faster. + b := make([]byte, 0, 1024) + for pos := 0; pos < len(ls.data); { + name, newPos := decodeString(ls.syms, ls.data, pos) + value, newPos := decodeString(ls.syms, ls.data, newPos) + if len(b)+len(name)+len(value)+2 >= cap(b) { + // If labels entry is 1KB+, hash the rest of them via Write(). + h := xxhash.New() + _, _ = h.Write(b) + for pos < len(ls.data) { + name, pos = decodeString(ls.syms, ls.data, pos) + value, pos = decodeString(ls.syms, ls.data, pos) + _, _ = h.WriteString(name) + _, _ = h.Write(seps) + _, _ = h.WriteString(value) + _, _ = h.Write(seps) + } + return h.Sum64() + } + + b = append(b, name...) + b = append(b, seps[0]) + b = append(b, value...) + b = append(b, seps[0]) + pos = newPos + } + return xxhash.Sum64(b) +} From b39286fd1fb3ba7ab75f17762524bcbbaf63eb0e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 23 Nov 2023 19:14:24 +0000 Subject: [PATCH 038/253] Add dedupelabels tag to not build regular labels Signed-off-by: Bryan Boreham --- model/labels/labels.go | 2 +- model/labels/sharding.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/model/labels/labels.go b/model/labels/labels.go index f145dfc5f8..a482d2a835 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !stringlabels +//go:build !stringlabels && !dedupelabels package labels diff --git a/model/labels/sharding.go b/model/labels/sharding.go index 6b4119860a..5e3e89fbbb 100644 --- a/model/labels/sharding.go +++ b/model/labels/sharding.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !stringlabels +//go:build !stringlabels && !dedupelabels package labels From 8f525b4ba4eb14f22a54cec4cf9b855d5c8efe4a Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 27 Mar 2023 16:32:25 +0100 Subject: [PATCH 039/253] storage/remote tests: refactor: extract function newTestQueueManager To reduce repetition. Signed-off-by: Bryan Boreham --- storage/remote/queue_manager_test.go | 114 ++++++++------------------- 1 file changed, 34 insertions(+), 80 deletions(-) diff --git a/storage/remote/queue_manager_test.go b/storage/remote/queue_manager_test.go index c953266b7f..daa89a930c 100644 --- a/storage/remote/queue_manager_test.go +++ b/storage/remote/queue_manager_test.go @@ -163,16 +163,23 @@ func TestSampleDelivery(t *testing.T) { } } -func TestMetadataDelivery(t *testing.T) { +func newTestClientAndQueueManager(t testing.TB, flushDeadline time.Duration) (*TestWriteClient, *QueueManager) { c := NewTestWriteClient() - - dir := t.TempDir() - cfg := config.DefaultQueueConfig mcfg := config.DefaultMetadataConfig + return c, newTestQueueManager(t, cfg, mcfg, flushDeadline, c) +} +func newTestQueueManager(t testing.TB, cfg config.QueueConfig, mcfg config.MetadataConfig, deadline time.Duration, c WriteClient) *QueueManager { + dir := t.TempDir() metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, deadline, newPool(), newHighestTimestampMetric(), nil, false, false) + + return m +} + +func TestMetadataDelivery(t *testing.T) { + c, m := newTestClientAndQueueManager(t, defaultFlushDeadline) m.Start() defer m.Stop() @@ -192,7 +199,7 @@ func TestMetadataDelivery(t *testing.T) { require.Len(t, c.receivedMetadata, numMetadata) // One more write than the rounded qoutient should be performed in order to get samples that didn't // fit into MaxSamplesPerSend. - require.Equal(t, numMetadata/mcfg.MaxSamplesPerSend+1, c.writesReceived) + require.Equal(t, numMetadata/config.DefaultMetadataConfig.MaxSamplesPerSend+1, c.writesReceived) // Make sure the last samples were sent. require.Equal(t, c.receivedMetadata[metadata[len(metadata)-1].Metric][0].MetricFamilyName, metadata[len(metadata)-1].Metric) } @@ -201,17 +208,13 @@ func TestSampleDeliveryTimeout(t *testing.T) { // Let's send one less sample than batch size, and wait the timeout duration n := 9 samples, series := createTimeseries(n, n) - c := NewTestWriteClient() cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig cfg.MaxShards = 1 cfg.BatchSendDeadline = model.Duration(100 * time.Millisecond) - dir := t.TempDir() - - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + c := NewTestWriteClient() + m := newTestQueueManager(t, cfg, config.DefaultMetadataConfig, defaultFlushDeadline, c) m.StoreSeries(series, 0) m.Start() defer m.Stop() @@ -244,16 +247,8 @@ func TestSampleDeliveryOrder(t *testing.T) { }) } - c := NewTestWriteClient() + c, m := newTestClientAndQueueManager(t, defaultFlushDeadline) c.expectSamples(samples, series) - - dir := t.TempDir() - - cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig - - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) m.StoreSeries(series, 0) m.Start() @@ -267,13 +262,10 @@ func TestShutdown(t *testing.T) { deadline := 1 * time.Second c := NewTestBlockedWriteClient() - dir := t.TempDir() - cfg := config.DefaultQueueConfig mcfg := config.DefaultMetadataConfig - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, deadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := newTestQueueManager(t, cfg, mcfg, deadline, c) n := 2 * config.DefaultQueueConfig.MaxSamplesPerSend samples, series := createTimeseries(n, n) m.StoreSeries(series, 0) @@ -306,12 +298,10 @@ func TestSeriesReset(t *testing.T) { numSegments := 4 numSeries := 25 - dir := t.TempDir() - cfg := config.DefaultQueueConfig mcfg := config.DefaultMetadataConfig - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, deadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := newTestQueueManager(t, cfg, mcfg, deadline, c) + for i := 0; i < numSegments; i++ { series := []record.RefSeries{} for j := 0; j < numSeries; j++ { @@ -330,17 +320,12 @@ func TestReshard(t *testing.T) { nSamples := config.DefaultQueueConfig.Capacity * size samples, series := createTimeseries(nSamples, nSeries) - c := NewTestWriteClient() - c.expectSamples(samples, series) - cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig cfg.MaxShards = 1 - dir := t.TempDir() - - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + c := NewTestWriteClient() + m := newTestQueueManager(t, cfg, config.DefaultMetadataConfig, defaultFlushDeadline, c) + c.expectSamples(samples, series) m.StoreSeries(series, 0) m.Start() @@ -363,7 +348,7 @@ func TestReshard(t *testing.T) { c.waitForExpectedData(t) } -func TestReshardRaceWithStop(*testing.T) { +func TestReshardRaceWithStop(t *testing.T) { c := NewTestWriteClient() var m *QueueManager h := sync.Mutex{} @@ -375,8 +360,7 @@ func TestReshardRaceWithStop(*testing.T) { exitCh := make(chan struct{}) go func() { for { - metrics := newQueueManagerMetrics(nil, "", "") - m = NewQueueManager(metrics, nil, nil, nil, "", newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m = newTestQueueManager(t, cfg, mcfg, defaultFlushDeadline, c) m.Start() h.Unlock() h.Lock() @@ -410,8 +394,7 @@ func TestReshardPartialBatch(t *testing.T) { flushDeadline := 10 * time.Millisecond cfg.BatchSendDeadline = model.Duration(batchSendDeadline) - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, t.TempDir(), newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, flushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := newTestQueueManager(t, cfg, mcfg, flushDeadline, c) m.StoreSeries(series, 0) m.Start() @@ -454,9 +437,7 @@ func TestQueueFilledDeadlock(t *testing.T) { batchSendDeadline := time.Millisecond cfg.BatchSendDeadline = model.Duration(batchSendDeadline) - metrics := newQueueManagerMetrics(nil, "", "") - - m := NewQueueManager(metrics, nil, nil, nil, t.TempDir(), newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, flushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := newTestQueueManager(t, cfg, mcfg, flushDeadline, c) m.StoreSeries(series, 0) m.Start() defer m.Stop() @@ -479,11 +460,7 @@ func TestQueueFilledDeadlock(t *testing.T) { } func TestReleaseNoninternedString(t *testing.T) { - cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig - metrics := newQueueManagerMetrics(nil, "", "") - c := NewTestWriteClient() - m := NewQueueManager(metrics, nil, nil, nil, "", newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + _, m := newTestClientAndQueueManager(t, defaultFlushDeadline) m.Start() defer m.Stop() @@ -525,12 +502,8 @@ func TestShouldReshard(t *testing.T) { }, } - cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig for _, c := range cases { - metrics := newQueueManagerMetrics(nil, "", "") - client := NewTestWriteClient() - m := NewQueueManager(metrics, nil, nil, nil, "", newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, client, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + _, m := newTestClientAndQueueManager(t, defaultFlushDeadline) m.numShards = c.startingShards m.dataIn.incr(c.samplesIn) m.dataOut.incr(c.samplesOut) @@ -904,10 +877,7 @@ func BenchmarkSampleSend(b *testing.B) { cfg.MinShards = 20 cfg.MaxShards = 20 - dir := b.TempDir() - - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := newTestQueueManager(b, cfg, mcfg, defaultFlushDeadline, c) m.StoreSeries(series, 0) // These should be received by the client. @@ -1083,15 +1053,9 @@ func TestProcessExternalLabels(t *testing.T) { } func TestCalculateDesiredShards(t *testing.T) { - c := NewTestWriteClient() cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig - - dir := t.TempDir() - - metrics := newQueueManagerMetrics(nil, "", "") - samplesIn := newEWMARate(ewmaWeight, shardUpdateDuration) - m := NewQueueManager(metrics, nil, nil, nil, dir, samplesIn, cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + _, m := newTestClientAndQueueManager(t, defaultFlushDeadline) + samplesIn := m.dataIn // Need to start the queue manager so the proper metrics are initialized. // However we can stop it right away since we don't need to do any actual @@ -1160,15 +1124,8 @@ func TestCalculateDesiredShards(t *testing.T) { } func TestCalculateDesiredShardsDetail(t *testing.T) { - c := NewTestWriteClient() - cfg := config.DefaultQueueConfig - mcfg := config.DefaultMetadataConfig - - dir := t.TempDir() - - metrics := newQueueManagerMetrics(nil, "", "") - samplesIn := newEWMARate(ewmaWeight, shardUpdateDuration) - m := NewQueueManager(metrics, nil, nil, nil, dir, samplesIn, cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + _, m := newTestClientAndQueueManager(t, defaultFlushDeadline) + samplesIn := m.dataIn for _, tc := range []struct { name string @@ -1393,10 +1350,7 @@ func TestDropOldTimeSeries(t *testing.T) { mcfg := config.DefaultMetadataConfig cfg.MaxShards = 1 cfg.SampleAgeLimit = model.Duration(60 * time.Second) - dir := t.TempDir() - - metrics := newQueueManagerMetrics(nil, "", "") - m := NewQueueManager(metrics, nil, nil, nil, dir, newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, c, defaultFlushDeadline, newPool(), newHighestTimestampMetric(), nil, false, false) + m := newTestQueueManager(t, cfg, mcfg, defaultFlushDeadline, c) m.StoreSeries(series, 0) m.Start() From 2ac1632eec2eec22bc0390d22d22982e50902140 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 27 Mar 2023 16:27:35 +0100 Subject: [PATCH 040/253] storage/remote: improve symbol-table handling On the incoming path, `writeHandler.write()` creates a new table for each request. `labelProtosToLabels` takes a `ScratchBuilder` now. Call `NewScratchBuilder` as required in tests. Signed-off-by: Bryan Boreham --- storage/remote/codec.go | 11 ++++++----- storage/remote/codec_test.go | 5 +++-- storage/remote/queue_manager_test.go | 7 ++++--- storage/remote/read_test.go | 4 +++- storage/remote/write_handler.go | 6 ++++-- storage/remote/write_handler_test.go | 5 +++-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/storage/remote/codec.go b/storage/remote/codec.go index 9cf1ed8712..d0d2dd1d9e 100644 --- a/storage/remote/codec.go +++ b/storage/remote/codec.go @@ -176,12 +176,13 @@ func ToQueryResult(ss storage.SeriesSet, sampleLimit int) (*prompb.QueryResult, // FromQueryResult unpacks and sorts a QueryResult proto. func FromQueryResult(sortSeries bool, res *prompb.QueryResult) storage.SeriesSet { + b := labels.NewScratchBuilder(0) series := make([]storage.Series, 0, len(res.Timeseries)) for _, ts := range res.Timeseries { if err := validateLabelsAndMetricName(ts.Labels); err != nil { return errSeriesSet{err: err} } - lbls := labelProtosToLabels(ts.Labels) + lbls := labelProtosToLabels(&b, ts.Labels) series = append(series, &concreteSeries{labels: lbls, floats: ts.Samples, histograms: ts.Histograms}) } @@ -616,11 +617,11 @@ func FromLabelMatchers(matchers []*prompb.LabelMatcher) ([]*labels.Matcher, erro return result, nil } -func exemplarProtoToExemplar(ep prompb.Exemplar) exemplar.Exemplar { +func exemplarProtoToExemplar(b *labels.ScratchBuilder, ep prompb.Exemplar) exemplar.Exemplar { timestamp := ep.Timestamp return exemplar.Exemplar{ - Labels: labelProtosToLabels(ep.Labels), + Labels: labelProtosToLabels(b, ep.Labels), Value: ep.Value, Ts: timestamp, HasTs: timestamp != 0, @@ -760,8 +761,8 @@ func LabelProtosToMetric(labelPairs []*prompb.Label) model.Metric { return metric } -func labelProtosToLabels(labelPairs []prompb.Label) labels.Labels { - b := labels.ScratchBuilder{} +func labelProtosToLabels(b *labels.ScratchBuilder, labelPairs []prompb.Label) labels.Labels { + b.Reset() for _, l := range labelPairs { b.Add(l.Name, l.Value) } diff --git a/storage/remote/codec_test.go b/storage/remote/codec_test.go index 0451953cb1..41d4b3656c 100644 --- a/storage/remote/codec_test.go +++ b/storage/remote/codec_test.go @@ -788,10 +788,11 @@ func (m *mockWriter) Write(p []byte) (n int, err error) { type mockChunkSeriesSet struct { chunkedSeries []*prompb.ChunkedSeries index int + builder labels.ScratchBuilder } func newMockChunkSeriesSet(ss []*prompb.ChunkedSeries) storage.ChunkSeriesSet { - return &mockChunkSeriesSet{chunkedSeries: ss, index: -1} + return &mockChunkSeriesSet{chunkedSeries: ss, index: -1, builder: labels.NewScratchBuilder(0)} } func (c *mockChunkSeriesSet) Next() bool { @@ -801,7 +802,7 @@ func (c *mockChunkSeriesSet) Next() bool { func (c *mockChunkSeriesSet) At() storage.ChunkSeries { return &storage.ChunkSeriesEntry{ - Lset: labelProtosToLabels(c.chunkedSeries[c.index].Labels), + Lset: labelProtosToLabels(&c.builder, c.chunkedSeries[c.index].Labels), ChunkIteratorFn: func(chunks.Iterator) chunks.Iterator { return &mockChunkIterator{ chunks: c.chunkedSeries[c.index].Chunks, diff --git a/storage/remote/queue_manager_test.go b/storage/remote/queue_manager_test.go index daa89a930c..e9de8beba4 100644 --- a/storage/remote/queue_manager_test.go +++ b/storage/remote/queue_manager_test.go @@ -523,7 +523,7 @@ func TestShouldReshard(t *testing.T) { func createTimeseries(numSamples, numSeries int, extraLabels ...labels.Label) ([]record.RefSample, []record.RefSeries) { samples := make([]record.RefSample, 0, numSamples) series := make([]record.RefSeries, 0, numSeries) - lb := labels.ScratchBuilder{} + lb := labels.NewScratchBuilder(1 + len(extraLabels)) for i := 0; i < numSeries; i++ { name := fmt.Sprintf("test_metric_%d", i) for j := 0; j < numSamples; j++ { @@ -760,9 +760,10 @@ func (c *TestWriteClient) Store(_ context.Context, req []byte, _ int) error { if err := proto.Unmarshal(reqBuf, &reqProto); err != nil { return err } + builder := labels.NewScratchBuilder(0) count := 0 for _, ts := range reqProto.Timeseries { - labels := labelProtosToLabels(ts.Labels) + labels := labelProtosToLabels(&builder, ts.Labels) seriesName := labels.Get("__name__") for _, sample := range ts.Samples { count++ @@ -1370,7 +1371,7 @@ func createTimeseriesWithOldSamples(numSamples, numSeries int, extraLabels ...la newSamples := make([]record.RefSample, 0, numSamples) samples := make([]record.RefSample, 0, numSamples) series := make([]record.RefSeries, 0, numSeries) - lb := labels.ScratchBuilder{} + lb := labels.NewScratchBuilder(1 + len(extraLabels)) for i := 0; i < numSeries; i++ { name := fmt.Sprintf("test_metric_%d", i) // We create half of the samples in the past. diff --git a/storage/remote/read_test.go b/storage/remote/read_test.go index 1bec9dfb65..87408dfb4f 100644 --- a/storage/remote/read_test.go +++ b/storage/remote/read_test.go @@ -195,6 +195,7 @@ func TestSeriesSetFilter(t *testing.T) { type mockedRemoteClient struct { got *prompb.Query store []*prompb.TimeSeries + b labels.ScratchBuilder } func (c *mockedRemoteClient) Read(_ context.Context, query *prompb.Query) (*prompb.QueryResult, error) { @@ -210,7 +211,7 @@ func (c *mockedRemoteClient) Read(_ context.Context, query *prompb.Query) (*prom q := &prompb.QueryResult{} for _, s := range c.store { - l := labelProtosToLabels(s.Labels) + l := labelProtosToLabels(&c.b, s.Labels) var notMatch bool for _, m := range matchers { @@ -242,6 +243,7 @@ func TestSampleAndChunkQueryableClient(t *testing.T) { {Labels: []prompb.Label{{Name: "a", Value: "b3"}, {Name: "region", Value: "us"}}}, {Labels: []prompb.Label{{Name: "a", Value: "b2"}, {Name: "region", Value: "europe"}}}, }, + b: labels.NewScratchBuilder(0), } for _, tc := range []struct { diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index 783cbde825..d0d96b09d5 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -25,6 +25,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/prometheus/model/exemplar" + "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/prompb" "github.com/prometheus/prometheus/storage" otlptranslator "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheusremotewrite" @@ -112,9 +113,10 @@ func (h *writeHandler) write(ctx context.Context, req *prompb.WriteRequest) (err err = app.Commit() }() + b := labels.NewScratchBuilder(0) var exemplarErr error for _, ts := range req.Timeseries { - labels := labelProtosToLabels(ts.Labels) + labels := labelProtosToLabels(&b, ts.Labels) if !labels.IsValid() { level.Warn(h.logger).Log("msg", "Invalid metric names or labels", "got", labels.String()) samplesWithInvalidLabels++ @@ -137,7 +139,7 @@ func (h *writeHandler) write(ctx context.Context, req *prompb.WriteRequest) (err } for _, ep := range ts.Exemplars { - e := exemplarProtoToExemplar(ep) + e := exemplarProtoToExemplar(&b, ep) _, exemplarErr = app.AppendExemplar(0, labels, e) exemplarErr = h.checkAppendExemplarError(exemplarErr, e, &outOfOrderExemplarErrs) diff --git a/storage/remote/write_handler_test.go b/storage/remote/write_handler_test.go index 73e5cb17d6..5125290f7c 100644 --- a/storage/remote/write_handler_test.go +++ b/storage/remote/write_handler_test.go @@ -55,18 +55,19 @@ func TestRemoteWriteHandler(t *testing.T) { resp := recorder.Result() require.Equal(t, http.StatusNoContent, resp.StatusCode) + b := labels.NewScratchBuilder(0) i := 0 j := 0 k := 0 for _, ts := range writeRequestFixture.Timeseries { - labels := labelProtosToLabels(ts.Labels) + labels := labelProtosToLabels(&b, ts.Labels) for _, s := range ts.Samples { requireEqual(t, mockSample{labels, s.Timestamp, s.Value}, appendable.samples[i]) i++ } for _, e := range ts.Exemplars { - exemplarLabels := labelProtosToLabels(e.Labels) + exemplarLabels := labelProtosToLabels(&b, e.Labels) requireEqual(t, mockExemplar{labels, exemplarLabels, e.Timestamp, e.Value}, appendable.exemplars[j]) j++ } From e171f6c8aa50da4dea2b6a27a5c126a304613fe8 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Sat, 24 Feb 2024 00:33:35 +0900 Subject: [PATCH 041/253] go: fix go.mod version from 1.21.7 to 1.21 Signed-off-by: junya koyama --- documentation/examples/remote_storage/go.mod | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index e5c1c4e4cb..e7b5bb8be5 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.21.7 +go 1.21 require ( github.com/alecthomas/kingpin/v2 v2.4.0 diff --git a/go.mod b/go.mod index 7ec59e99ed..80a26ec38e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/prometheus -go 1.21.7 +go 1.21 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 From 22890b1eb3eafb64a8fc37aa39e05aad1c10a676 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 25 Feb 2024 19:26:52 +0000 Subject: [PATCH 042/253] PromQL: improve warning for mixed values in aggregations Aggregations discard the metric name, so don't try to include it in the error message. Add a test that generates this warning. Signed-off-by: Bryan Boreham --- promql/engine.go | 6 ++---- promql/engine_test.go | 16 ++++++++++++++++ util/annotations/annotations.go | 13 +++++++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 575ca58eae..cd955ff5eb 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2869,8 +2869,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par case parser.AVG: if aggr.hasFloat && aggr.hasHistogram { // We cannot aggregate histogram sample with a float64 sample. - metricName := aggr.labels.Get(labels.MetricName) - annos.Add(annotations.NewMixedFloatsHistogramsWarning(metricName, e.Expr.PositionRange())) + annos.Add(annotations.NewMixedFloatsHistogramsAggWarning(e.Expr.PositionRange())) continue } if aggr.hasHistogram { @@ -2923,8 +2922,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par case parser.SUM: if aggr.hasFloat && aggr.hasHistogram { // We cannot aggregate histogram sample with a float64 sample. - metricName := aggr.labels.Get(labels.MetricName) - annos.Add(annotations.NewMixedFloatsHistogramsWarning(metricName, e.Expr.PositionRange())) + annos.Add(annotations.NewMixedFloatsHistogramsAggWarning(e.Expr.PositionRange())) continue } if aggr.hasHistogram { diff --git a/promql/engine_test.go b/promql/engine_test.go index 5dc385942c..105108d5b2 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -4315,6 +4315,8 @@ func TestNativeHistogram_Sum_Count_Add_AvgOperator(t *testing.T) { ts := idx0 * int64(10*time.Minute/time.Millisecond) app := storage.Appender(context.Background()) + _, err := app.Append(0, labels.FromStrings("__name__", "float_series", "idx", "0"), ts, 42) + require.NoError(t, err) for idx1, h := range c.histograms { lbls := labels.FromStrings("__name__", seriesName, "idx", fmt.Sprintf("%d", idx1)) // Since we mutate h later, we need to create a copy here. @@ -4344,17 +4346,31 @@ func TestNativeHistogram_Sum_Count_Add_AvgOperator(t *testing.T) { res := qry.Exec(context.Background()) require.NoError(t, res.Err) + require.Empty(t, res.Warnings) vector, err := res.Vector() require.NoError(t, err) testutil.RequireEqual(t, exp, vector) } + queryAndCheckAnnotations := func(queryString string, ts int64, expWarnings annotations.Annotations) { + qry, err := engine.NewInstantQuery(context.Background(), storage, nil, queryString, timestamp.Time(ts)) + require.NoError(t, err) + + res := qry.Exec(context.Background()) + require.NoError(t, res.Err) + require.Equal(t, expWarnings, res.Warnings) + } // sum(). queryString := fmt.Sprintf("sum(%s)", seriesName) queryAndCheck(queryString, ts, []Sample{{T: ts, H: &c.expected, Metric: labels.EmptyLabels()}}) + queryString = `sum({idx="0"})` + var annos annotations.Annotations + annos.Add(annotations.NewMixedFloatsHistogramsAggWarning(posrange.PositionRange{Start: 4, End: 13})) + queryAndCheckAnnotations(queryString, ts, annos) + // + operator. queryString = fmt.Sprintf(`%s{idx="0"}`, seriesName) for idx := 1; idx < len(c.histograms); idx++ { diff --git a/util/annotations/annotations.go b/util/annotations/annotations.go index 29dafeb2e9..c7340e4c12 100644 --- a/util/annotations/annotations.go +++ b/util/annotations/annotations.go @@ -105,7 +105,7 @@ var ( InvalidQuantileWarning = fmt.Errorf("%w: quantile value should be between 0 and 1", PromQLWarning) BadBucketLabelWarning = fmt.Errorf("%w: bucket label %q is missing or has a malformed value", PromQLWarning, model.BucketLabel) - MixedFloatsHistogramsWarning = fmt.Errorf("%w: encountered a mix of histograms and floats for metric name", PromQLWarning) + MixedFloatsHistogramsWarning = fmt.Errorf("%w: encountered a mix of histograms and floats for ", PromQLWarning) MixedClassicNativeHistogramsWarning = fmt.Errorf("%w: vector contains a mix of classic and native histograms for metric name", PromQLWarning) NativeHistogramNotCounterWarning = fmt.Errorf("%w: this native histogram metric is not a counter:", PromQLWarning) NativeHistogramNotGaugeWarning = fmt.Errorf("%w: this native histogram metric is not a gauge:", PromQLWarning) @@ -155,7 +155,16 @@ func NewBadBucketLabelWarning(metricName, label string, pos posrange.PositionRan func NewMixedFloatsHistogramsWarning(metricName string, pos posrange.PositionRange) error { return annoErr{ PositionRange: pos, - Err: fmt.Errorf("%w %q", MixedFloatsHistogramsWarning, metricName), + Err: fmt.Errorf("%w metric name %q", MixedFloatsHistogramsWarning, metricName), + } +} + +// NewMixedFloatsHistogramsAggWarning is used when the queried series includes both +// float samples and histogram samples in an aggregation. +func NewMixedFloatsHistogramsAggWarning(pos posrange.PositionRange) error { + return annoErr{ + PositionRange: pos, + Err: fmt.Errorf("%w aggregation", MixedFloatsHistogramsWarning), } } From 2507469291d2aa370b1152dd1162bf7ff044e82d Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Mon, 26 Feb 2024 10:53:39 +0100 Subject: [PATCH 043/253] Fix: metadata API using wrong field names (#13633) Fix is to add json tags to `Metadata` struct. Absence of these tags causes Go to use the field name, which starts with an upper-case letter and breaks the protocol. Extend tests to verify the JSON response. Signed-off-by: ismail simsek --- model/metadata/metadata.go | 6 +++--- web/api/v1/api_test.go | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/model/metadata/metadata.go b/model/metadata/metadata.go index f6f2827a46..1b7e63e0f3 100644 --- a/model/metadata/metadata.go +++ b/model/metadata/metadata.go @@ -17,7 +17,7 @@ import "github.com/prometheus/common/model" // Metadata stores a series' metadata information. type Metadata struct { - Type model.MetricType - Unit string - Help string + Type model.MetricType `json:"type"` + Unit string `json:"unit"` + Help string `json:"help"` } diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 8c0a9c73bf..d3013b2eef 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -1056,6 +1056,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E response interface{} responseLen int responseMetadataTotal int + responseAsJSON string errType errorType sorter func(interface{}) metadata []targetMetadata @@ -1714,6 +1715,9 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E "prometheus_engine_query_duration_seconds": {{Type: model.MetricTypeSummary, Help: "Query timings", Unit: ""}}, "go_info": {{Type: model.MetricTypeGauge, Help: "Information about the Go environment.", Unit: ""}}, }, + responseAsJSON: `{"prometheus_engine_query_duration_seconds":[{"type":"summary","unit":"", +"help":"Query timings"}], "go_info":[{"type":"gauge","unit":"", +"help":"Information about the Go environment."}]}`, }, // With duplicate metadata for a metric that comes from different targets. { @@ -1745,6 +1749,8 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E response: map[string][]metadata.Metadata{ "go_threads": {{Type: model.MetricTypeGauge, Help: "Number of OS threads created"}}, }, + responseAsJSON: `{"go_threads": [{"type":"gauge","unit":"", +"help":"Number of OS threads created"}]}`, }, // With non-duplicate metadata for the same metric from different targets. { @@ -1779,6 +1785,9 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E {Type: model.MetricTypeGauge, Help: "Number of OS threads that were created."}, }, }, + responseAsJSON: `{"go_threads": [{"type":"gauge","unit":"", +"help":"Number of OS threads created"},{"type":"gauge","unit":"", +"help":"Number of OS threads that were created."}]}`, sorter: func(m interface{}) { v := m.(map[string][]metadata.Metadata)["go_threads"] @@ -1806,7 +1815,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E { Metric: "prometheus_engine_query_duration_seconds", Type: model.MetricTypeSummary, - Help: "Query Timmings.", + Help: "Query Timings.", Unit: "", }, }, @@ -1862,6 +1871,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E {Type: model.MetricTypeSummary, Help: "A summary of the GC invocation durations."}, }, }, + responseAsJSON: `{"go_gc_duration_seconds":[{"help":"A summary of the GC invocation durations.","type":"summary","unit":""}],"go_threads": [{"type":"gauge","unit":"","help":"Number of OS threads created"}]}`, }, // With a limit for the number of metadata per metric and per metric. { @@ -1985,6 +1995,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E {Type: model.MetricTypeGauge, Help: "Number of OS threads that were created."}, }, }, + responseAsJSON: `{"go_threads": [{"type":"gauge","unit":"","help":"Number of OS threads created"},{"type":"gauge","unit":"","help":"Number of OS threads that were created."}]}`, sorter: func(m interface{}) { v := m.(map[string][]metadata.Metadata)["go_threads"] @@ -2854,6 +2865,12 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E } assertAPIResponse(t, res.data, test.response) } + + if test.responseAsJSON != "" { + s, err := json.Marshal(res.data) + require.NoError(t, err) + require.JSONEq(t, test.responseAsJSON, string(s)) + } }) } }) From eecaa71ff1c7ea3ede1b92949e93dec29a3693fc Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Mon, 26 Feb 2024 10:53:39 +0100 Subject: [PATCH 044/253] Fix: metadata API using wrong field names (#13633) Fix is to add json tags to `Metadata` struct. Absence of these tags causes Go to use the field name, which starts with an upper-case letter and breaks the protocol. Extend tests to verify the JSON response. Signed-off-by: ismail simsek --- model/metadata/metadata.go | 6 +++--- web/api/v1/api_test.go | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/model/metadata/metadata.go b/model/metadata/metadata.go index f6f2827a46..1b7e63e0f3 100644 --- a/model/metadata/metadata.go +++ b/model/metadata/metadata.go @@ -17,7 +17,7 @@ import "github.com/prometheus/common/model" // Metadata stores a series' metadata information. type Metadata struct { - Type model.MetricType - Unit string - Help string + Type model.MetricType `json:"type"` + Unit string `json:"unit"` + Help string `json:"help"` } diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index c9ab84087e..c3f88e20df 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -1066,6 +1066,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E response interface{} responseLen int responseMetadataTotal int + responseAsJSON string errType errorType sorter func(interface{}) metadata []targetMetadata @@ -1736,6 +1737,9 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E "prometheus_engine_query_duration_seconds": {{Type: model.MetricTypeSummary, Help: "Query timings", Unit: ""}}, "go_info": {{Type: model.MetricTypeGauge, Help: "Information about the Go environment.", Unit: ""}}, }, + responseAsJSON: `{"prometheus_engine_query_duration_seconds":[{"type":"summary","unit":"", +"help":"Query timings"}], "go_info":[{"type":"gauge","unit":"", +"help":"Information about the Go environment."}]}`, }, // With duplicate metadata for a metric that comes from different targets. { @@ -1767,6 +1771,8 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E response: map[string][]metadata.Metadata{ "go_threads": {{Type: model.MetricTypeGauge, Help: "Number of OS threads created"}}, }, + responseAsJSON: `{"go_threads": [{"type":"gauge","unit":"", +"help":"Number of OS threads created"}]}`, }, // With non-duplicate metadata for the same metric from different targets. { @@ -1801,6 +1807,9 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E {Type: model.MetricTypeGauge, Help: "Number of OS threads that were created."}, }, }, + responseAsJSON: `{"go_threads": [{"type":"gauge","unit":"", +"help":"Number of OS threads created"},{"type":"gauge","unit":"", +"help":"Number of OS threads that were created."}]}`, sorter: func(m interface{}) { v := m.(map[string][]metadata.Metadata)["go_threads"] @@ -1828,7 +1837,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E { Metric: "prometheus_engine_query_duration_seconds", Type: model.MetricTypeSummary, - Help: "Query Timmings.", + Help: "Query Timings.", Unit: "", }, }, @@ -1884,6 +1893,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E {Type: model.MetricTypeSummary, Help: "A summary of the GC invocation durations."}, }, }, + responseAsJSON: `{"go_gc_duration_seconds":[{"help":"A summary of the GC invocation durations.","type":"summary","unit":""}],"go_threads": [{"type":"gauge","unit":"","help":"Number of OS threads created"}]}`, }, // With a limit for the number of metadata per metric and per metric. { @@ -2007,6 +2017,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E {Type: model.MetricTypeGauge, Help: "Number of OS threads that were created."}, }, }, + responseAsJSON: `{"go_threads": [{"type":"gauge","unit":"","help":"Number of OS threads created"},{"type":"gauge","unit":"","help":"Number of OS threads that were created."}]}`, sorter: func(m interface{}) { v := m.(map[string][]metadata.Metadata)["go_threads"] @@ -2880,6 +2891,12 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E } assertAPIResponse(t, res.data, test.response) } + + if test.responseAsJSON != "" { + s, err := json.Marshal(res.data) + require.NoError(t, err) + require.JSONEq(t, test.responseAsJSON, string(s)) + } }) } }) From e537d6d1c198af5ab2c6fe493db8072165accb36 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 26 Feb 2024 10:00:21 +0000 Subject: [PATCH 045/253] Cut 2.50.1 with metadata api bugfix Signed-off-by: Bryan Boreham --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 ++-- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8a42c8ff..0b0350004f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 2.50.1 / 2024-02-26 + +* [BUGFIX] API: Fix metadata API using wrong field names. #13633 + ## 2.50.0 / 2024-02-22 * [CHANGE] Remote Write: Error `storage.ErrTooOldSample` is now generating HTTP error 400 instead of HTTP error 500. #13335 diff --git a/VERSION b/VERSION index 9e29315acb..895eb8a3b2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.50.0 +2.50.1 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index fb199ff5db..89aa2e9ea2 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.50.0", + "version": "0.50.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.50.0", + "@prometheus-io/lezer-promql": "0.50.1", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index 8490a37208..16f3f42637 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.50.0", + "version": "0.50.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 62aad79727..c241d42e57 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.50.0", + "version": "0.50.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.50.0", + "version": "0.50.1", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.50.0", + "version": "0.50.1", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.50.0", + "@prometheus-io/lezer-promql": "0.50.1", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.50.0", + "version": "0.50.1", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.50.0", + "version": "0.50.1", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.0", + "@prometheus-io/codemirror-promql": "0.50.1", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index af6bc6ddd0..a28cb80657 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.50.0" + "version": "0.50.1" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index 1164b0f774..113b2298ce 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.50.0", + "version": "0.50.1", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.0", + "@prometheus-io/codemirror-promql": "0.50.1", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 93b72ec5ddd297cf5b1640c5c45e0fe5865dce56 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 16 Apr 2023 23:12:01 +0200 Subject: [PATCH 046/253] tsdb: create SymbolTables for labels as required Signed-off-by: Bryan Boreham --- model/textparse/openmetricsparse_test.go | 2 +- model/textparse/promparse_test.go | 2 +- tsdb/agent/db.go | 3 ++- tsdb/head.go | 7 ++++--- tsdb/head_wal.go | 11 ++++++----- tsdb/index/index.go | 4 ++++ tsdb/record/record.go | 5 ++++- tsdb/wal.go | 2 ++ tsdb/wlog/checkpoint.go | 4 +++- tsdb/wlog/watcher.go | 5 +++-- 10 files changed, 30 insertions(+), 15 deletions(-) diff --git a/model/textparse/openmetricsparse_test.go b/model/textparse/openmetricsparse_test.go index d128761e39..f3aa21dfa9 100644 --- a/model/textparse/openmetricsparse_test.go +++ b/model/textparse/openmetricsparse_test.go @@ -400,7 +400,7 @@ choices}`, "strange©™\n'quoted' \"name\"", "6"), require.Equal(t, exp[i].m, string(m)) require.Equal(t, exp[i].t, ts) require.Equal(t, exp[i].v, v) - require.Equal(t, exp[i].lset, res) + testutil.RequireEqual(t, exp[i].lset, res) if exp[i].e == nil { require.False(t, found) } else { diff --git a/model/textparse/promparse_test.go b/model/textparse/promparse_test.go index cbfc8aa6cc..775e5faa56 100644 --- a/model/textparse/promparse_test.go +++ b/model/textparse/promparse_test.go @@ -325,7 +325,7 @@ choices}`, "strange©™\n'quoted' \"name\"", "6"), require.Equal(t, exp[i].m, string(m)) require.Equal(t, exp[i].t, ts) require.Equal(t, exp[i].v, v) - require.Equal(t, exp[i].lset, res) + testutil.RequireEqual(t, exp[i].lset, res) case EntryType: m, typ := p.Type() diff --git a/tsdb/agent/db.go b/tsdb/agent/db.go index d399897133..513c2ed5a3 100644 --- a/tsdb/agent/db.go +++ b/tsdb/agent/db.go @@ -417,7 +417,8 @@ func (db *DB) replayWAL() error { func (db *DB) loadWAL(r *wlog.Reader, multiRef map[chunks.HeadSeriesRef]chunks.HeadSeriesRef) (err error) { var ( - dec record.Decoder + syms = labels.NewSymbolTable() // One table for the whole WAL. + dec = record.NewDecoder(syms) lastRef = chunks.HeadSeriesRef(db.nextRef.Load()) decoded = make(chan interface{}, 10) diff --git a/tsdb/head.go b/tsdb/head.go index b3ca0a1488..dd2142e528 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -717,6 +717,7 @@ func (h *Head) Init(minValidTime int64) error { h.startWALReplayStatus(startFrom, endAt) + syms := labels.NewSymbolTable() // One table for the whole WAL. multiRef := map[chunks.HeadSeriesRef]chunks.HeadSeriesRef{} if err == nil && startFrom >= snapIdx { sr, err := wlog.NewSegmentsReader(dir) @@ -731,7 +732,7 @@ func (h *Head) Init(minValidTime int64) error { // A corrupted checkpoint is a hard error for now and requires user // intervention. There's likely little data that can be recovered anyway. - if err := h.loadWAL(wlog.NewReader(sr), multiRef, mmappedChunks, oooMmappedChunks); err != nil { + if err := h.loadWAL(wlog.NewReader(sr), syms, multiRef, mmappedChunks, oooMmappedChunks); err != nil { return fmt.Errorf("backfill checkpoint: %w", err) } h.updateWALReplayStatusRead(startFrom) @@ -764,7 +765,7 @@ func (h *Head) Init(minValidTime int64) error { if err != nil { return fmt.Errorf("segment reader (offset=%d): %w", offset, err) } - err = h.loadWAL(wlog.NewReader(sr), multiRef, mmappedChunks, oooMmappedChunks) + err = h.loadWAL(wlog.NewReader(sr), syms, multiRef, mmappedChunks, oooMmappedChunks) if err := sr.Close(); err != nil { level.Warn(h.logger).Log("msg", "Error while closing the wal segments reader", "err", err) } @@ -792,7 +793,7 @@ func (h *Head) Init(minValidTime int64) error { } sr := wlog.NewSegmentBufReader(s) - err = h.loadWBL(wlog.NewReader(sr), multiRef, lastMmapRef) + err = h.loadWBL(wlog.NewReader(sr), syms, multiRef, lastMmapRef) if err := sr.Close(); err != nil { level.Warn(h.logger).Log("msg", "Error while closing the wbl segments reader", "err", err) } diff --git a/tsdb/head_wal.go b/tsdb/head_wal.go index 1be65f1341..dd836a537c 100644 --- a/tsdb/head_wal.go +++ b/tsdb/head_wal.go @@ -52,7 +52,7 @@ type histogramRecord struct { fh *histogram.FloatHistogram } -func (h *Head) loadWAL(r *wlog.Reader, multiRef map[chunks.HeadSeriesRef]chunks.HeadSeriesRef, mmappedChunks, oooMmappedChunks map[chunks.HeadSeriesRef][]*mmappedChunk) (err error) { +func (h *Head) loadWAL(r *wlog.Reader, syms *labels.SymbolTable, multiRef map[chunks.HeadSeriesRef]chunks.HeadSeriesRef, mmappedChunks, oooMmappedChunks map[chunks.HeadSeriesRef][]*mmappedChunk) (err error) { // Track number of samples that referenced a series we don't know about // for error reporting. var unknownRefs atomic.Uint64 @@ -69,7 +69,6 @@ func (h *Head) loadWAL(r *wlog.Reader, multiRef map[chunks.HeadSeriesRef]chunks. processors = make([]walSubsetProcessor, concurrency) exemplarsInput chan record.RefExemplar - dec record.Decoder shards = make([][]record.RefSample, concurrency) histogramShards = make([][]histogramRecord, concurrency) @@ -137,6 +136,7 @@ func (h *Head) loadWAL(r *wlog.Reader, multiRef map[chunks.HeadSeriesRef]chunks. go func() { defer close(decoded) var err error + dec := record.NewDecoder(syms) for r.Next() { rec := r.Record() switch dec.Type(rec) { @@ -645,7 +645,7 @@ func (wp *walSubsetProcessor) processWALSamples(h *Head, mmappedChunks, oooMmapp return unknownRefs, unknownHistogramRefs, mmapOverlappingChunks } -func (h *Head) loadWBL(r *wlog.Reader, multiRef map[chunks.HeadSeriesRef]chunks.HeadSeriesRef, lastMmapRef chunks.ChunkDiskMapperRef) (err error) { +func (h *Head) loadWBL(r *wlog.Reader, syms *labels.SymbolTable, multiRef map[chunks.HeadSeriesRef]chunks.HeadSeriesRef, lastMmapRef chunks.ChunkDiskMapperRef) (err error) { // Track number of samples, m-map markers, that referenced a series we don't know about // for error reporting. var unknownRefs, mmapMarkerUnknownRefs atomic.Uint64 @@ -657,7 +657,7 @@ func (h *Head) loadWBL(r *wlog.Reader, multiRef map[chunks.HeadSeriesRef]chunks. concurrency = h.opts.WALReplayConcurrency processors = make([]wblSubsetProcessor, concurrency) - dec record.Decoder + dec = record.NewDecoder(syms) shards = make([][]record.RefSample, concurrency) decodedCh = make(chan interface{}, 10) @@ -1360,7 +1360,8 @@ func (h *Head) loadChunkSnapshot() (int, int, map[chunks.HeadSeriesRef]*memSerie errChan = make(chan error, concurrency) refSeries map[chunks.HeadSeriesRef]*memSeries exemplarBuf []record.RefExemplar - dec record.Decoder + syms = labels.NewSymbolTable() // New table for the whole snapshot. + dec = record.NewDecoder(syms) ) wg.Add(concurrency) diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 84c7716849..4241ba8283 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -1118,6 +1118,7 @@ type Reader struct { symbols *Symbols nameSymbols map[uint32]string // Cache of the label name symbol lookups, // as there are not many and they are half of all lookups. + st *labels.SymbolTable // TODO: see if we can merge this with nameSymbols. dec *Decoder @@ -1177,6 +1178,7 @@ func newReader(b ByteSlice, c io.Closer) (*Reader, error) { b: b, c: c, postings: map[string][]postingOffset{}, + st: labels.NewSymbolTable(), } // Verify header. @@ -1653,6 +1655,8 @@ func (r *Reader) Series(id storage.SeriesRef, builder *labels.ScratchBuilder, ch if d.Err() != nil { return d.Err() } + builder.SetSymbolTable(r.st) + builder.Reset() err := r.dec.Series(d.Get(), builder, chks) if err != nil { return fmt.Errorf("read series: %w", err) diff --git a/tsdb/record/record.go b/tsdb/record/record.go index 3931ad05d6..8a8409e55f 100644 --- a/tsdb/record/record.go +++ b/tsdb/record/record.go @@ -192,11 +192,14 @@ type RefMmapMarker struct { } // Decoder decodes series, sample, metadata and tombstone records. -// The zero value is ready to use. type Decoder struct { builder labels.ScratchBuilder } +func NewDecoder(t *labels.SymbolTable) Decoder { // FIXME remove t + return Decoder{builder: labels.NewScratchBuilder(0)} +} + // Type returns the type of the record. // Returns RecordUnknown if no valid record type is found. func (d *Decoder) Type(rec []byte) Type { diff --git a/tsdb/wal.go b/tsdb/wal.go index 1509c9cd96..e06a8aea53 100644 --- a/tsdb/wal.go +++ b/tsdb/wal.go @@ -31,6 +31,7 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/encoding" @@ -859,6 +860,7 @@ func newWALReader(files []*segmentFile, l log.Logger) *walReader { files: files, buf: make([]byte, 0, 128*4096), crc32: newCRC32(), + dec: record.NewDecoder(labels.NewSymbolTable()), } } diff --git a/tsdb/wlog/checkpoint.go b/tsdb/wlog/checkpoint.go index 3d5b56da27..a49ed1a0ce 100644 --- a/tsdb/wlog/checkpoint.go +++ b/tsdb/wlog/checkpoint.go @@ -28,6 +28,7 @@ import ( "github.com/go-kit/log/level" "golang.org/x/exp/slices" + "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/tsdb/chunks" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" @@ -154,7 +155,8 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head tstones []tombstones.Stone exemplars []record.RefExemplar metadata []record.RefMetadata - dec record.Decoder + st = labels.NewSymbolTable() // Needed for decoding; labels do not outlive this function. + dec = record.NewDecoder(st) enc record.Encoder buf []byte recs [][]byte diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index 6994d2dd8a..a4c46bbaa7 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -29,6 +29,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "golang.org/x/exp/slices" + "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/timestamp" "github.com/prometheus/prometheus/tsdb/record" ) @@ -532,7 +533,7 @@ func (w *Watcher) garbageCollectSeries(segmentNum int) error { // Also used with readCheckpoint - implements segmentReadFn. func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { var ( - dec record.Decoder + dec = record.NewDecoder(labels.NewSymbolTable()) // One table per WAL segment means it won't grow indefinitely. series []record.RefSeries samples []record.RefSample samplesToSend []record.RefSample @@ -669,7 +670,7 @@ func (w *Watcher) readSegment(r *LiveReader, segmentNum int, tail bool) error { // Used with readCheckpoint - implements segmentReadFn. func (w *Watcher) readSegmentForGC(r *LiveReader, segmentNum int, _ bool) error { var ( - dec record.Decoder + dec = record.NewDecoder(labels.NewSymbolTable()) // Needed for decoding; labels do not outlive this function. series []record.RefSeries ) for r.Next() && !isClosed(w.quit) { From 925134e6de1e6ecda2cf12abbafa5b0512c0fe93 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 16 Apr 2023 23:13:47 +0200 Subject: [PATCH 047/253] tsdb tests: make work with labels SymbolTable Need to initialize decoders with SymbolTable. Signed-off-by: Bryan Boreham --- tsdb/agent/db_test.go | 6 +++--- tsdb/db_test.go | 4 ++-- tsdb/head_test.go | 2 +- tsdb/record/record_test.go | 4 ++-- tsdb/wal_test.go | 2 +- tsdb/wlog/checkpoint_test.go | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tsdb/agent/db_test.go b/tsdb/agent/db_test.go index 32b7e4394e..a7dae32208 100644 --- a/tsdb/agent/db_test.go +++ b/tsdb/agent/db_test.go @@ -184,7 +184,7 @@ func TestCommit(t *testing.T) { // Read records from WAL and check for expected count of series, samples, and exemplars. var ( r = wlog.NewReader(sr) - dec record.Decoder + dec = record.NewDecoder(labels.NewSymbolTable()) walSeriesCount, walSamplesCount, walExemplarsCount, walHistogramCount, walFloatHistogramCount int ) @@ -293,7 +293,7 @@ func TestRollback(t *testing.T) { // Read records from WAL and check for expected count of series and samples. var ( r = wlog.NewReader(sr) - dec record.Decoder + dec = record.NewDecoder(labels.NewSymbolTable()) walSeriesCount, walSamplesCount, walHistogramCount, walFloatHistogramCount, walExemplarsCount int ) @@ -737,7 +737,7 @@ func TestStorage_DuplicateExemplarsIgnored(t *testing.T) { defer sr.Close() r := wlog.NewReader(sr) - var dec record.Decoder + dec := record.NewDecoder(labels.NewSymbolTable()) for r.Next() { rec := r.Record() if dec.Type(rec) == record.Exemplars { diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 3f9097c087..45a16b8ba3 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -4031,7 +4031,7 @@ func TestOOOWALWrite(t *testing.T) { var ( records []interface{} - dec record.Decoder + dec record.Decoder = record.NewDecoder(labels.NewSymbolTable()) ) for r.Next() { rec := r.Record() @@ -5390,7 +5390,7 @@ func TestWBLAndMmapReplay(t *testing.T) { require.NoError(t, err) sr, err := wlog.NewSegmentsReader(originalWblDir) require.NoError(t, err) - var dec record.Decoder + dec := record.NewDecoder(labels.NewSymbolTable()) r, markers, addedRecs := wlog.NewReader(sr), 0, 0 for r.Next() { rec := r.Record() diff --git a/tsdb/head_test.go b/tsdb/head_test.go index bc81e64570..41c2e062f2 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -172,7 +172,7 @@ func readTestWAL(t testing.TB, dir string) (recs []interface{}) { require.NoError(t, sr.Close()) }() - var dec record.Decoder + dec := record.NewDecoder(labels.NewSymbolTable()) r := wlog.NewReader(sr) for r.Next() { diff --git a/tsdb/record/record_test.go b/tsdb/record/record_test.go index 773c3abfc9..da7748e187 100644 --- a/tsdb/record/record_test.go +++ b/tsdb/record/record_test.go @@ -29,7 +29,7 @@ import ( func TestRecord_EncodeDecode(t *testing.T) { var enc Encoder - var dec Decoder + dec := NewDecoder(labels.NewSymbolTable()) series := []RefSeries{ { @@ -187,7 +187,7 @@ func TestRecord_EncodeDecode(t *testing.T) { // Bugfix check for pull/521 and pull/523. func TestRecord_Corrupted(t *testing.T) { var enc Encoder - var dec Decoder + dec := NewDecoder(labels.NewSymbolTable()) t.Run("Test corrupted series record", func(t *testing.T) { series := []RefSeries{ diff --git a/tsdb/wal_test.go b/tsdb/wal_test.go index 466183e9b8..7794a54547 100644 --- a/tsdb/wal_test.go +++ b/tsdb/wal_test.go @@ -510,7 +510,7 @@ func TestMigrateWAL_Fuzz(t *testing.T) { r := wlog.NewReader(sr) var res []interface{} - var dec record.Decoder + dec := record.NewDecoder(labels.NewSymbolTable()) for r.Next() { rec := r.Record() diff --git a/tsdb/wlog/checkpoint_test.go b/tsdb/wlog/checkpoint_test.go index 89b1c7f339..142a5a9d49 100644 --- a/tsdb/wlog/checkpoint_test.go +++ b/tsdb/wlog/checkpoint_test.go @@ -237,7 +237,7 @@ func TestCheckpoint(t *testing.T) { require.NoError(t, err) defer sr.Close() - var dec record.Decoder + dec := record.NewDecoder(labels.NewSymbolTable()) var series []record.RefSeries var metadata []record.RefMetadata r := NewReader(sr) From 3716326f3f19aae95789a078de9560b3cb432404 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 23 Nov 2023 18:37:42 +0000 Subject: [PATCH 048/253] rules: call NewScratchBuilder Need to initialize ScratchBuilder with a SymbolTable. Signed-off-by: Bryan Boreham --- rules/alerting.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rules/alerting.go b/rules/alerting.go index a99b2b4aa4..7b0921a724 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -356,6 +356,8 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, // or update the expression value for existing elements. resultFPs := map[uint64]struct{}{} + lb := labels.NewBuilder(labels.EmptyLabels()) + sb := labels.NewScratchBuilder(0) var vec promql.Vector alerts := make(map[uint64]*Alert, len(res)) for _, smpl := range res { @@ -391,14 +393,14 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, return result } - lb := labels.NewBuilder(smpl.Metric).Del(labels.MetricName) - + lb.Reset(smpl.Metric) + lb.Del(labels.MetricName) r.labels.Range(func(l labels.Label) { lb.Set(l.Name, expand(l.Value)) }) lb.Set(labels.AlertName, r.Name()) - sb := labels.ScratchBuilder{} + sb.Reset() r.annotations.Range(func(a labels.Label) { sb.Add(a.Name, expand(a.Value)) }) From 123109e9679677e6497a98dd7a06e436e6abb729 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 30 Apr 2023 12:52:34 +0100 Subject: [PATCH 049/253] config: make work with SymbolTable labels Need a SymbolTable when we expand ExternalLabels. And we can't use labels.NewBuilder because we need to add blank values. Signed-off-by: Bryan Boreham --- config/config.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 7fa03a1445..e81ee8dd0b 100644 --- a/config/config.go +++ b/config/config.go @@ -82,7 +82,7 @@ func Load(s string, expandExternalLabels bool, logger log.Logger) (*Config, erro return cfg, nil } - b := labels.ScratchBuilder{} + b := labels.NewScratchBuilder(0) cfg.GlobalConfig.ExternalLabels.Range(func(v labels.Label) { newV := os.Expand(v.Value, func(s string) string { if s == "$" { @@ -97,6 +97,7 @@ func Load(s string, expandExternalLabels bool, logger log.Logger) (*Config, erro if newV != v.Value { level.Debug(logger).Log("msg", "External label replaced", "label", v.Name, "input", v.Value, "output", newV) } + // Note newV can be blank. https://github.com/prometheus/prometheus/issues/11024 b.Add(v.Name, newV) }) cfg.GlobalConfig.ExternalLabels = b.Labels() From eff3a13e196bee80d0247020fca293da3e990476 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 25 Mar 2023 13:31:24 +0000 Subject: [PATCH 050/253] model/textparse: parsers take a labels SymbolTable This allows strings to be interned to save memory. Signed-off-by: Bryan Boreham --- cmd/promtool/backfill.go | 5 +++-- model/textparse/interface.go | 12 ++++++------ model/textparse/interface_test.go | 4 +++- model/textparse/openmetricsparse.go | 7 +++++-- model/textparse/openmetricsparse_test.go | 8 ++++---- model/textparse/promparse.go | 7 +++++-- model/textparse/promparse_test.go | 19 +++++++++++-------- model/textparse/protobufparse.go | 3 ++- model/textparse/protobufparse_test.go | 4 ++-- web/federate_test.go | 2 +- 10 files changed, 42 insertions(+), 29 deletions(-) diff --git a/cmd/promtool/backfill.go b/cmd/promtool/backfill.go index 39410881b2..601c3ced9f 100644 --- a/cmd/promtool/backfill.go +++ b/cmd/promtool/backfill.go @@ -127,7 +127,8 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn ctx := context.Background() app := w.Appender(ctx) - p := textparse.NewOpenMetricsParser(input) + symbolTable := labels.NewSymbolTable() // One table per block means it won't grow too large. + p := textparse.NewOpenMetricsParser(input, symbolTable) samplesCount := 0 for { e, err := p.Next() @@ -216,7 +217,7 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn } func backfill(maxSamplesInAppender int, input []byte, outputDir string, humanReadable, quiet bool, maxBlockDuration time.Duration) (err error) { - p := textparse.NewOpenMetricsParser(input) + p := textparse.NewOpenMetricsParser(input, nil) // Don't need a SymbolTable to get max and min timestamps. maxt, mint, err := getMinAndMaxTimestamps(p) if err != nil { return fmt.Errorf("getting min and max timestamp: %w", err) diff --git a/model/textparse/interface.go b/model/textparse/interface.go index 3a363ebfbc..2e8c40e72f 100644 --- a/model/textparse/interface.go +++ b/model/textparse/interface.go @@ -80,22 +80,22 @@ type Parser interface { // // This function always returns a valid parser, but might additionally // return an error if the content type cannot be parsed. -func New(b []byte, contentType string, parseClassicHistograms bool) (Parser, error) { +func New(b []byte, contentType string, parseClassicHistograms bool, st *labels.SymbolTable) (Parser, error) { if contentType == "" { - return NewPromParser(b), nil + return NewPromParser(b, st), nil } mediaType, _, err := mime.ParseMediaType(contentType) if err != nil { - return NewPromParser(b), err + return NewPromParser(b, st), err } switch mediaType { case "application/openmetrics-text": - return NewOpenMetricsParser(b), nil + return NewOpenMetricsParser(b, st), nil case "application/vnd.google.protobuf": - return NewProtobufParser(b, parseClassicHistograms), nil + return NewProtobufParser(b, parseClassicHistograms, st), nil default: - return NewPromParser(b), nil + return NewPromParser(b, st), nil } } diff --git a/model/textparse/interface_test.go b/model/textparse/interface_test.go index de140d6819..c644565628 100644 --- a/model/textparse/interface_test.go +++ b/model/textparse/interface_test.go @@ -17,6 +17,8 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/prometheus/prometheus/model/labels" ) func TestNewParser(t *testing.T) { @@ -91,7 +93,7 @@ func TestNewParser(t *testing.T) { tt := tt // Copy to local variable before going parallel. t.Parallel() - p, err := New([]byte{}, tt.contentType, false) + p, err := New([]byte{}, tt.contentType, false, labels.NewSymbolTable()) tt.validateParser(t, p) if tt.err == "" { require.NoError(t, err) diff --git a/model/textparse/openmetricsparse.go b/model/textparse/openmetricsparse.go index 2a7eae080f..ea92bc55f4 100644 --- a/model/textparse/openmetricsparse.go +++ b/model/textparse/openmetricsparse.go @@ -97,8 +97,11 @@ type OpenMetricsParser struct { } // NewOpenMetricsParser returns a new parser of the byte slice. -func NewOpenMetricsParser(b []byte) Parser { - return &OpenMetricsParser{l: &openMetricsLexer{b: b}} +func NewOpenMetricsParser(b []byte, st *labels.SymbolTable) Parser { + return &OpenMetricsParser{ + l: &openMetricsLexer{b: b}, + builder: labels.NewScratchBuilderWithSymbolTable(st, 16), + } } // Series returns the bytes of the series, the timestamp if set, and the value diff --git a/model/textparse/openmetricsparse_test.go b/model/textparse/openmetricsparse_test.go index f3aa21dfa9..e356beeae5 100644 --- a/model/textparse/openmetricsparse_test.go +++ b/model/textparse/openmetricsparse_test.go @@ -247,7 +247,7 @@ foo_total 17.0 1520879607.789 # {id="counter-test"} 5` }, } - p := NewOpenMetricsParser([]byte(input)) + p := NewOpenMetricsParser([]byte(input), labels.NewSymbolTable()) i := 0 var res labels.Labels @@ -378,7 +378,7 @@ choices}`, "strange©™\n'quoted' \"name\"", "6"), }, } - p := NewOpenMetricsParser([]byte(input)) + p := NewOpenMetricsParser([]byte(input), labels.NewSymbolTable()) i := 0 var res labels.Labels @@ -727,7 +727,7 @@ func TestOpenMetricsParseErrors(t *testing.T) { } for i, c := range cases { - p := NewOpenMetricsParser([]byte(c.input)) + p := NewOpenMetricsParser([]byte(c.input), labels.NewSymbolTable()) var err error for err == nil { _, err = p.Next() @@ -792,7 +792,7 @@ func TestOMNullByteHandling(t *testing.T) { } for i, c := range cases { - p := NewOpenMetricsParser([]byte(c.input)) + p := NewOpenMetricsParser([]byte(c.input), labels.NewSymbolTable()) var err error for err == nil { _, err = p.Next() diff --git a/model/textparse/promparse.go b/model/textparse/promparse.go index 1de783b0d0..54b5306e6a 100644 --- a/model/textparse/promparse.go +++ b/model/textparse/promparse.go @@ -166,8 +166,11 @@ type PromParser struct { } // NewPromParser returns a new parser of the byte slice. -func NewPromParser(b []byte) Parser { - return &PromParser{l: &promlexer{b: append(b, '\n')}} +func NewPromParser(b []byte, st *labels.SymbolTable) Parser { + return &PromParser{ + l: &promlexer{b: append(b, '\n')}, + builder: labels.NewScratchBuilderWithSymbolTable(st, 16), + } } // Series returns the bytes of the series, the timestamp if set, and the value diff --git a/model/textparse/promparse_test.go b/model/textparse/promparse_test.go index 775e5faa56..4ec8c9b9cd 100644 --- a/model/textparse/promparse_test.go +++ b/model/textparse/promparse_test.go @@ -178,7 +178,7 @@ testmetric{label="\"bar\""} 1` }, } - p := NewPromParser([]byte(input)) + p := NewPromParser([]byte(input), labels.NewSymbolTable()) i := 0 var res labels.Labels @@ -304,7 +304,7 @@ choices}`, "strange©™\n'quoted' \"name\"", "6"), }, } - p := NewPromParser([]byte(input)) + p := NewPromParser([]byte(input), labels.NewSymbolTable()) i := 0 var res labels.Labels @@ -422,7 +422,7 @@ func TestPromParseErrors(t *testing.T) { } for i, c := range cases { - p := NewPromParser([]byte(c.input)) + p := NewPromParser([]byte(c.input), labels.NewSymbolTable()) var err error for err == nil { _, err = p.Next() @@ -476,7 +476,7 @@ func TestPromNullByteHandling(t *testing.T) { } for i, c := range cases { - p := NewPromParser([]byte(c.input)) + p := NewPromParser([]byte(c.input), labels.NewSymbolTable()) var err error for err == nil { _, err = p.Next() @@ -497,7 +497,7 @@ const ( ) func BenchmarkParse(b *testing.B) { - for parserName, parser := range map[string]func([]byte) Parser{ + for parserName, parser := range map[string]func([]byte, *labels.SymbolTable) Parser{ "prometheus": NewPromParser, "openmetrics": NewOpenMetricsParser, } { @@ -516,8 +516,9 @@ func BenchmarkParse(b *testing.B) { b.ReportAllocs() b.ResetTimer() + st := labels.NewSymbolTable() for i := 0; i < b.N; i += promtestdataSampleCount { - p := parser(buf) + p := parser(buf, st) Outer: for i < b.N { @@ -544,8 +545,9 @@ func BenchmarkParse(b *testing.B) { b.ReportAllocs() b.ResetTimer() + st := labels.NewSymbolTable() for i := 0; i < b.N; i += promtestdataSampleCount { - p := parser(buf) + p := parser(buf, st) Outer: for i < b.N { @@ -577,8 +579,9 @@ func BenchmarkParse(b *testing.B) { b.ReportAllocs() b.ResetTimer() + st := labels.NewSymbolTable() for i := 0; i < b.N; i += promtestdataSampleCount { - p := parser(buf) + p := parser(buf, st) Outer: for i < b.N { diff --git a/model/textparse/protobufparse.go b/model/textparse/protobufparse.go index 8fd89af825..ea3a2e1a34 100644 --- a/model/textparse/protobufparse.go +++ b/model/textparse/protobufparse.go @@ -80,13 +80,14 @@ type ProtobufParser struct { } // NewProtobufParser returns a parser for the payload in the byte slice. -func NewProtobufParser(b []byte, parseClassicHistograms bool) Parser { +func NewProtobufParser(b []byte, parseClassicHistograms bool, st *labels.SymbolTable) Parser { return &ProtobufParser{ in: b, state: EntryInvalid, mf: &dto.MetricFamily{}, metricBytes: &bytes.Buffer{}, parseClassicHistograms: parseClassicHistograms, + builder: labels.NewScratchBuilderWithSymbolTable(st, 16), } } diff --git a/model/textparse/protobufparse_test.go b/model/textparse/protobufparse_test.go index c807ae644c..e323a6cc8f 100644 --- a/model/textparse/protobufparse_test.go +++ b/model/textparse/protobufparse_test.go @@ -743,7 +743,7 @@ func TestProtobufParse(t *testing.T) { }{ { name: "ignore classic buckets of native histograms", - parser: NewProtobufParser(inputBuf.Bytes(), false), + parser: NewProtobufParser(inputBuf.Bytes(), false, labels.NewSymbolTable()), expected: []parseResult{ { m: "go_build_info", @@ -1280,7 +1280,7 @@ func TestProtobufParse(t *testing.T) { }, { name: "parse classic and native buckets", - parser: NewProtobufParser(inputBuf.Bytes(), true), + parser: NewProtobufParser(inputBuf.Bytes(), true, labels.NewSymbolTable()), expected: []parseResult{ { // 0 m: "go_build_info", diff --git a/web/federate_test.go b/web/federate_test.go index 92b806fe89..b8749dfa32 100644 --- a/web/federate_test.go +++ b/web/federate_test.go @@ -391,7 +391,7 @@ func TestFederationWithNativeHistograms(t *testing.T) { body, err := io.ReadAll(res.Body) require.NoError(t, err) - p := textparse.NewProtobufParser(body, false) + p := textparse.NewProtobufParser(body, false, labels.NewSymbolTable()) var actVec promql.Vector metricFamilies := 0 l := labels.Labels{} From 9ba13de220f7b15e6b0554d7a045e4225e366e09 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 16 Apr 2023 14:15:13 +0200 Subject: [PATCH 051/253] scraping: pass a Builder to get Target labels This saves memory allocations from making a new Builder every time. Signed-off-by: Bryan Boreham --- scrape/target.go | 4 ++-- scrape/target_test.go | 3 ++- web/api/v1/api.go | 11 +++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/scrape/target.go b/scrape/target.go index c9287f818a..ad4b4f6857 100644 --- a/scrape/target.go +++ b/scrape/target.go @@ -169,8 +169,8 @@ func (t *Target) offset(interval time.Duration, offsetSeed uint64) time.Duration } // Labels returns a copy of the set of all public labels of the target. -func (t *Target) Labels() labels.Labels { - b := labels.NewScratchBuilder(t.labels.Len()) +func (t *Target) Labels(b *labels.ScratchBuilder) labels.Labels { + b.Reset() t.labels.Range(func(l labels.Label) { if !strings.HasPrefix(l.Name, model.ReservedLabelPrefix) { b.Add(l.Name, l.Value) diff --git a/scrape/target_test.go b/scrape/target_test.go index 6e87ce71d9..413fbc1b81 100644 --- a/scrape/target_test.go +++ b/scrape/target_test.go @@ -42,7 +42,8 @@ const ( func TestTargetLabels(t *testing.T) { target := newTestTarget("example.com:80", 0, labels.FromStrings("job", "some_job", "foo", "bar")) want := labels.FromStrings(model.JobLabel, "some_job", "foo", "bar") - got := target.Labels() + b := labels.NewScratchBuilder(0) + got := target.Labels(&b) require.Equal(t, want, got) i := 0 target.LabelsRange(func(l labels.Label) { diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 0c02293bfa..fcb55026e8 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -1009,6 +1009,7 @@ func (api *API) targets(r *http.Request) apiFuncResult { targetsActive := api.targetRetriever(r.Context()).TargetsActive() activeKeys, numTargets := sortKeys(targetsActive) res.ActiveTargets = make([]*Target, 0, numTargets) + builder := labels.NewScratchBuilder(0) for _, key := range activeKeys { if scrapePool != "" && key != scrapePool { @@ -1025,7 +1026,7 @@ func (api *API) targets(r *http.Request) apiFuncResult { res.ActiveTargets = append(res.ActiveTargets, &Target{ DiscoveredLabels: target.DiscoveredLabels(), - Labels: target.Labels(), + Labels: target.Labels(&builder), ScrapePool: key, ScrapeURL: target.URL().String(), GlobalURL: globalURL.String(), @@ -1101,6 +1102,7 @@ func (api *API) targetMetadata(r *http.Request) apiFuncResult { } } + builder := labels.NewScratchBuilder(0) metric := r.FormValue("metric") res := []metricMetadata{} for _, tt := range api.targetRetriever(r.Context()).TargetsActive() { @@ -1108,15 +1110,16 @@ func (api *API) targetMetadata(r *http.Request) apiFuncResult { if limit >= 0 && len(res) >= limit { break } + targetLabels := t.Labels(&builder) // Filter targets that don't satisfy the label matchers. - if matchTarget != "" && !matchLabels(t.Labels(), matchers) { + if matchTarget != "" && !matchLabels(targetLabels, matchers) { continue } // If no metric is specified, get the full list for the target. if metric == "" { for _, md := range t.ListMetadata() { res = append(res, metricMetadata{ - Target: t.Labels(), + Target: targetLabels, Metric: md.Metric, Type: md.Type, Help: md.Help, @@ -1128,7 +1131,7 @@ func (api *API) targetMetadata(r *http.Request) apiFuncResult { // Get metadata for the specified metric. if md, ok := t.GetMetadata(metric); ok { res = append(res, metricMetadata{ - Target: t.Labels(), + Target: targetLabels, Type: md.Type, Help: md.Help, Unit: md.Unit, From 0403d098e1f152d450a0b622a6175cf0c56944fd Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 23 Nov 2023 19:02:37 +0000 Subject: [PATCH 052/253] scraping: re-use symbolTable for target discovery Call labels.NewBuilderWithSymbolTable. Signed-off-by: Bryan Boreham --- scrape/scrape.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index de35b9e408..9b295a349c 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -73,6 +73,8 @@ type scrapePool struct { client *http.Client loops map[uint64]loop + symbolTable *labels.SymbolTable + targetMtx sync.Mutex // activeTargets and loops must always be synchronized to have the same // set of hashes. @@ -136,6 +138,7 @@ func newScrapePool(cfg *config.ScrapeConfig, app storage.Appendable, offsetSeed client: client, activeTargets: map[uint64]*Target{}, loops: map[uint64]loop{}, + symbolTable: labels.NewSymbolTable(), // TODO: clean this out from time to time. logger: logger, metrics: metrics, httpOpts: options.HTTPClientOptions, @@ -361,7 +364,7 @@ func (sp *scrapePool) Sync(tgs []*targetgroup.Group) { sp.targetMtx.Lock() var all []*Target var targets []*Target - lb := labels.NewBuilder(labels.EmptyLabels()) + lb := labels.NewBuilderWithSymbolTable(sp.symbolTable) sp.droppedTargets = []*Target{} sp.droppedTargetsCount = 0 for _, tg := range tgs { From abb3a62f04c4563f80db1fc8c0dd726ece62c1c0 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 24 Nov 2023 18:08:56 +0000 Subject: [PATCH 053/253] scraping: re-use symbol table for scrape loops One symbol table for all loops in the same scrape pool, i.e. from the same job. Signed-off-by: Bryan Boreham --- scrape/scrape.go | 6 +++++- scrape/scrape_test.go | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index 9b295a349c..072f5f47be 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -163,6 +163,7 @@ func newScrapePool(cfg *config.ScrapeConfig, app storage.Appendable, offsetSeed func(l labels.Labels) labels.Labels { return mutateReportSampleLabels(l, opts.target) }, func(ctx context.Context) storage.Appender { return app.Appender(ctx) }, cache, + sp.symbolTable, offsetSeed, opts.honorTimestamps, opts.trackTimestampsStaleness, @@ -809,6 +810,7 @@ type scrapeLoop struct { enableCTZeroIngestion bool appender func(ctx context.Context) storage.Appender + symbolTable *labels.SymbolTable sampleMutator labelsMutator reportSampleMutator labelsMutator @@ -1088,6 +1090,7 @@ func newScrapeLoop(ctx context.Context, reportSampleMutator labelsMutator, appender func(ctx context.Context) storage.Appender, cache *scrapeCache, + symbolTable *labels.SymbolTable, offsetSeed uint64, honorTimestamps bool, trackTimestampsStaleness bool, @@ -1133,6 +1136,7 @@ func newScrapeLoop(ctx context.Context, buffers: buffers, cache: cache, appender: appender, + symbolTable: symbolTable, sampleMutator: sampleMutator, reportSampleMutator: reportSampleMutator, stopped: make(chan struct{}), @@ -1431,7 +1435,7 @@ type appendErrors struct { } func (sl *scrapeLoop) append(app storage.Appender, b []byte, contentType string, ts time.Time) (total, added, seriesAdded int, err error) { - p, err := textparse.New(b, contentType, sl.scrapeClassicHistograms) + p, err := textparse.New(b, contentType, sl.scrapeClassicHistograms, sl.symbolTable) if err != nil { level.Debug(sl.l).Log( "msg", "Invalid content type on scrape, using prometheus parser as fallback.", diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index eefa7be66f..67f22f1491 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -660,6 +660,7 @@ func newBasicScrapeLoop(t testing.TB, ctx context.Context, scraper scraper, app nopMutator, app, nil, + nil, 0, true, false, @@ -800,6 +801,7 @@ func TestScrapeLoopRun(t *testing.T) { nopMutator, app, nil, + nil, 0, true, false, @@ -942,6 +944,7 @@ func TestScrapeLoopMetadata(t *testing.T) { nopMutator, func(ctx context.Context) storage.Appender { return nopAppender{} }, cache, + labels.NewSymbolTable(), 0, true, false, @@ -1470,7 +1473,7 @@ func TestScrapeLoopAppendCacheEntryButErrNotFound(t *testing.T) { fakeRef := storage.SeriesRef(1) expValue := float64(1) metric := []byte(`metric{n="1"} 1`) - p, warning := textparse.New(metric, "", false) + p, warning := textparse.New(metric, "", false, labels.NewSymbolTable()) require.NoError(t, warning) var lset labels.Labels From 4e748b9cd8c269948b79d35e46d77bff66ced7cf Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 10 Oct 2023 21:30:19 +0100 Subject: [PATCH 054/253] scraping: re-use labels Builder in scrape report metrics Signed-off-by: Bryan Boreham --- scrape/scrape.go | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index 072f5f47be..ce581d71b8 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -1785,30 +1785,31 @@ func (sl *scrapeLoop) report(app storage.Appender, start time.Time, duration tim if scrapeErr == nil { health = 1 } + b := labels.NewBuilderWithSymbolTable(sl.symbolTable) - if err = sl.addReportSample(app, scrapeHealthMetricName, ts, health); err != nil { + if err = sl.addReportSample(app, scrapeHealthMetricName, ts, health, b); err != nil { return } - if err = sl.addReportSample(app, scrapeDurationMetricName, ts, duration.Seconds()); err != nil { + if err = sl.addReportSample(app, scrapeDurationMetricName, ts, duration.Seconds(), b); err != nil { return } - if err = sl.addReportSample(app, scrapeSamplesMetricName, ts, float64(scraped)); err != nil { + if err = sl.addReportSample(app, scrapeSamplesMetricName, ts, float64(scraped), b); err != nil { return } - if err = sl.addReportSample(app, samplesPostRelabelMetricName, ts, float64(added)); err != nil { + if err = sl.addReportSample(app, samplesPostRelabelMetricName, ts, float64(added), b); err != nil { return } - if err = sl.addReportSample(app, scrapeSeriesAddedMetricName, ts, float64(seriesAdded)); err != nil { + if err = sl.addReportSample(app, scrapeSeriesAddedMetricName, ts, float64(seriesAdded), b); err != nil { return } if sl.reportExtraMetrics { - if err = sl.addReportSample(app, scrapeTimeoutMetricName, ts, sl.timeout.Seconds()); err != nil { + if err = sl.addReportSample(app, scrapeTimeoutMetricName, ts, sl.timeout.Seconds(), b); err != nil { return } - if err = sl.addReportSample(app, scrapeSampleLimitMetricName, ts, float64(sl.sampleLimit)); err != nil { + if err = sl.addReportSample(app, scrapeSampleLimitMetricName, ts, float64(sl.sampleLimit), b); err != nil { return } - if err = sl.addReportSample(app, scrapeBodySizeBytesMetricName, ts, float64(bytes)); err != nil { + if err = sl.addReportSample(app, scrapeBodySizeBytesMetricName, ts, float64(bytes), b); err != nil { return } } @@ -1819,37 +1820,38 @@ func (sl *scrapeLoop) reportStale(app storage.Appender, start time.Time) (err er ts := timestamp.FromTime(start) stale := math.Float64frombits(value.StaleNaN) + b := labels.NewBuilder(labels.EmptyLabels()) - if err = sl.addReportSample(app, scrapeHealthMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeHealthMetricName, ts, stale, b); err != nil { return } - if err = sl.addReportSample(app, scrapeDurationMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeDurationMetricName, ts, stale, b); err != nil { return } - if err = sl.addReportSample(app, scrapeSamplesMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeSamplesMetricName, ts, stale, b); err != nil { return } - if err = sl.addReportSample(app, samplesPostRelabelMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, samplesPostRelabelMetricName, ts, stale, b); err != nil { return } - if err = sl.addReportSample(app, scrapeSeriesAddedMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeSeriesAddedMetricName, ts, stale, b); err != nil { return } if sl.reportExtraMetrics { - if err = sl.addReportSample(app, scrapeTimeoutMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeTimeoutMetricName, ts, stale, b); err != nil { return } - if err = sl.addReportSample(app, scrapeSampleLimitMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeSampleLimitMetricName, ts, stale, b); err != nil { return } - if err = sl.addReportSample(app, scrapeBodySizeBytesMetricName, ts, stale); err != nil { + if err = sl.addReportSample(app, scrapeBodySizeBytesMetricName, ts, stale, b); err != nil { return } } return } -func (sl *scrapeLoop) addReportSample(app storage.Appender, s []byte, t int64, v float64) error { +func (sl *scrapeLoop) addReportSample(app storage.Appender, s []byte, t int64, v float64, b *labels.Builder) error { ce, ok := sl.cache.get(s) var ref storage.SeriesRef var lset labels.Labels @@ -1860,8 +1862,9 @@ func (sl *scrapeLoop) addReportSample(app storage.Appender, s []byte, t int64, v // The constants are suffixed with the invalid \xff unicode rune to avoid collisions // with scraped metrics in the cache. // We have to drop it when building the actual metric. - lset = labels.FromStrings(labels.MetricName, string(s[:len(s)-1])) - lset = sl.reportSampleMutator(lset) + b.Reset(labels.EmptyLabels()) + b.Set(labels.MetricName, string(s[:len(s)-1])) + lset = sl.reportSampleMutator(b.Labels()) } ref, err := app.Append(ref, lset, t, v) From 5f50d974c92bd55199961bdc514f92fbd5ac2fd1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 24 Nov 2023 19:46:26 +0000 Subject: [PATCH 055/253] scraping: reset symbol table periodically Signed-off-by: Bryan Boreham --- scrape/manager_test.go | 11 ++++++----- scrape/scrape.go | 42 ++++++++++++++++++++++++++++++------------ scrape/scrape_test.go | 14 +++++++++----- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/scrape/manager_test.go b/scrape/manager_test.go index 7b7a929168..f90fd0ce66 100644 --- a/scrape/manager_test.go +++ b/scrape/manager_test.go @@ -523,11 +523,12 @@ scrape_configs: loops: map[uint64]loop{ 1: noopLoop(), }, - newLoop: newLoop, - logger: nil, - config: cfg1.ScrapeConfigs[0], - client: http.DefaultClient, - metrics: scrapeManager.metrics, + newLoop: newLoop, + logger: nil, + config: cfg1.ScrapeConfigs[0], + client: http.DefaultClient, + metrics: scrapeManager.metrics, + symbolTable: labels.NewSymbolTable(), } scrapeManager.scrapePools = map[string]*scrapePool{ "job1": sp, diff --git a/scrape/scrape.go b/scrape/scrape.go index ce581d71b8..aa2d5538b1 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -73,7 +73,9 @@ type scrapePool struct { client *http.Client loops map[uint64]loop - symbolTable *labels.SymbolTable + symbolTable *labels.SymbolTable + lastSymbolTableCheck time.Time + initialSymbolTableLen int targetMtx sync.Mutex // activeTargets and loops must always be synchronized to have the same @@ -132,17 +134,18 @@ func newScrapePool(cfg *config.ScrapeConfig, app storage.Appendable, offsetSeed ctx, cancel := context.WithCancel(context.Background()) sp := &scrapePool{ - cancel: cancel, - appendable: app, - config: cfg, - client: client, - activeTargets: map[uint64]*Target{}, - loops: map[uint64]loop{}, - symbolTable: labels.NewSymbolTable(), // TODO: clean this out from time to time. - logger: logger, - metrics: metrics, - httpOpts: options.HTTPClientOptions, - noDefaultPort: options.NoDefaultPort, + cancel: cancel, + appendable: app, + config: cfg, + client: client, + activeTargets: map[uint64]*Target{}, + loops: map[uint64]loop{}, + symbolTable: labels.NewSymbolTable(), + lastSymbolTableCheck: time.Now(), + logger: logger, + metrics: metrics, + httpOpts: options.HTTPClientOptions, + noDefaultPort: options.NoDefaultPort, } sp.newLoop = func(opts scrapeLoopOptions) loop { // Update the targets retrieval function for metadata to a new scrape cache. @@ -352,6 +355,21 @@ func (sp *scrapePool) reload(cfg *config.ScrapeConfig) error { sp.metrics.targetReloadIntervalLength.WithLabelValues(interval.String()).Observe( time.Since(start).Seconds(), ) + + // Here we take steps to clear out the symbol table if it has grown a lot. + // After waiting some time for things to settle, we take the size of the symbol-table. + // If, after some more time, the table has grown to twice that size, we start a new one. + const minTimeToCleanSymbolTable = 5 * time.Minute + if time.Since(sp.lastSymbolTableCheck) > minTimeToCleanSymbolTable { + if sp.initialSymbolTableLen == 0 { + sp.initialSymbolTableLen = sp.symbolTable.Len() + } else if sp.symbolTable.Len() > 2*sp.initialSymbolTableLen { + sp.symbolTable = labels.NewSymbolTable() + sp.initialSymbolTableLen = 0 + } + sp.lastSymbolTableCheck = time.Now() + } + return nil } diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index 67f22f1491..bcaeb460e2 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -279,6 +279,7 @@ func TestScrapePoolReload(t *testing.T) { logger: nil, client: http.DefaultClient, metrics: newTestScrapeMetrics(t), + symbolTable: labels.NewSymbolTable(), } // Reloading a scrape pool with a new scrape configuration must stop all scrape @@ -357,10 +358,11 @@ func TestScrapePoolReloadPreserveRelabeledIntervalTimeout(t *testing.T) { loops: map[uint64]loop{ 1: noopLoop(), }, - newLoop: newLoop, - logger: nil, - client: http.DefaultClient, - metrics: newTestScrapeMetrics(t), + newLoop: newLoop, + logger: nil, + client: http.DefaultClient, + metrics: newTestScrapeMetrics(t), + symbolTable: labels.NewSymbolTable(), } err := sp.reload(reloadCfg) @@ -391,6 +393,7 @@ func TestScrapePoolTargetLimit(t *testing.T) { logger: log.NewNopLogger(), client: http.DefaultClient, metrics: newTestScrapeMetrics(t), + symbolTable: labels.NewSymbolTable(), } tgs := []*targetgroup.Group{} @@ -623,6 +626,7 @@ func TestScrapePoolScrapeLoopsStarted(t *testing.T) { logger: nil, client: http.DefaultClient, metrics: newTestScrapeMetrics(t), + symbolTable: labels.NewSymbolTable(), } tgs := []*targetgroup.Group{ @@ -660,7 +664,7 @@ func newBasicScrapeLoop(t testing.TB, ctx context.Context, scraper scraper, app nopMutator, app, nil, - nil, + labels.NewSymbolTable(), 0, true, false, From 0347148628ac5511cc52c26497287b7fb6ce9a76 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 29 Nov 2023 18:19:48 +0000 Subject: [PATCH 056/253] promql: fuzz test needs symbol table for parser Signed-off-by: Bryan Boreham --- promql/fuzz.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/promql/fuzz.go b/promql/fuzz.go index d2e5925ebc..3fd50b9496 100644 --- a/promql/fuzz.go +++ b/promql/fuzz.go @@ -20,6 +20,7 @@ import ( "errors" "io" + "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/textparse" "github.com/prometheus/prometheus/promql/parser" ) @@ -56,8 +57,11 @@ const ( maxInputSize = 10240 ) +// Use package-scope symbol table to avoid memory allocation on every fuzzing operation. +var symbolTable = labels.NewSymbolTable() + func fuzzParseMetricWithContentType(in []byte, contentType string) int { - p, warning := textparse.New(in, contentType, false) + p, warning := textparse.New(in, contentType, false, symbolTable) if warning != nil { // An invalid content type is being passed, which should not happen // in this context. From c8c28efcb36ce67c84c0044145dc32a3b76ccd8f Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 26 Jan 2024 17:28:55 +0000 Subject: [PATCH 057/253] Run Go tests with -tags dedupelabels Signed-off-by: Bryan Boreham --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1e2b66bf1..aac5d23458 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,7 @@ jobs: - run: make GO_ONLY=1 SKIP_GOLANGCI_LINT=1 - run: go test ./tsdb/ -test.tsdb-isolation=false - run: go test --tags=stringlabels ./... + - run: go test --tags=dedupelabels ./... - run: GOARCH=386 go test ./cmd/prometheus - run: make -C documentation/examples/remote_storage - run: make -C documentation/examples From d16ce3c9bd774eaf6d11b887fd8e26461229c8bf Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 1 Feb 2024 18:32:52 +0000 Subject: [PATCH 058/253] model/labels (dedupelabels): small clarifications Suggestion from @colega. Signed-off-by: Bryan Boreham --- model/labels/labels_dedupelabels.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/model/labels/labels_dedupelabels.go b/model/labels/labels_dedupelabels.go index db6c56b337..2306d38d1c 100644 --- a/model/labels/labels_dedupelabels.go +++ b/model/labels/labels_dedupelabels.go @@ -81,10 +81,10 @@ func (t *SymbolTable) toNumUnlocked(name string) int { } i := t.nextNum if t.nextNum == cap(t.byNum) { - // Name table is full; copy to a new one. Don't touch the existing slice. - oldSlice := t.byNum - t.nameTable = &nameTable{byNum: make([]string, cap(oldSlice)*2), symbolTable: t} - copy(t.nameTable.byNum, oldSlice) + // Name table is full; copy to a new one. Don't touch the existing slice, as nameTable is immutable after construction. + newSlice := make([]string, cap(t.byNum)*2) + copy(newSlice, t.byNum) + t.nameTable = &nameTable{byNum: newSlice, symbolTable: t} } name = strings.Clone(name) t.byNum[i] = name @@ -112,18 +112,18 @@ func decodeVarint(data string, index int) (int, int) { if b < 0x80 { return int(b), index } - size := int(b & 0x7F) + value := int(b & 0x7F) for shift := uint(7); ; shift += 7 { // Just panic if we go of the end of data, since all Labels strings are constructed internally and // malformed data indicates a bug, or memory corruption. b := data[index] index++ - size |= int(b&0x7F) << shift + value |= int(b&0x7F) << shift if b < 0x80 { break } } - return size, index + return value, index } func decodeString(t *nameTable, data string, index int) (string, int) { @@ -304,8 +304,7 @@ func (ls Labels) BytesWithoutLabels(buf []byte, names ...string) []byte { // Copy returns a copy of the labels. func (ls Labels) Copy() Labels { - buf := append([]byte{}, ls.data...) - return Labels{syms: ls.syms, data: yoloString(buf)} + return Labels{syms: ls.syms, data: strings.Clone(ls.data)} } // Get returns the value for the label with the given name. From 55e7de04f8b60e15a4d1e3e54833da1d91c05316 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 1 Feb 2024 18:49:24 +0000 Subject: [PATCH 059/253] model/labels (stringlabels): use strings.Clone Suggestion from @colega. Signed-off-by: Bryan Boreham --- model/labels/labels_stringlabels.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index 9ac4e46503..d284cb03c0 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -188,8 +188,7 @@ func (ls Labels) BytesWithoutLabels(buf []byte, names ...string) []byte { // Copy returns a copy of the labels. func (ls Labels) Copy() Labels { - buf := append([]byte{}, ls.data...) - return Labels{data: yoloString(buf)} + return Labels{data: strings.Clone(ls.data)} } // Get returns the value for the label with the given name. From e1a741a0d7064b81e0f6e9a96bf0474610602fa7 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 26 Feb 2024 11:44:32 +0000 Subject: [PATCH 060/253] labels: update copyright dates Signed-off-by: Bryan Boreham --- model/labels/labels_dedupelabels.go | 2 +- model/labels/sharding_dedupelabels.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/model/labels/labels_dedupelabels.go b/model/labels/labels_dedupelabels.go index 2306d38d1c..0cf2eb599c 100644 --- a/model/labels/labels_dedupelabels.go +++ b/model/labels/labels_dedupelabels.go @@ -1,4 +1,4 @@ -// Copyright 2017 The Prometheus Authors +// Copyright 2024 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at diff --git a/model/labels/sharding_dedupelabels.go b/model/labels/sharding_dedupelabels.go index a4ff285123..5912724f9b 100644 --- a/model/labels/sharding_dedupelabels.go +++ b/model/labels/sharding_dedupelabels.go @@ -1,4 +1,4 @@ -// Copyright 2020 The Prometheus Authors +// Copyright 2024 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at From 195a0f5ab8d34d68631562cf8086bc2d692344d1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 26 Feb 2024 14:02:06 +0000 Subject: [PATCH 061/253] remove uneccessary space Co-authored-by: Julien Signed-off-by: Bryan Boreham --- util/annotations/annotations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/annotations/annotations.go b/util/annotations/annotations.go index c7340e4c12..16a920d57f 100644 --- a/util/annotations/annotations.go +++ b/util/annotations/annotations.go @@ -105,7 +105,7 @@ var ( InvalidQuantileWarning = fmt.Errorf("%w: quantile value should be between 0 and 1", PromQLWarning) BadBucketLabelWarning = fmt.Errorf("%w: bucket label %q is missing or has a malformed value", PromQLWarning, model.BucketLabel) - MixedFloatsHistogramsWarning = fmt.Errorf("%w: encountered a mix of histograms and floats for ", PromQLWarning) + MixedFloatsHistogramsWarning = fmt.Errorf("%w: encountered a mix of histograms and floats for", PromQLWarning) MixedClassicNativeHistogramsWarning = fmt.Errorf("%w: vector contains a mix of classic and native histograms for metric name", PromQLWarning) NativeHistogramNotCounterWarning = fmt.Errorf("%w: this native histogram metric is not a counter:", PromQLWarning) NativeHistogramNotGaugeWarning = fmt.Errorf("%w: this native histogram metric is not a gauge:", PromQLWarning) From 9fbfc9ea98683398e8566264472f7531550deb2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:03:04 +0000 Subject: [PATCH 062/253] build(deps): bump actions/setup-go from 4.1.0 to 5.0.0 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4.1.0 to 5.0.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/93397bea11091df50f3d7e59dc26a7711a8bcfbe...0c52d547c9bc32b1aa3301fd7a9cb496313a4491) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00b5949157..8705b9d72d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: 1.22.x - run: | @@ -141,7 +141,7 @@ jobs: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Install Go - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: cache: false go-version: 1.22.x diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ec6ae25c64..9f665779a5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: 1.22.x From 3fc6577ec652cb757b48359a36ecb2bb2732604a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:03:41 +0000 Subject: [PATCH 063/253] build(deps): bump the k8s-io group with 3 updates Bumps the k8s-io group with 3 updates: [k8s.io/api](https://github.com/kubernetes/api), [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) and [k8s.io/client-go](https://github.com/kubernetes/client-go). Updates `k8s.io/api` from 0.28.6 to 0.29.2 - [Commits](https://github.com/kubernetes/api/compare/v0.28.6...v0.29.2) Updates `k8s.io/apimachinery` from 0.28.6 to 0.29.2 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.28.6...v0.29.2) Updates `k8s.io/client-go` from 0.28.6 to 0.29.2 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.28.6...v0.29.2) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/apimachinery dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/client-go dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 80a26ec38e..f8c0bfa2ad 100644 --- a/go.mod +++ b/go.mod @@ -87,9 +87,9 @@ require ( google.golang.org/protobuf v1.32.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.28.6 - k8s.io/apimachinery v0.28.6 - k8s.io/client-go v0.28.6 + k8s.io/api v0.29.2 + k8s.io/apimachinery v0.29.2 + k8s.io/client-go v0.29.2 k8s.io/klog v1.0.0 k8s.io/klog/v2 v2.120.1 ) diff --git a/go.sum b/go.sum index 0b0bf4d987..c0c47233c1 100644 --- a/go.sum +++ b/go.sum @@ -614,11 +614,11 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= -github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -1262,12 +1262,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.28.6 h1:yy6u9CuIhmg55YvF/BavPBBXB+5QicB64njJXxVnzLo= -k8s.io/api v0.28.6/go.mod h1:AM6Ys6g9MY3dl/XNaNfg/GePI0FT7WBGu8efU/lirAo= -k8s.io/apimachinery v0.28.6 h1:RsTeR4z6S07srPg6XYrwXpTJVMXsjPXn0ODakMytSW0= -k8s.io/apimachinery v0.28.6/go.mod h1:QFNX/kCl/EMT2WTSz8k4WLCv2XnkOLMaL8GAVRMdpsA= -k8s.io/client-go v0.28.6 h1:Gge6ziyIdafRchfoBKcpaARuz7jfrK1R1azuwORIsQI= -k8s.io/client-go v0.28.6/go.mod h1:+nu0Yp21Oeo/cBCsprNVXB2BfJTV51lFfe5tXl2rUL8= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= +k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= From 67f13f35410b60be7ca673bcf4fbaa6bdc35b6ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:03:53 +0000 Subject: [PATCH 064/253] build(deps): bump github.com/aws/aws-sdk-go from 1.50.0 to 1.50.25 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.50.0 to 1.50.25. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.50.0...v1.50.25) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 80a26ec38e..5f9eb9367c 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/KimMachineGun/automemlimit v0.5.0 github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 - github.com/aws/aws-sdk-go v1.50.0 + github.com/aws/aws-sdk-go v1.50.25 github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 github.com/cespare/xxhash/v2 v2.2.0 github.com/dennwc/varint v1.0.0 diff --git a/go.sum b/go.sum index 0b0bf4d987..8e8b97c871 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI= -github.com/aws/aws-sdk-go v1.50.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.50.25 h1:vhiHtLYybv1Nhx3Kv18BBC6L0aPJHaG9aeEsr92W99c= +github.com/aws/aws-sdk-go v1.50.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0= From 4a0541178dea71aeac56ce4c8cf1a6927fbda323 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:04:22 +0000 Subject: [PATCH 065/253] build(deps): bump github.com/docker/docker Bumps [github.com/docker/docker](https://github.com/docker/docker) from 25.0.0+incompatible to 25.0.3+incompatible. - [Release notes](https://github.com/docker/docker/releases) - [Commits](https://github.com/docker/docker/compare/v25.0.0...v25.0.3) --- updated-dependencies: - dependency-name: github.com/docker/docker dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 80a26ec38e..ba3ddf1b2b 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 github.com/dennwc/varint v1.0.0 github.com/digitalocean/godo v1.108.0 - github.com/docker/docker v25.0.0+incompatible + github.com/docker/docker v25.0.3+incompatible github.com/edsrzf/mmap-go v1.1.0 github.com/envoyproxy/go-control-plane v0.12.0 github.com/envoyproxy/protoc-gen-validate v1.0.4 diff --git a/go.sum b/go.sum index 0b0bf4d987..84bca32e2c 100644 --- a/go.sum +++ b/go.sum @@ -151,8 +151,8 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK 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 v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= -github.com/docker/docker v25.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= +github.com/docker/docker v25.0.3+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= From 851a28203cb99589e7f90f9960163cba49f140aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:04:44 +0000 Subject: [PATCH 066/253] build(deps): bump github.com/linode/linodego from 1.27.1 to 1.29.0 Bumps [github.com/linode/linodego](https://github.com/linode/linodego) from 1.27.1 to 1.29.0. - [Release notes](https://github.com/linode/linodego/releases) - [Commits](https://github.com/linode/linodego/compare/v1.27.1...v1.29.0) --- updated-dependencies: - dependency-name: github.com/linode/linodego dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 80a26ec38e..5dc13d03e0 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/json-iterator/go v1.1.12 github.com/klauspost/compress v1.17.4 github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b - github.com/linode/linodego v1.27.1 + github.com/linode/linodego v1.29.0 github.com/miekg/dns v1.1.58 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f @@ -75,10 +75,10 @@ require ( go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 golang.org/x/exp v0.0.0-20240119083558-1b970713d09a - golang.org/x/net v0.20.0 + golang.org/x/net v0.21.0 golang.org/x/oauth2 v0.16.0 golang.org/x/sync v0.6.0 - golang.org/x/sys v0.16.0 + golang.org/x/sys v0.17.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.17.0 google.golang.org/api v0.157.0 @@ -185,9 +185,9 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect - golang.org/x/crypto v0.18.0 // indirect + golang.org/x/crypto v0.19.0 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect diff --git a/go.sum b/go.sum index 0b0bf4d987..95b6ea7599 100644 --- a/go.sum +++ b/go.sum @@ -526,8 +526,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linode/linodego v1.27.1 h1:KoQm5g2fppw8qIClJqUEL0yKH0+f+7te3Mewagb5QKE= -github.com/linode/linodego v1.27.1/go.mod h1:5oAsx+uinHtVo6U77nXXXtox7MWzUW6aEkTOKXxA9uo= +github.com/linode/linodego v1.29.0 h1:gDSQWAbKMAQX8db9FDCXHhodQPrJmLcmthjx6m+PyV4= +github.com/linode/linodego v1.29.0/go.mod h1:3k6WvCM10gillgYcnoLqIL23ST27BD9HhMsCJWb3Bpk= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -855,8 +855,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -938,8 +938,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1032,15 +1032,15 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 58f528dcbc4d2be60ee10a8495dccc82d9b06bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Naveiras?= Date: Mon, 26 Feb 2024 15:57:22 +0000 Subject: [PATCH 067/253] [docs] Update remote write queue defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update docs to reflect the default values in the `config.DefaultQueueConfig` Signed-off-by: Raúl Naveiras --- docs/configuration/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index e62d61b099..d228468655 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -3643,13 +3643,13 @@ queue_config: # samples from the WAL. It is recommended to have enough capacity in each # shard to buffer several requests to keep throughput up while processing # occasional slow remote requests. - [ capacity: | default = 2500 ] + [ capacity: | default = 10000 ] # Maximum number of shards, i.e. amount of concurrency. - [ max_shards: | default = 200 ] + [ max_shards: | default = 50 ] # Minimum number of shards, i.e. amount of concurrency. [ min_shards: | default = 1 ] # Maximum number of samples per send. - [ max_samples_per_send: | default = 500] + [ max_samples_per_send: | default = 2000] # Maximum time a sample will wait in buffer. [ batch_send_deadline: | default = 5s ] # Initial retry delay. Gets doubled for every retry. From ba6aa95222c1f10003bb8ed17f2a4bb10dfae81d Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 23 Feb 2024 17:00:20 +0000 Subject: [PATCH 068/253] refactor: metrics parsing: extract common checking code Signed-off-by: Bryan Boreham --- model/textparse/openmetricsparse_test.go | 130 +---------------------- model/textparse/promparse_test.go | 91 ++++++---------- 2 files changed, 38 insertions(+), 183 deletions(-) diff --git a/model/textparse/openmetricsparse_test.go b/model/textparse/openmetricsparse_test.go index e356beeae5..bc76a540d3 100644 --- a/model/textparse/openmetricsparse_test.go +++ b/model/textparse/openmetricsparse_test.go @@ -14,7 +14,6 @@ package textparse import ( - "errors" "io" "testing" @@ -23,7 +22,6 @@ import ( "github.com/prometheus/prometheus/model/exemplar" "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/util/testutil" ) func TestOpenMetricsParse(t *testing.T) { @@ -74,17 +72,7 @@ foo_total 17.0 1520879607.789 # {id="counter-test"} 5` int64p := func(x int64) *int64 { return &x } - exp := []struct { - lset labels.Labels - m string - t *int64 - v float64 - typ model.MetricType - help string - unit string - comment string - e *exemplar.Exemplar - }{ + exp := []expectedParse{ { m: "go_gc_duration_seconds", help: "A summary of the GC invocation durations.", @@ -248,57 +236,7 @@ foo_total 17.0 1520879607.789 # {id="counter-test"} 5` } p := NewOpenMetricsParser([]byte(input), labels.NewSymbolTable()) - i := 0 - - var res labels.Labels - - for { - et, err := p.Next() - if errors.Is(err, io.EOF) { - break - } - require.NoError(t, err) - - switch et { - case EntrySeries: - m, ts, v := p.Series() - - var e exemplar.Exemplar - p.Metric(&res) - found := p.Exemplar(&e) - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].t, ts) - require.Equal(t, exp[i].v, v) - testutil.RequireEqual(t, exp[i].lset, res) - if exp[i].e == nil { - require.False(t, found) - } else { - require.True(t, found) - testutil.RequireEqual(t, *exp[i].e, e) - } - - case EntryType: - m, typ := p.Type() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].typ, typ) - - case EntryHelp: - m, h := p.Help() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].help, string(h)) - - case EntryUnit: - m, u := p.Unit() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].unit, string(u)) - - case EntryComment: - require.Equal(t, exp[i].comment, string(p.Comment())) - } - - i++ - } - require.Len(t, exp, i) + checkParseResults(t, p, exp) } func TestUTF8OpenMetricsParse(t *testing.T) { @@ -322,17 +260,7 @@ func TestUTF8OpenMetricsParse(t *testing.T) { input += "\n# EOF\n" - exp := []struct { - lset labels.Labels - m string - t *int64 - v float64 - typ model.MetricType - help string - unit string - comment string - e *exemplar.Exemplar - }{ + exp := []expectedParse{ { m: "go.gc_duration_seconds", help: "A summary of the GC invocation durations.", @@ -379,57 +307,7 @@ choices}`, "strange©™\n'quoted' \"name\"", "6"), } p := NewOpenMetricsParser([]byte(input), labels.NewSymbolTable()) - i := 0 - - var res labels.Labels - - for { - et, err := p.Next() - if errors.Is(err, io.EOF) { - break - } - require.NoError(t, err) - - switch et { - case EntrySeries: - m, ts, v := p.Series() - - var e exemplar.Exemplar - p.Metric(&res) - found := p.Exemplar(&e) - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].t, ts) - require.Equal(t, exp[i].v, v) - testutil.RequireEqual(t, exp[i].lset, res) - if exp[i].e == nil { - require.False(t, found) - } else { - require.True(t, found) - require.Equal(t, *exp[i].e, e) - } - - case EntryType: - m, typ := p.Type() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].typ, typ) - - case EntryHelp: - m, h := p.Help() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].help, string(h)) - - case EntryUnit: - m, u := p.Unit() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].unit, string(u)) - - case EntryComment: - require.Equal(t, exp[i].comment, string(p.Comment())) - } - - i++ - } - require.Len(t, exp, i) + checkParseResults(t, p, exp) } func TestOpenMetricsParseErrors(t *testing.T) { diff --git a/model/textparse/promparse_test.go b/model/textparse/promparse_test.go index 4ec8c9b9cd..204ea7d036 100644 --- a/model/textparse/promparse_test.go +++ b/model/textparse/promparse_test.go @@ -26,10 +26,23 @@ import ( "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/exemplar" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/util/testutil" ) +type expectedParse struct { + lset labels.Labels + m string + t *int64 + v float64 + typ model.MetricType + help string + unit string + comment string + e *exemplar.Exemplar +} + func TestPromParse(t *testing.T) { input := `# HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary @@ -63,15 +76,7 @@ testmetric{label="\"bar\""} 1` int64p := func(x int64) *int64 { return &x } - exp := []struct { - lset labels.Labels - m string - t *int64 - v float64 - typ model.MetricType - help string - comment string - }{ + exp := []expectedParse{ { m: "go_gc_duration_seconds", help: "A summary of the GC invocation durations.", @@ -179,6 +184,10 @@ testmetric{label="\"bar\""} 1` } p := NewPromParser([]byte(input), labels.NewSymbolTable()) + checkParseResults(t, p, exp) +} + +func checkParseResults(t *testing.T, p Parser, exp []expectedParse) { i := 0 var res labels.Labels @@ -201,6 +210,15 @@ testmetric{label="\"bar\""} 1` require.Equal(t, exp[i].v, v) testutil.RequireEqual(t, exp[i].lset, res) + var e exemplar.Exemplar + found := p.Exemplar(&e) + if exp[i].e == nil { + require.False(t, found) + } else { + require.True(t, found) + testutil.RequireEqual(t, *exp[i].e, e) + } + case EntryType: m, typ := p.Type() require.Equal(t, exp[i].m, string(m)) @@ -211,6 +229,11 @@ testmetric{label="\"bar\""} 1` require.Equal(t, exp[i].m, string(m)) require.Equal(t, exp[i].help, string(h)) + case EntryUnit: + m, u := p.Unit() + require.Equal(t, exp[i].m, string(m)) + require.Equal(t, exp[i].unit, string(u)) + case EntryComment: require.Equal(t, exp[i].comment, string(p.Comment())) } @@ -241,15 +264,7 @@ func TestUTF8PromParse(t *testing.T) { {"go.gc_duration_seconds_count"} 99 {"Heizölrückstoßabdämpfung 10€ metric with \"interesting\" {character\nchoices}","strange©™\n'quoted' \"name\""="6"} 10.0` - exp := []struct { - lset labels.Labels - m string - t *int64 - v float64 - typ model.MetricType - help string - comment string - }{ + exp := []expectedParse{ { m: "go.gc_duration_seconds", help: "A summary of the GC invocation durations.", @@ -305,45 +320,7 @@ choices}`, "strange©™\n'quoted' \"name\"", "6"), } p := NewPromParser([]byte(input), labels.NewSymbolTable()) - i := 0 - - var res labels.Labels - - for { - et, err := p.Next() - if errors.Is(err, io.EOF) { - break - } - require.NoError(t, err) - - switch et { - case EntrySeries: - m, ts, v := p.Series() - - p.Metric(&res) - - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].t, ts) - require.Equal(t, exp[i].v, v) - testutil.RequireEqual(t, exp[i].lset, res) - - case EntryType: - m, typ := p.Type() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].typ, typ) - - case EntryHelp: - m, h := p.Help() - require.Equal(t, exp[i].m, string(m)) - require.Equal(t, exp[i].help, string(h)) - - case EntryComment: - require.Equal(t, exp[i].comment, string(p.Comment())) - } - - i++ - } - require.Len(t, exp, i) + checkParseResults(t, p, exp) } func TestPromParseErrors(t *testing.T) { From 1a8ea78207af44d2e26c53a55341687b859340d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Thu, 16 Nov 2023 13:16:47 +0000 Subject: [PATCH 069/253] Fix BenchmarkScrapeLoopAppendOM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenMetrics requires EOF comment at the end of metrics body, but the makeTestMetrics() function doesn't append it. This means this benchmark tests a response with errors but I don't think that was the intention. Signed-off-by: Łukasz Mierzwa --- scrape/scrape_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index bcaeb460e2..e37d091aec 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -1068,6 +1068,7 @@ func makeTestMetrics(n int) []byte { fmt.Fprintf(&sb, "# HELP metric_a help text\n") fmt.Fprintf(&sb, "metric_a{foo=\"%d\",bar=\"%d\"} 1\n", i, i*100) } + fmt.Fprintf(&sb, "# EOF\n") return sb.Bytes() } From 50c81bed86327fa4c954d5cab35142f84bfce532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Thu, 16 Nov 2023 13:22:28 +0000 Subject: [PATCH 070/253] Check for duplicated series on a scrape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Prometheus scrapes a target and it sees the same time series repeated multiple times it currently silently ignores that. This change adds a test for that and fixes the scrape loop so that: - Only first sample for each unique time series is appended - Duplicated samples increment the prometheus_target_scrapes_sample_duplicate_timestamp_total metric This allows one to identify such scrape jobs and targets. Benchmark results: ``` name old time/op new time/op delta ScrapeLoopAppend-8 64.8µs ± 2% 71.1µs ±20% +9.75% (p=0.000 n=10+10) ScrapeLoopAppendOM-8 64.2µs ± 1% 68.5µs ± 7% +6.71% (p=0.000 n=9+10) TargetsFromGroup/1_targets-8 14.2µs ± 1% 14.5µs ± 1% +1.99% (p=0.000 n=10+10) TargetsFromGroup/10_targets-8 149µs ± 1% 152µs ± 1% +2.05% (p=0.000 n=9+10) TargetsFromGroup/100_targets-8 1.49ms ± 4% 1.48ms ± 1% ~ (p=0.796 n=10+10) name old alloc/op new alloc/op delta ScrapeLoopAppend-8 19.9kB ± 1% 17.8kB ± 3% -10.23% (p=0.000 n=8+10) ScrapeLoopAppendOM-8 19.9kB ± 1% 18.3kB ±10% -8.14% (p=0.001 n=9+10) TargetsFromGroup/1_targets-8 2.43kB ± 0% 2.43kB ± 0% -0.15% (p=0.045 n=10+10) TargetsFromGroup/10_targets-8 24.3kB ± 0% 24.3kB ± 0% ~ (p=0.083 n=10+9) TargetsFromGroup/100_targets-8 243kB ± 0% 243kB ± 0% ~ (p=0.720 n=9+10) name old allocs/op new allocs/op delta ScrapeLoopAppend-8 9.00 ± 0% 9.00 ± 0% ~ (all equal) ScrapeLoopAppendOM-8 10.0 ± 0% 10.0 ± 0% ~ (all equal) TargetsFromGroup/1_targets-8 40.0 ± 0% 40.0 ± 0% ~ (all equal) TargetsFromGroup/10_targets-8 400 ± 0% 400 ± 0% ~ (all equal) TargetsFromGroup/100_targets-8 4.00k ± 0% 4.00k ± 0% ~ (all equal) ``` Signed-off-by: Łukasz Mierzwa --- scrape/scrape.go | 53 +++++++++++++++++++++++++------------------ scrape/scrape_test.go | 28 +++++++++++++++++++++++ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index aa2d5538b1..9bff47eebc 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -1512,13 +1512,13 @@ func (sl *scrapeLoop) append(app storage.Appender, b []byte, contentType string, loop: for { var ( - et textparse.Entry - sampleAdded, isHistogram bool - met []byte - parsedTimestamp *int64 - val float64 - h *histogram.Histogram - fh *histogram.FloatHistogram + et textparse.Entry + sampleAdded, isHistogram, seriesAlreadyScraped bool + met []byte + parsedTimestamp *int64 + val float64 + h *histogram.Histogram + fh *histogram.FloatHistogram ) if et, err = p.Next(); err != nil { if errors.Is(err, io.EOF) { @@ -1573,6 +1573,7 @@ loop: if ok { ref = ce.ref lset = ce.lset + hash = ce.hash // Update metadata only if it changed in the current iteration. updateMetadata(lset, false) @@ -1609,24 +1610,30 @@ loop: updateMetadata(lset, true) } - if ctMs := p.CreatedTimestamp(); sl.enableCTZeroIngestion && ctMs != nil { - ref, err = app.AppendCTZeroSample(ref, lset, t, *ctMs) - if err != nil && !errors.Is(err, storage.ErrOutOfOrderCT) { // OOO is a common case, ignoring completely for now. - // CT is an experimental feature. For now, we don't need to fail the - // scrape on errors updating the created timestamp, log debug. - level.Debug(sl.l).Log("msg", "Error when appending CT in scrape loop", "series", string(met), "ct", *ctMs, "t", t, "err", err) + _, seriesAlreadyScraped = sl.cache.seriesCur[hash] + if seriesAlreadyScraped { + err = storage.ErrDuplicateSampleForTimestamp + } else { + if ctMs := p.CreatedTimestamp(); sl.enableCTZeroIngestion && ctMs != nil { + ref, err = app.AppendCTZeroSample(ref, lset, t, *ctMs) + if err != nil && !errors.Is(err, storage.ErrOutOfOrderCT) { // OOO is a common case, ignoring completely for now. + // CT is an experimental feature. For now, we don't need to fail the + // scrape on errors updating the created timestamp, log debug. + level.Debug(sl.l).Log("msg", "Error when appending CT in scrape loop", "series", string(met), "ct", *ctMs, "t", t, "err", err) + } + } + + if isHistogram { + if h != nil { + ref, err = app.AppendHistogram(ref, lset, t, h, nil) + } else { + ref, err = app.AppendHistogram(ref, lset, t, nil, fh) + } + } else { + ref, err = app.Append(ref, lset, t, val) } } - if isHistogram { - if h != nil { - ref, err = app.AppendHistogram(ref, lset, t, h, nil) - } else { - ref, err = app.AppendHistogram(ref, lset, t, nil, fh) - } - } else { - ref, err = app.Append(ref, lset, t, val) - } sampleAdded, err = sl.checkAddError(ce, met, parsedTimestamp, err, &sampleLimitErr, &bucketLimitErr, &appErrs) if err != nil { if !errors.Is(err, storage.ErrNotFound) { @@ -1648,6 +1655,8 @@ loop: // Increment added even if there's an error so we correctly report the // number of samples remaining after relabeling. + // We still report duplicated samples here since this number should be the exact number + // of time series exposed on a scrape after relabelling. added++ exemplars = exemplars[:0] // Reset and reuse the exemplar slice. for hasExemplar := p.Exemplar(&e); hasExemplar; hasExemplar = p.Exemplar(&e) { diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index e37d091aec..4732fbe0d0 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -3600,3 +3600,31 @@ func BenchmarkTargetScraperGzip(b *testing.B) { }) } } + +// When a scrape contains multiple instances for the same time series we should increment +// prometheus_target_scrapes_sample_duplicate_timestamp_total metric. +func TestScrapeLoopSeriesAddedDuplicates(t *testing.T) { + ctx, sl := simpleTestScrapeLoop(t) + + slApp := sl.appender(ctx) + total, added, seriesAdded, err := sl.append(slApp, []byte("test_metric 1\ntest_metric 2\ntest_metric 3\n"), "", time.Time{}) + require.NoError(t, err) + require.NoError(t, slApp.Commit()) + require.Equal(t, 3, total) + require.Equal(t, 3, added) + require.Equal(t, 1, seriesAdded) + + slApp = sl.appender(ctx) + total, added, seriesAdded, err = sl.append(slApp, []byte("test_metric 1\ntest_metric 1\ntest_metric 1\n"), "", time.Time{}) + require.NoError(t, err) + require.NoError(t, slApp.Commit()) + require.Equal(t, 3, total) + require.Equal(t, 3, added) + require.Equal(t, 0, seriesAdded) + + metric := dto.Metric{} + err = sl.metrics.targetScrapeSampleDuplicate.Write(&metric) + require.NoError(t, err) + value := metric.GetCounter().GetValue() + require.Equal(t, 4.0, value) +} From 55dcaab41bedc995460927a2c4f3e977d23c374c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Thu, 16 Nov 2023 14:35:44 +0000 Subject: [PATCH 071/253] Fix TestScrapeLoopDiscardDuplicateLabels test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test calls Rollback() which is normally called from within append code. Doing so means that staleness tracking data is outdated and need to by cycled manually. Signed-off-by: Łukasz Mierzwa --- scrape/scrape_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index 4732fbe0d0..dbe9f0bb29 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -2636,6 +2636,9 @@ func TestScrapeLoopDiscardDuplicateLabels(t *testing.T) { _, _, _, err := sl.append(slApp, []byte("test_metric{le=\"500\"} 1\ntest_metric{le=\"600\",le=\"700\"} 1\n"), "", time.Time{}) require.Error(t, err) require.NoError(t, slApp.Rollback()) + // We need to cycle staleness cache maps after a manual rollback. Otherwise they will have old entries in them, + // which would cause ErrDuplicateSampleForTimestamp errors on the next append. + sl.cache.iterDone(true) q, err := s.Querier(time.Time{}.UnixNano(), 0) require.NoError(t, err) From 21f8b35f5bdef290c9e1254ab2e0b86d8f68237a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 28 Nov 2023 17:42:29 +0000 Subject: [PATCH 072/253] Move staleness tracking out of checkAddError() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This call bloats checkAddError signature and logic, we can and should call it from the main scrape logic. Signed-off-by: Łukasz Mierzwa --- scrape/scrape.go | 13 ++++++++----- scrape/scrape_test.go | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index 9bff47eebc..701aa609f3 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -1634,7 +1634,13 @@ loop: } } - sampleAdded, err = sl.checkAddError(ce, met, parsedTimestamp, err, &sampleLimitErr, &bucketLimitErr, &appErrs) + if err == nil { + if (parsedTimestamp == nil || sl.trackTimestampsStaleness) && ce != nil { + sl.cache.trackStaleness(ce.hash, ce.lset) + } + } + + sampleAdded, err = sl.checkAddError(met, err, &sampleLimitErr, &bucketLimitErr, &appErrs) if err != nil { if !errors.Is(err, storage.ErrNotFound) { level.Debug(sl.l).Log("msg", "Unexpected error", "series", string(met), "err", err) @@ -1751,12 +1757,9 @@ loop: // Adds samples to the appender, checking the error, and then returns the # of samples added, // whether the caller should continue to process more samples, and any sample or bucket limit errors. -func (sl *scrapeLoop) checkAddError(ce *cacheEntry, met []byte, tp *int64, err error, sampleLimitErr, bucketLimitErr *error, appErrs *appendErrors) (bool, error) { +func (sl *scrapeLoop) checkAddError(met []byte, err error, sampleLimitErr, bucketLimitErr *error, appErrs *appendErrors) (bool, error) { switch { case err == nil: - if (tp == nil || sl.trackTimestampsStaleness) && ce != nil { - sl.cache.trackStaleness(ce.hash, ce.lset) - } return true, nil case errors.Is(err, storage.ErrNotFound): return false, storage.ErrNotFound diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index dbe9f0bb29..0dfca538d8 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -2975,7 +2975,7 @@ func TestReuseCacheRace(t *testing.T) { func TestCheckAddError(t *testing.T) { var appErrs appendErrors sl := scrapeLoop{l: log.NewNopLogger(), metrics: newTestScrapeMetrics(t)} - sl.checkAddError(nil, nil, nil, storage.ErrOutOfOrderSample, nil, nil, &appErrs) + sl.checkAddError(nil, storage.ErrOutOfOrderSample, nil, nil, &appErrs) require.Equal(t, 1, appErrs.numOutOfOrder) } From c013a3c1b572fb7a11683c49590822c46d91a917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 27 Feb 2024 12:09:32 +0000 Subject: [PATCH 073/253] Check of duplicated samples directly in scrapeCache.get() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid extra map lookup by hooking check into cache get. ``` goos: linux goarch: amd64 pkg: github.com/prometheus/prometheus/scrape cpu: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz │ main.txt │ new.txt │ │ sec/op │ sec/op vs base │ ScrapeLoopAppend-8 66.72µ ± 0% 66.89µ ± 0% ~ (p=0.879 n=50) ScrapeLoopAppendOM-8 66.61µ ± 0% 66.89µ ± 1% ~ (p=0.115 n=50) geomean 66.66µ 66.89µ +0.34% │ main.txt │ new.txt │ │ B/op │ B/op vs base │ ScrapeLoopAppend-8 20.17Ki ± 1% 20.12Ki ± 1% ~ (p=0.343 n=50) ScrapeLoopAppendOM-8 20.38Ki ± 10% 17.99Ki ± 2% -11.69% (p=0.017 n=50) geomean 20.27Ki 19.03Ki -6.14% │ main.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ ScrapeLoopAppend-8 11.00 ± 0% 11.00 ± 0% ~ (p=1.000 n=50) ¹ ScrapeLoopAppendOM-8 12.00 ± 0% 12.00 ± 0% ~ (p=1.000 n=50) ¹ geomean 11.49 11.49 +0.00% ¹ all samples are equal ``` Signed-off-by: Łukasz Mierzwa --- scrape/scrape.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index 701aa609f3..6be858c681 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -954,13 +954,14 @@ func (c *scrapeCache) iterDone(flushCache bool) { } } -func (c *scrapeCache) get(met []byte) (*cacheEntry, bool) { +func (c *scrapeCache) get(met []byte) (*cacheEntry, bool, bool) { e, ok := c.series[string(met)] if !ok { - return nil, false + return nil, false, false } + alreadyScraped := e.lastIter == c.iter e.lastIter = c.iter - return e, true + return e, true, alreadyScraped } func (c *scrapeCache) addRef(met []byte, ref storage.SeriesRef, lset labels.Labels, hash uint64) { @@ -1512,13 +1513,13 @@ func (sl *scrapeLoop) append(app storage.Appender, b []byte, contentType string, loop: for { var ( - et textparse.Entry - sampleAdded, isHistogram, seriesAlreadyScraped bool - met []byte - parsedTimestamp *int64 - val float64 - h *histogram.Histogram - fh *histogram.FloatHistogram + et textparse.Entry + sampleAdded, isHistogram bool + met []byte + parsedTimestamp *int64 + val float64 + h *histogram.Histogram + fh *histogram.FloatHistogram ) if et, err = p.Next(); err != nil { if errors.Is(err, io.EOF) { @@ -1564,7 +1565,7 @@ loop: if sl.cache.getDropped(met) { continue } - ce, ok := sl.cache.get(met) + ce, ok, seriesAlreadyScraped := sl.cache.get(met) var ( ref storage.SeriesRef hash uint64 @@ -1610,7 +1611,6 @@ loop: updateMetadata(lset, true) } - _, seriesAlreadyScraped = sl.cache.seriesCur[hash] if seriesAlreadyScraped { err = storage.ErrDuplicateSampleForTimestamp } else { @@ -1882,7 +1882,7 @@ func (sl *scrapeLoop) reportStale(app storage.Appender, start time.Time) (err er } func (sl *scrapeLoop) addReportSample(app storage.Appender, s []byte, t int64, v float64, b *labels.Builder) error { - ce, ok := sl.cache.get(s) + ce, ok, _ := sl.cache.get(s) var ref storage.SeriesRef var lset labels.Labels if ok { From befab52a147f9ff513e76ee2a591b6108fc5f090 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 27 Feb 2024 16:58:56 +0000 Subject: [PATCH 074/253] Move v2.51 release date up The previous release was forked on 25th Jan, so we should aim about 6 weeks after that. Signed-off-by: Bryan Boreham --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 2dfa9cc451..c2f98ab2ce 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -55,7 +55,7 @@ Release cadence of first pre-releases being cut is 6 weeks. | v2.48 | 2023-10-04 | Levi Harrison (GitHub: @LeviHarrison) | | v2.49 | 2023-12-05 | Bartek Plotka (GitHub: @bwplotka) | | v2.50 | 2024-01-16 | Augustin Husson (GitHub: @nexucis) | -| v2.51 | 2024-04-01 | Bryan Boreham (GitHub: @bboreham) | +| v2.51 | 2024-03-07 | Bryan Boreham (GitHub: @bboreham) | If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice. From ac51a8024cf6a8134b9345673f8a685846c6a6fc Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 27 Feb 2024 15:47:47 -0500 Subject: [PATCH 075/253] tests(utf8): confirm that other quote marks are handled correctly in promql Signed-off-by: Owen Williams --- promql/parser/parse_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index 2d5f59da0a..bd696ae969 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -1731,6 +1731,34 @@ var testExpr = []struct { }, }, }, + { + input: `{'foo\'bar', 'a\\dos\\path'='boo\\urns'}`, + expected: &VectorSelector{ + // When a metric is named inside the braces, the Name field is not set. + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, `foo'bar`), + MustLabelMatcher(labels.MatchEqual, `a\dos\path`, `boo\urns`), + }, + PosRange: posrange.PositionRange{ + Start: 0, + End: 40, + }, + }, + }, + { + input: `{'foo\'bar', ` + "`" + `a\dos\path` + "`" + `="boo"}`, + expected: &VectorSelector{ + // When a metric is named inside the braces, the Name field is not set. + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, `foo'bar`), + MustLabelMatcher(labels.MatchEqual, `a\dos\path`, "boo"), + }, + PosRange: posrange.PositionRange{ + Start: 0, + End: 32, + }, + }, + }, { input: `{"foo", a="bc"}`, expected: &VectorSelector{ From 9c67344a5491b6e3e50de36639604731df7bae0e Mon Sep 17 00:00:00 2001 From: machine424 Date: Fri, 16 Feb 2024 14:21:10 +0100 Subject: [PATCH 076/253] chore(ci): Run all tests on the oldest golang version Run test_mixins on the latest golang version Signed-off-by: machine424 --- .github/workflows/ci.yml | 29 ++++++++++++++--------------- .promu.yml | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00b5949157..94590d4171 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,9 +8,9 @@ jobs: test_go: name: Go tests runs-on: ubuntu-latest - # Whenever the Go version is updated here, .promu.yml - # should also be updated. container: + # Whenever the Go version is updated here, .promu.yml + # should also be updated. image: quay.io/prometheus/golang-builder:1.22-base steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -27,6 +27,17 @@ jobs: with: version: "3.15.8" + test_go_oldest: + name: Go tests with previous Go version + runs-on: ubuntu-latest + container: + # The go version in this image should be N-1 wrt test_go. + image: quay.io/prometheus/golang-builder:1.21-base + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - run: make build + - run: make test GO_ONLY=1 + test_ui: name: UI tests runs-on: ubuntu-latest @@ -62,25 +73,13 @@ jobs: go test $TestTargets -vet=off -v shell: powershell - test_golang_oldest: - name: Go tests with previous Go version - runs-on: ubuntu-latest - # The go verson in this image should be N-1 wrt test_go. - container: - image: quay.io/prometheus/golang-builder:1.21-base - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - run: make build - - run: go test ./tsdb/... - - run: go test ./tsdb/ -test.tsdb-isolation=false - test_mixins: name: Mixins tests runs-on: ubuntu-latest # Whenever the Go version is updated here, .promu.yml # should also be updated. container: - image: quay.io/prometheus/golang-builder:1.21-base + image: quay.io/prometheus/golang-builder:1.22-base steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - run: go install ./cmd/promtool/. diff --git a/.promu.yml b/.promu.yml index d8cdc4209a..0aa51d6d31 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # Whenever the Go version is updated here, - # .circle/config.yml should also be updated. + # .github/workflows should also be updated. version: 1.22 repository: path: github.com/prometheus/prometheus From f477e0539a4f196759cc9aa5c79698c758ca04b9 Mon Sep 17 00:00:00 2001 From: machine424 Date: Mon, 15 Jan 2024 17:24:46 +0100 Subject: [PATCH 077/253] Move from golang.org/x/exp/slices into slices now that we only support Go >= 1.21 Prevent adding back golang.org/x/exp/slices. Signed-off-by: machine424 --- .golangci.yml | 2 ++ cmd/promtool/tsdb.go | 2 +- go.mod | 2 +- model/histogram/generic_test.go | 2 +- model/histogram/histogram.go | 3 +-- model/labels/labels.go | 2 +- model/labels/labels_common.go | 2 +- model/labels/labels_dedupelabels.go | 2 +- model/labels/labels_stringlabels.go | 2 +- promql/engine.go | 2 +- promql/functions.go | 2 +- promql/quantile.go | 3 +-- rules/group.go | 2 +- rules/manager.go | 2 +- scrape/scrape.go | 2 +- storage/merge.go | 3 +-- storage/remote/codec.go | 2 +- storage/remote/read_handler.go | 2 +- tsdb/block.go | 2 +- tsdb/chunks/head_chunks.go | 2 +- tsdb/compact.go | 2 +- tsdb/db.go | 2 +- tsdb/exemplar.go | 2 +- tsdb/head_read.go | 2 +- tsdb/index/index.go | 3 +-- tsdb/index/postings.go | 2 +- tsdb/index/postingsstats.go | 3 +-- tsdb/ooo_head_read.go | 2 +- tsdb/ooo_head_read_test.go | 2 +- tsdb/querier.go | 2 +- tsdb/wlog/checkpoint.go | 2 +- tsdb/wlog/watcher.go | 2 +- tsdb/wlog/wlog.go | 2 +- util/stats/timer.go | 3 +-- web/api/v1/api.go | 2 +- web/federate.go | 2 +- 36 files changed, 37 insertions(+), 41 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index cc290b3343..2eeb6c1c8f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -64,6 +64,8 @@ linters-settings: desc: "Use github.com/klauspost/compress instead of gzip" - pkg: "zlib" desc: "Use github.com/klauspost/compress instead of zlib" + - pkg: "golang.org/x/exp/slices" + desc: "Use 'slices' instead." errcheck: exclude-functions: # Don't flag lines such as "io.Copy(io.Discard, resp.Body)". diff --git a/cmd/promtool/tsdb.go b/cmd/promtool/tsdb.go index 4bba8421c2..8692a3fec9 100644 --- a/cmd/promtool/tsdb.go +++ b/cmd/promtool/tsdb.go @@ -23,6 +23,7 @@ import ( "path/filepath" "runtime" "runtime/pprof" + "slices" "strconv" "strings" "sync" @@ -31,7 +32,6 @@ import ( "github.com/alecthomas/units" "github.com/go-kit/log" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql/parser" diff --git a/go.mod b/go.mod index aa3edbbe51..f2d3954428 100644 --- a/go.mod +++ b/go.mod @@ -74,7 +74,7 @@ require ( go.uber.org/automaxprocs v1.5.3 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/net v0.21.0 golang.org/x/oauth2 v0.16.0 golang.org/x/sync v0.6.0 diff --git a/model/histogram/generic_test.go b/model/histogram/generic_test.go index 6a22b6f193..b4d6585a8b 100644 --- a/model/histogram/generic_test.go +++ b/model/histogram/generic_test.go @@ -15,10 +15,10 @@ package histogram import ( "math" + "slices" "testing" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" ) func TestGetBound(t *testing.T) { diff --git a/model/histogram/histogram.go b/model/histogram/histogram.go index d40adeb620..d94cf98fa6 100644 --- a/model/histogram/histogram.go +++ b/model/histogram/histogram.go @@ -16,9 +16,8 @@ package histogram import ( "fmt" "math" + "slices" "strings" - - "golang.org/x/exp/slices" ) // CounterResetHint contains the known information about a counter reset, diff --git a/model/labels/labels.go b/model/labels/labels.go index a482d2a835..e998248269 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -17,10 +17,10 @@ package labels import ( "bytes" + "slices" "strings" "github.com/cespare/xxhash/v2" - "golang.org/x/exp/slices" ) // Labels is a sorted set of labels. Order has to be guaranteed upon diff --git a/model/labels/labels_common.go b/model/labels/labels_common.go index e51001e7d7..4c4a87e872 100644 --- a/model/labels/labels_common.go +++ b/model/labels/labels_common.go @@ -16,10 +16,10 @@ package labels import ( "bytes" "encoding/json" + "slices" "strconv" "github.com/prometheus/common/model" - "golang.org/x/exp/slices" ) const ( diff --git a/model/labels/labels_dedupelabels.go b/model/labels/labels_dedupelabels.go index 0cf2eb599c..dfc74aa3a3 100644 --- a/model/labels/labels_dedupelabels.go +++ b/model/labels/labels_dedupelabels.go @@ -17,12 +17,12 @@ package labels import ( "bytes" + "slices" "strings" "sync" "unsafe" "github.com/cespare/xxhash/v2" - "golang.org/x/exp/slices" ) // Labels is implemented by a SymbolTable and string holding name/value diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index d284cb03c0..2e718c2b1f 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -17,11 +17,11 @@ package labels import ( "reflect" + "slices" "strings" "unsafe" "github.com/cespare/xxhash/v2" - "golang.org/x/exp/slices" ) // Labels is implemented by a single flat string holding name/value pairs. diff --git a/promql/engine.go b/promql/engine.go index cd955ff5eb..edc90d21a2 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -22,6 +22,7 @@ import ( "math" "reflect" "runtime" + "slices" "sort" "strconv" "strings" @@ -36,7 +37,6 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" diff --git a/promql/functions.go b/promql/functions.go index fe1a5644ec..98318fdab9 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -16,6 +16,7 @@ package promql import ( "fmt" "math" + "slices" "sort" "strconv" "strings" @@ -24,7 +25,6 @@ import ( "github.com/facette/natsort" "github.com/grafana/regexp" "github.com/prometheus/common/model" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" diff --git a/promql/quantile.go b/promql/quantile.go index f62519f5b9..6a225afb11 100644 --- a/promql/quantile.go +++ b/promql/quantile.go @@ -15,10 +15,9 @@ package promql import ( "math" + "slices" "sort" - "golang.org/x/exp/slices" - "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" ) diff --git a/rules/group.go b/rules/group.go index bc59bf8598..b8694a255e 100644 --- a/rules/group.go +++ b/rules/group.go @@ -17,12 +17,12 @@ import ( "context" "errors" "math" + "slices" "strings" "sync" "time" "go.uber.org/atomic" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/promql/parser" diff --git a/rules/manager.go b/rules/manager.go index 66dcdcf2e4..e87d55b1e1 100644 --- a/rules/manager.go +++ b/rules/manager.go @@ -18,6 +18,7 @@ import ( "errors" "fmt" "net/url" + "slices" "strings" "sync" "time" @@ -25,7 +26,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "golang.org/x/sync/semaphore" "github.com/prometheus/prometheus/model/labels" diff --git a/scrape/scrape.go b/scrape/scrape.go index aa2d5538b1..6ac3c551c1 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -23,6 +23,7 @@ import ( "math" "net/http" "reflect" + "slices" "strconv" "strings" "sync" @@ -34,7 +35,6 @@ import ( config_util "github.com/prometheus/common/config" "github.com/prometheus/common/model" "github.com/prometheus/common/version" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/discovery/targetgroup" diff --git a/storage/merge.go b/storage/merge.go index 38897449b5..8855600220 100644 --- a/storage/merge.go +++ b/storage/merge.go @@ -19,10 +19,9 @@ import ( "context" "fmt" "math" + "slices" "sync" - "golang.org/x/exp/slices" - "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/tsdb/chunkenc" diff --git a/storage/remote/codec.go b/storage/remote/codec.go index d0d2dd1d9e..1228b23f5c 100644 --- a/storage/remote/codec.go +++ b/storage/remote/codec.go @@ -20,6 +20,7 @@ import ( "io" "math" "net/http" + "slices" "sort" "strings" "sync" @@ -28,7 +29,6 @@ import ( "github.com/golang/snappy" "github.com/prometheus/common/model" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/exemplar" "github.com/prometheus/prometheus/model/histogram" diff --git a/storage/remote/read_handler.go b/storage/remote/read_handler.go index 3a99e3360c..ffc64c9c3f 100644 --- a/storage/remote/read_handler.go +++ b/storage/remote/read_handler.go @@ -17,13 +17,13 @@ import ( "context" "errors" "net/http" + "slices" "strings" "sync" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/model/labels" diff --git a/tsdb/block.go b/tsdb/block.go index 7833e187ff..abd223e4ad 100644 --- a/tsdb/block.go +++ b/tsdb/block.go @@ -22,12 +22,12 @@ import ( "io" "os" "path/filepath" + "slices" "sync" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/oklog/ulid" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" diff --git a/tsdb/chunks/head_chunks.go b/tsdb/chunks/head_chunks.go index 12c3e7b900..5ba5381320 100644 --- a/tsdb/chunks/head_chunks.go +++ b/tsdb/chunks/head_chunks.go @@ -23,13 +23,13 @@ import ( "io" "os" "path/filepath" + "slices" "strconv" "sync" "github.com/dennwc/varint" "github.com/prometheus/client_golang/prometheus" "go.uber.org/atomic" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/tsdb/chunkenc" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" diff --git a/tsdb/compact.go b/tsdb/compact.go index efe3306c7c..b21ac4d317 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -21,13 +21,13 @@ import ( "io" "os" "path/filepath" + "slices" "time" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/oklog/ulid" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/tsdb/chunkenc" diff --git a/tsdb/db.go b/tsdb/db.go index e9265c55e5..f29315517b 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -23,6 +23,7 @@ import ( "math" "os" "path/filepath" + "slices" "strconv" "strings" "sync" @@ -33,7 +34,6 @@ import ( "github.com/oklog/ulid" "github.com/prometheus/client_golang/prometheus" "go.uber.org/atomic" - "golang.org/x/exp/slices" "golang.org/x/sync/errgroup" "github.com/prometheus/prometheus/config" diff --git a/tsdb/exemplar.go b/tsdb/exemplar.go index 805de70da3..3dd784c623 100644 --- a/tsdb/exemplar.go +++ b/tsdb/exemplar.go @@ -16,11 +16,11 @@ package tsdb import ( "context" "errors" + "slices" "sync" "unicode/utf8" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/model/exemplar" diff --git a/tsdb/head_read.go b/tsdb/head_read.go index 457d3e1c47..10a4623924 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -18,10 +18,10 @@ import ( "errors" "fmt" "math" + "slices" "sync" "github.com/go-kit/log/level" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 4241ba8283..7aae4c2645 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -25,11 +25,10 @@ import ( "math" "os" "path/filepath" + "slices" "sort" "unsafe" - "golang.org/x/exp/slices" - "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" "github.com/prometheus/prometheus/tsdb/chunks" diff --git a/tsdb/index/postings.go b/tsdb/index/postings.go index 222a8b0d6f..61a5560ee4 100644 --- a/tsdb/index/postings.go +++ b/tsdb/index/postings.go @@ -20,12 +20,12 @@ import ( "fmt" "math" "runtime" + "slices" "sort" "strings" "sync" "github.com/bboreham/go-loser" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" diff --git a/tsdb/index/postingsstats.go b/tsdb/index/postingsstats.go index 0ad4e08575..f9ee640ff5 100644 --- a/tsdb/index/postingsstats.go +++ b/tsdb/index/postingsstats.go @@ -15,8 +15,7 @@ package index import ( "math" - - "golang.org/x/exp/slices" + "slices" ) // Stat holds values for a single cardinality statistic. diff --git a/tsdb/ooo_head_read.go b/tsdb/ooo_head_read.go index 3a801bf98b..c9fe5cd580 100644 --- a/tsdb/ooo_head_read.go +++ b/tsdb/ooo_head_read.go @@ -17,9 +17,9 @@ import ( "context" "errors" "math" + "slices" "github.com/oklog/ulid" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" diff --git a/tsdb/ooo_head_read_test.go b/tsdb/ooo_head_read_test.go index 36289056b8..1716f29b55 100644 --- a/tsdb/ooo_head_read_test.go +++ b/tsdb/ooo_head_read_test.go @@ -17,12 +17,12 @@ import ( "context" "fmt" "math" + "slices" "sort" "testing" "time" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/storage" diff --git a/tsdb/querier.go b/tsdb/querier.go index ab2c53d70d..6fc2758dbe 100644 --- a/tsdb/querier.go +++ b/tsdb/querier.go @@ -18,11 +18,11 @@ import ( "errors" "fmt" "math" + "slices" "strings" "unicode/utf8" "github.com/oklog/ulid" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" diff --git a/tsdb/wlog/checkpoint.go b/tsdb/wlog/checkpoint.go index a49ed1a0ce..4ad1bb2365 100644 --- a/tsdb/wlog/checkpoint.go +++ b/tsdb/wlog/checkpoint.go @@ -21,12 +21,12 @@ import ( "math" "os" "path/filepath" + "slices" "strconv" "strings" "github.com/go-kit/log" "github.com/go-kit/log/level" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/tsdb/chunks" diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index a4c46bbaa7..b924944689 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -20,6 +20,7 @@ import ( "math" "os" "path/filepath" + "slices" "strconv" "strings" "time" @@ -27,7 +28,6 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/timestamp" diff --git a/tsdb/wlog/wlog.go b/tsdb/wlog/wlog.go index fdea756945..577057fd4f 100644 --- a/tsdb/wlog/wlog.go +++ b/tsdb/wlog/wlog.go @@ -23,6 +23,7 @@ import ( "io" "os" "path/filepath" + "slices" "strconv" "sync" "time" @@ -32,7 +33,6 @@ import ( "github.com/golang/snappy" "github.com/klauspost/compress/zstd" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/tsdb/fileutil" ) diff --git a/util/stats/timer.go b/util/stats/timer.go index b7d79f4121..eca0fcccb0 100644 --- a/util/stats/timer.go +++ b/util/stats/timer.go @@ -16,9 +16,8 @@ package stats import ( "bytes" "fmt" + "slices" "time" - - "golang.org/x/exp/slices" ) // A Timer that can be started and stopped and accumulates the total time it diff --git a/web/api/v1/api.go b/web/api/v1/api.go index fcb55026e8..59e20004cd 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -24,6 +24,7 @@ import ( "net/url" "os" "path/filepath" + "slices" "sort" "strconv" "strings" @@ -37,7 +38,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" "github.com/prometheus/common/route" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/model/labels" diff --git a/web/federate.go b/web/federate.go index e0bfc6ee25..8176eba365 100644 --- a/web/federate.go +++ b/web/federate.go @@ -17,6 +17,7 @@ import ( "errors" "fmt" "net/http" + "slices" "sort" "strings" @@ -26,7 +27,6 @@ import ( dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" - "golang.org/x/exp/slices" "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" From 4b71f6ffc21b40a8b88a8ad39a66b7d1075fbea6 Mon Sep 17 00:00:00 2001 From: machine424 Date: Wed, 24 Jan 2024 23:22:32 +0100 Subject: [PATCH 078/253] promtool: add a "tsdb dump-openmetrics" to dump in OpemMetrics format. This closes the loop, as the output can be fed into "tsdb create-blocks-from openmetrics" Native histograms are not supported. Signed-off-by: machine424 --- cmd/promtool/main.go | 10 ++- .../dump-openmetrics-roundtrip-test.prom | 15 +++++ .../testdata/dump-openmetrics-test.prom | 11 ++++ cmd/promtool/tsdb.go | 61 +++++++++++++++++-- cmd/promtool/tsdb_test.go | 56 +++++++++++++++-- docs/command-line/promtool.md | 26 ++++++++ 6 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 cmd/promtool/testdata/dump-openmetrics-roundtrip-test.prom create mode 100644 cmd/promtool/testdata/dump-openmetrics-test.prom diff --git a/cmd/promtool/main.go b/cmd/promtool/main.go index 0332c33eaa..47bf02c104 100644 --- a/cmd/promtool/main.go +++ b/cmd/promtool/main.go @@ -239,6 +239,12 @@ func main() { dumpMaxTime := tsdbDumpCmd.Flag("max-time", "Maximum timestamp to dump.").Default(strconv.FormatInt(math.MaxInt64, 10)).Int64() dumpMatch := tsdbDumpCmd.Flag("match", "Series selector. Can be specified multiple times.").Default("{__name__=~'(?s:.*)'}").Strings() + tsdbDumpOpenMetricsCmd := tsdbCmd.Command("dump-openmetrics", "[Experimental] Dump samples from a TSDB into OpenMetrics format. Native histograms are not dumped.") + dumpOpenMetricsPath := tsdbDumpOpenMetricsCmd.Arg("db path", "Database path (default is "+defaultDBPath+").").Default(defaultDBPath).String() + dumpOpenMetricsMinTime := tsdbDumpOpenMetricsCmd.Flag("min-time", "Minimum timestamp to dump.").Default(strconv.FormatInt(math.MinInt64, 10)).Int64() + dumpOpenMetricsMaxTime := tsdbDumpOpenMetricsCmd.Flag("max-time", "Maximum timestamp to dump.").Default(strconv.FormatInt(math.MaxInt64, 10)).Int64() + dumpOpenMetricsMatch := tsdbDumpOpenMetricsCmd.Flag("match", "Series selector. Can be specified multiple times.").Default("{__name__=~'(?s:.*)'}").Strings() + importCmd := tsdbCmd.Command("create-blocks-from", "[Experimental] Import samples from input and produce TSDB blocks. Please refer to the storage docs for more details.") importHumanReadable := importCmd.Flag("human-readable", "Print human readable values.").Short('r').Bool() importQuiet := importCmd.Flag("quiet", "Do not print created blocks.").Short('q').Bool() @@ -390,7 +396,9 @@ func main() { os.Exit(checkErr(listBlocks(*listPath, *listHumanReadable))) case tsdbDumpCmd.FullCommand(): - os.Exit(checkErr(dumpSamples(ctx, *dumpPath, *dumpMinTime, *dumpMaxTime, *dumpMatch))) + os.Exit(checkErr(dumpSamples(ctx, *dumpPath, *dumpMinTime, *dumpMaxTime, *dumpMatch, formatSeriesSet))) + case tsdbDumpOpenMetricsCmd.FullCommand(): + os.Exit(checkErr(dumpSamples(ctx, *dumpOpenMetricsPath, *dumpOpenMetricsMinTime, *dumpOpenMetricsMaxTime, *dumpOpenMetricsMatch, formatSeriesSetOpenMetrics))) // TODO(aSquare14): Work on adding support for custom block size. case openMetricsImportCmd.FullCommand(): os.Exit(backfillOpenMetrics(*importFilePath, *importDBPath, *importHumanReadable, *importQuiet, *maxBlockDuration)) diff --git a/cmd/promtool/testdata/dump-openmetrics-roundtrip-test.prom b/cmd/promtool/testdata/dump-openmetrics-roundtrip-test.prom new file mode 100644 index 0000000000..c2318e94e6 --- /dev/null +++ b/cmd/promtool/testdata/dump-openmetrics-roundtrip-test.prom @@ -0,0 +1,15 @@ +my_histogram_bucket{instance="localhost:8000",job="example2",le="+Inf"} 1.0267820369e+10 1700215884.373 +my_histogram_bucket{instance="localhost:8000",job="example2",le="+Inf"} 1.026872507e+10 1700215889.373 +my_histogram_bucket{instance="localhost:8000",job="example2",le="0.01"} 0 1700215884.373 +my_histogram_bucket{instance="localhost:8000",job="example2",le="0.01"} 0 1700215889.373 +my_histogram_count{instance="localhost:8000",job="example2"} 1.0267820369e+10 1700215884.373 +my_histogram_count{instance="localhost:8000",job="example2"} 1.026872507e+10 1700215889.373 +my_summary_count{instance="localhost:8000",job="example5"} 9.518161497e+09 1700211684.981 +my_summary_count{instance="localhost:8000",job="example5"} 9.519048034e+09 1700211689.984 +my_summary_sum{instance="localhost:8000",job="example5"} 5.2349889185e+10 1700211684.981 +my_summary_sum{instance="localhost:8000",job="example5"} 5.2354761848e+10 1700211689.984 +up{instance="localhost:8000",job="example2"} 1 1700226034.330 +up{instance="localhost:8000",job="example2"} 1 1700226094.329 +up{instance="localhost:8000",job="example3"} 1 1700210681.366 +up{instance="localhost:8000",job="example3"} 1 1700210686.366 +# EOF diff --git a/cmd/promtool/testdata/dump-openmetrics-test.prom b/cmd/promtool/testdata/dump-openmetrics-test.prom new file mode 100644 index 0000000000..c027b8c270 --- /dev/null +++ b/cmd/promtool/testdata/dump-openmetrics-test.prom @@ -0,0 +1,11 @@ +my_counter{baz="abc",foo="bar"} 1 0.000 +my_counter{baz="abc",foo="bar"} 2 60.000 +my_counter{baz="abc",foo="bar"} 3 120.000 +my_counter{baz="abc",foo="bar"} 4 180.000 +my_counter{baz="abc",foo="bar"} 5 240.000 +my_gauge{abc="baz",bar="foo"} 9 0.000 +my_gauge{abc="baz",bar="foo"} 8 60.000 +my_gauge{abc="baz",bar="foo"} 0 120.000 +my_gauge{abc="baz",bar="foo"} 4 180.000 +my_gauge{abc="baz",bar="foo"} 7 240.000 +# EOF diff --git a/cmd/promtool/tsdb.go b/cmd/promtool/tsdb.go index 4bba8421c2..519f735102 100644 --- a/cmd/promtool/tsdb.go +++ b/cmd/promtool/tsdb.go @@ -15,6 +15,7 @@ package main import ( "bufio" + "bytes" "context" "errors" "fmt" @@ -706,7 +707,9 @@ func analyzeCompaction(ctx context.Context, block tsdb.BlockReader, indexr tsdb. return nil } -func dumpSamples(ctx context.Context, path string, mint, maxt int64, match []string) (err error) { +type SeriesSetFormatter func(series storage.SeriesSet) error + +func dumpSamples(ctx context.Context, path string, mint, maxt int64, match []string, formatter SeriesSetFormatter) (err error) { db, err := tsdb.OpenDBReadOnly(path, nil) if err != nil { return err @@ -736,6 +739,22 @@ func dumpSamples(ctx context.Context, path string, mint, maxt int64, match []str ss = q.Select(ctx, false, nil, matcherSets[0]...) } + err = formatter(ss) + if err != nil { + return err + } + + if ws := ss.Warnings(); len(ws) > 0 { + return tsdb_errors.NewMulti(ws.AsErrors()...).Err() + } + + if ss.Err() != nil { + return ss.Err() + } + return nil +} + +func formatSeriesSet(ss storage.SeriesSet) error { for ss.Next() { series := ss.At() lbs := series.Labels() @@ -756,14 +775,44 @@ func dumpSamples(ctx context.Context, path string, mint, maxt int64, match []str return ss.Err() } } + return nil +} - if ws := ss.Warnings(); len(ws) > 0 { - return tsdb_errors.NewMulti(ws.AsErrors()...).Err() - } +// CondensedString is labels.Labels.String() without spaces after the commas. +func CondensedString(ls labels.Labels) string { + var b bytes.Buffer - if ss.Err() != nil { - return ss.Err() + b.WriteByte('{') + i := 0 + ls.Range(func(l labels.Label) { + if i > 0 { + b.WriteByte(',') + } + b.WriteString(l.Name) + b.WriteByte('=') + b.WriteString(strconv.Quote(l.Value)) + i++ + }) + b.WriteByte('}') + return b.String() +} + +func formatSeriesSetOpenMetrics(ss storage.SeriesSet) error { + for ss.Next() { + series := ss.At() + lbs := series.Labels() + metricName := lbs.Get(labels.MetricName) + lbs = lbs.DropMetricName() + it := series.Iterator(nil) + for it.Next() == chunkenc.ValFloat { + ts, val := it.At() + fmt.Printf("%s%s %g %.3f\n", metricName, CondensedString(lbs), val, float64(ts)/1000) + } + if it.Err() != nil { + return ss.Err() + } } + fmt.Println("# EOF") return nil } diff --git a/cmd/promtool/tsdb_test.go b/cmd/promtool/tsdb_test.go index aeb51a07e0..36a65d73e4 100644 --- a/cmd/promtool/tsdb_test.go +++ b/cmd/promtool/tsdb_test.go @@ -22,10 +22,12 @@ import ( "runtime" "strings" "testing" + "time" "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/promql" + "github.com/prometheus/prometheus/tsdb" ) func TestGenerateBucket(t *testing.T) { @@ -52,7 +54,7 @@ func TestGenerateBucket(t *testing.T) { } // getDumpedSamples dumps samples and returns them. -func getDumpedSamples(t *testing.T, path string, mint, maxt int64, match []string) string { +func getDumpedSamples(t *testing.T, path string, mint, maxt int64, match []string, formatter SeriesSetFormatter) string { t.Helper() oldStdout := os.Stdout @@ -65,6 +67,7 @@ func getDumpedSamples(t *testing.T, path string, mint, maxt int64, match []strin mint, maxt, match, + formatter, ) require.NoError(t, err) @@ -76,6 +79,14 @@ func getDumpedSamples(t *testing.T, path string, mint, maxt int64, match []strin return buf.String() } +func normalizeNewLine(b []byte) []byte { + if strings.Contains(runtime.GOOS, "windows") { + // We use "/n" while dumping on windows as well. + return bytes.ReplaceAll(b, []byte("\r\n"), []byte("\n")) + } + return b +} + func TestTSDBDump(t *testing.T) { storage := promql.LoadedStorage(t, ` load 1m @@ -136,15 +147,48 @@ func TestTSDBDump(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - dumpedMetrics := getDumpedSamples(t, storage.Dir(), tt.mint, tt.maxt, tt.match) + dumpedMetrics := getDumpedSamples(t, storage.Dir(), tt.mint, tt.maxt, tt.match, formatSeriesSet) expectedMetrics, err := os.ReadFile(tt.expectedDump) require.NoError(t, err) - if strings.Contains(runtime.GOOS, "windows") { - // We use "/n" while dumping on windows as well. - expectedMetrics = bytes.ReplaceAll(expectedMetrics, []byte("\r\n"), []byte("\n")) - } + expectedMetrics = normalizeNewLine(expectedMetrics) // even though in case of one matcher samples are not sorted, the order in the cases above should stay the same. require.Equal(t, string(expectedMetrics), dumpedMetrics) }) } } + +func TestTSDBDumpOpenMetrics(t *testing.T) { + storage := promql.LoadedStorage(t, ` + load 1m + my_counter{foo="bar", baz="abc"} 1 2 3 4 5 + my_gauge{bar="foo", abc="baz"} 9 8 0 4 7 + `) + + expectedMetrics, err := os.ReadFile("testdata/dump-openmetrics-test.prom") + require.NoError(t, err) + expectedMetrics = normalizeNewLine(expectedMetrics) + dumpedMetrics := getDumpedSamples(t, storage.Dir(), math.MinInt64, math.MaxInt64, []string{"{__name__=~'(?s:.*)'}"}, formatSeriesSetOpenMetrics) + require.Equal(t, string(expectedMetrics), dumpedMetrics) +} + +func TestTSDBDumpOpenMetricsRoundTrip(t *testing.T) { + initialMetrics, err := os.ReadFile("testdata/dump-openmetrics-roundtrip-test.prom") + require.NoError(t, err) + initialMetrics = normalizeNewLine(initialMetrics) + + dbDir := t.TempDir() + // Import samples from OM format + err = backfill(5000, initialMetrics, dbDir, false, false, 2*time.Hour) + require.NoError(t, err) + db, err := tsdb.Open(dbDir, nil, nil, tsdb.DefaultOptions(), nil) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, db.Close()) + }) + + // Dump the blocks into OM format + dumpedMetrics := getDumpedSamples(t, dbDir, math.MinInt64, math.MaxInt64, []string{"{__name__=~'(?s:.*)'}"}, formatSeriesSetOpenMetrics) + + // Should get back the initial metrics. + require.Equal(t, string(initialMetrics), dumpedMetrics) +} diff --git a/docs/command-line/promtool.md b/docs/command-line/promtool.md index 863bc068c3..3eceed48f2 100644 --- a/docs/command-line/promtool.md +++ b/docs/command-line/promtool.md @@ -582,6 +582,32 @@ Dump samples from a TSDB. +##### `promtool tsdb dump-openmetrics` + +[Experimental] Dump samples from a TSDB into OpenMetrics format. Native histograms are not dumped. + + + +###### Flags + +| Flag | Description | Default | +| --- | --- | --- | +| --min-time | Minimum timestamp to dump. | `-9223372036854775808` | +| --max-time | Maximum timestamp to dump. | `9223372036854775807` | +| --match | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` | + + + + +###### Arguments + +| Argument | Description | Default | +| --- | --- | --- | +| db path | Database path (default is data/). | `data/` | + + + + ##### `promtool tsdb create-blocks-from` [Experimental] Import samples from input and produce TSDB blocks. Please refer to the storage docs for more details. From 0e81ab44a2d5d1f7ca5c6e31618f7fc14e84a5d5 Mon Sep 17 00:00:00 2001 From: machine424 Date: Wed, 7 Feb 2024 12:38:40 +0100 Subject: [PATCH 079/253] discovery(k8s): add a metric to track failed requests, failures will still be logged. Signed-off-by: machine424 --- discovery/kubernetes/kubernetes.go | 51 ++++++++++++++++++------- discovery/kubernetes/kubernetes_test.go | 40 +++++++++++++++++++ discovery/kubernetes/metrics.go | 13 ++++++- 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/discovery/kubernetes/kubernetes.go b/discovery/kubernetes/kubernetes.go index d6b8115848..94058aa04e 100644 --- a/discovery/kubernetes/kubernetes.go +++ b/discovery/kubernetes/kubernetes.go @@ -485,8 +485,8 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { eps := NewEndpointSlice( log.With(d.logger, "role", "endpointslice"), informer, - cache.NewSharedInformer(slw, &apiv1.Service{}, resyncDisabled), - cache.NewSharedInformer(plw, &apiv1.Pod{}, resyncDisabled), + d.mustNewSharedInformer(slw, &apiv1.Service{}, resyncDisabled), + d.mustNewSharedInformer(plw, &apiv1.Pod{}, resyncDisabled), nodeInf, d.metrics.eventCount, ) @@ -545,8 +545,8 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { eps := NewEndpoints( log.With(d.logger, "role", "endpoint"), d.newEndpointsByNodeInformer(elw), - cache.NewSharedInformer(slw, &apiv1.Service{}, resyncDisabled), - cache.NewSharedInformer(plw, &apiv1.Pod{}, resyncDisabled), + d.mustNewSharedInformer(slw, &apiv1.Service{}, resyncDisabled), + d.mustNewSharedInformer(plw, &apiv1.Pod{}, resyncDisabled), nodeInf, d.metrics.eventCount, ) @@ -602,7 +602,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { } svc := NewService( log.With(d.logger, "role", "service"), - cache.NewSharedInformer(slw, &apiv1.Service{}, resyncDisabled), + d.mustNewSharedInformer(slw, &apiv1.Service{}, resyncDisabled), d.metrics.eventCount, ) d.discoverers = append(d.discoverers, svc) @@ -641,7 +641,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { return i.Watch(ctx, options) }, } - informer = cache.NewSharedInformer(ilw, &networkv1.Ingress{}, resyncDisabled) + informer = d.mustNewSharedInformer(ilw, &networkv1.Ingress{}, resyncDisabled) } else { i := d.client.NetworkingV1beta1().Ingresses(namespace) ilw := &cache.ListWatch{ @@ -656,7 +656,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) { return i.Watch(ctx, options) }, } - informer = cache.NewSharedInformer(ilw, &v1beta1.Ingress{}, resyncDisabled) + informer = d.mustNewSharedInformer(ilw, &v1beta1.Ingress{}, resyncDisabled) } ingress := NewIngress( log.With(d.logger, "role", "ingress"), @@ -747,7 +747,7 @@ func (d *Discovery) newNodeInformer(ctx context.Context) cache.SharedInformer { return d.client.CoreV1().Nodes().Watch(ctx, options) }, } - return cache.NewSharedInformer(nlw, &apiv1.Node{}, resyncDisabled) + return d.mustNewSharedInformer(nlw, &apiv1.Node{}, resyncDisabled) } func (d *Discovery) newPodsByNodeInformer(plw *cache.ListWatch) cache.SharedIndexInformer { @@ -762,7 +762,7 @@ func (d *Discovery) newPodsByNodeInformer(plw *cache.ListWatch) cache.SharedInde } } - return cache.NewSharedIndexInformer(plw, &apiv1.Pod{}, resyncDisabled, indexers) + return d.mustNewSharedIndexInformer(plw, &apiv1.Pod{}, resyncDisabled, indexers) } func (d *Discovery) newEndpointsByNodeInformer(plw *cache.ListWatch) cache.SharedIndexInformer { @@ -783,7 +783,7 @@ func (d *Discovery) newEndpointsByNodeInformer(plw *cache.ListWatch) cache.Share return pods, nil } if !d.attachMetadata.Node { - return cache.NewSharedIndexInformer(plw, &apiv1.Endpoints{}, resyncDisabled, indexers) + return d.mustNewSharedIndexInformer(plw, &apiv1.Endpoints{}, resyncDisabled, indexers) } indexers[nodeIndex] = func(obj interface{}) ([]string, error) { @@ -809,13 +809,13 @@ func (d *Discovery) newEndpointsByNodeInformer(plw *cache.ListWatch) cache.Share return nodes, nil } - return cache.NewSharedIndexInformer(plw, &apiv1.Endpoints{}, resyncDisabled, indexers) + return d.mustNewSharedIndexInformer(plw, &apiv1.Endpoints{}, resyncDisabled, indexers) } func (d *Discovery) newEndpointSlicesByNodeInformer(plw *cache.ListWatch, object runtime.Object) cache.SharedIndexInformer { indexers := make(map[string]cache.IndexFunc) if !d.attachMetadata.Node { - return cache.NewSharedIndexInformer(plw, object, resyncDisabled, indexers) + return d.mustNewSharedIndexInformer(plw, object, resyncDisabled, indexers) } indexers[nodeIndex] = func(obj interface{}) ([]string, error) { @@ -854,7 +854,32 @@ func (d *Discovery) newEndpointSlicesByNodeInformer(plw *cache.ListWatch, object return nodes, nil } - return cache.NewSharedIndexInformer(plw, object, resyncDisabled, indexers) + return d.mustNewSharedIndexInformer(plw, object, resyncDisabled, indexers) +} + +func (d *Discovery) informerWatchErrorHandler(r *cache.Reflector, err error) { + d.metrics.failuresCount.Inc() + cache.DefaultWatchErrorHandler(r, err) +} + +func (d *Discovery) mustNewSharedInformer(lw cache.ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration) cache.SharedInformer { + informer := cache.NewSharedInformer(lw, exampleObject, defaultEventHandlerResyncPeriod) + // Invoking SetWatchErrorHandler should fail only if the informer has been started beforehand. + // Such a scenario would suggest an incorrect use of the API, thus the panic. + if err := informer.SetWatchErrorHandler(d.informerWatchErrorHandler); err != nil { + panic(err) + } + return informer +} + +func (d *Discovery) mustNewSharedIndexInformer(lw cache.ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + informer := cache.NewSharedIndexInformer(lw, exampleObject, defaultEventHandlerResyncPeriod, indexers) + // Invoking SetWatchErrorHandler should fail only if the informer has been started beforehand. + // Such a scenario would suggest an incorrect use of the API, thus the panic. + if err := informer.SetWatchErrorHandler(d.informerWatchErrorHandler); err != nil { + panic(err) + } + return informer } func checkDiscoveryV1Supported(client kubernetes.Interface) (bool, error) { diff --git a/discovery/kubernetes/kubernetes_test.go b/discovery/kubernetes/kubernetes_test.go index e3dd093009..552f8a4453 100644 --- a/discovery/kubernetes/kubernetes_test.go +++ b/discovery/kubernetes/kubernetes_test.go @@ -21,12 +21,16 @@ import ( "time" "github.com/go-kit/log" + prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/version" + "k8s.io/apimachinery/pkg/watch" fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" + kubetesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" "github.com/prometheus/client_golang/prometheus" @@ -314,3 +318,39 @@ func TestCheckNetworkingV1Supported(t *testing.T) { }) } } + +func TestFailuresCountMetric(t *testing.T) { + tests := []struct { + role Role + minFailedWatches int + }{ + {RoleNode, 1}, + {RolePod, 1}, + {RoleService, 1}, + {RoleEndpoint, 3}, + {RoleEndpointSlice, 3}, + {RoleIngress, 1}, + } + + for _, tc := range tests { + tc := tc + t.Run(string(tc.role), func(t *testing.T) { + t.Parallel() + + n, c := makeDiscovery(tc.role, NamespaceDiscovery{}) + // The counter is initialized and no failures at the beginning. + require.Equal(t, float64(0), prom_testutil.ToFloat64(n.metrics.failuresCount)) + + // Simulate an error on watch requests. + c.Discovery().(*fakediscovery.FakeDiscovery).PrependWatchReactor("*", func(action kubetesting.Action) (bool, watch.Interface, error) { + return true, nil, apierrors.NewUnauthorized("unauthorized") + }) + + // Start the discovery. + k8sDiscoveryTest{discovery: n}.Run(t) + + // At least the errors of the initial watches should be caught (watches are retried on errors). + require.GreaterOrEqual(t, prom_testutil.ToFloat64(n.metrics.failuresCount), float64(tc.minFailedWatches)) + }) + } +} diff --git a/discovery/kubernetes/metrics.go b/discovery/kubernetes/metrics.go index 7d384fb96a..fe419bc782 100644 --- a/discovery/kubernetes/metrics.go +++ b/discovery/kubernetes/metrics.go @@ -22,7 +22,8 @@ import ( var _ discovery.DiscovererMetrics = (*kubernetesMetrics)(nil) type kubernetesMetrics struct { - eventCount *prometheus.CounterVec + eventCount *prometheus.CounterVec + failuresCount prometheus.Counter metricRegisterer discovery.MetricRegisterer } @@ -37,10 +38,18 @@ func newDiscovererMetrics(reg prometheus.Registerer, rmi discovery.RefreshMetric }, []string{"role", "event"}, ), + failuresCount: prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: discovery.KubernetesMetricsNamespace, + Name: "failures_total", + Help: "The number of failed WATCH/LIST requests.", + }, + ), } m.metricRegisterer = discovery.NewMetricRegisterer(reg, []prometheus.Collector{ m.eventCount, + m.failuresCount, }) // Initialize metric vectors. @@ -61,6 +70,8 @@ func newDiscovererMetrics(reg prometheus.Registerer, rmi discovery.RefreshMetric } } + m.failuresCount.Add(0) + return m } From a09465baeed40ecc0468d81fb44c41a69305e127 Mon Sep 17 00:00:00 2001 From: Robert Fratto Date: Wed, 28 Feb 2024 17:28:39 -0500 Subject: [PATCH 080/253] storage/remote: disable resharding during active retry backoffs (#13562) * storage/remote: disable resharding during active retry backoffs Today, remote_write reshards based on pure throughput. This is problematic if throughput has been diminished because of HTTP 429s; increasing the number of shards due to backpressure will only exacerbate the problem. This commit disables resharding for twice the retry backoff, ensuring that resharding will never occur during an active backoff, and that resharding does not become enabled again until enough time has elapsed to allow any pending requests to be retried. Signed-off-by: Robert Fratto * storage/remote: test that resharding is disabled on retry Signed-off-by: Robert Fratto * storage/remote: address review feedback Signed-off-by: Robert Fratto * storage/remote: track time where resharding initially got disabled This change introduces a second atomic int64 to roughly track when resharding got disabled. This int64 is only updated after updating the disabled timestamp if resharding was previously enabled. Signed-off-by: Robert Fratto --------- Signed-off-by: Robert Fratto --- storage/remote/queue_manager.go | 68 +++++++++++++++++++++---- storage/remote/queue_manager_test.go | 75 ++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 11 deletions(-) diff --git a/storage/remote/queue_manager.go b/storage/remote/queue_manager.go index 4b0c72cf60..98e4aa54c1 100644 --- a/storage/remote/queue_manager.go +++ b/storage/remote/queue_manager.go @@ -396,8 +396,10 @@ type WriteClient interface { // indicated by the provided WriteClient. Implements writeTo interface // used by WAL Watcher. type QueueManager struct { - lastSendTimestamp atomic.Int64 - buildRequestLimitTimestamp atomic.Int64 + lastSendTimestamp atomic.Int64 + buildRequestLimitTimestamp atomic.Int64 + reshardDisableStartTimestamp atomic.Int64 // Time that reshard was disabled. + reshardDisableEndTimestamp atomic.Int64 // Time that reshard is disabled until. logger log.Logger flushDeadline time.Duration @@ -574,7 +576,7 @@ func (t *QueueManager) sendMetadataWithBackoff(ctx context.Context, metadata []p retry := func() { t.metrics.retriedMetadataTotal.Add(float64(len(metadata))) } - err = sendWriteRequestWithBackoff(ctx, t.cfg, t.logger, attemptStore, retry) + err = t.sendWriteRequestWithBackoff(ctx, attemptStore, retry) if err != nil { return err } @@ -1021,6 +1023,13 @@ func (t *QueueManager) shouldReshard(desiredShards int) bool { level.Warn(t.logger).Log("msg", "Skipping resharding, last successful send was beyond threshold", "lastSendTimestamp", lsts, "minSendTimestamp", minSendTimestamp) return false } + if disableTimestamp := t.reshardDisableEndTimestamp.Load(); time.Now().Unix() < disableTimestamp { + disabledAt := time.Unix(t.reshardDisableStartTimestamp.Load(), 0) + disabledFor := time.Until(time.Unix(disableTimestamp, 0)) + + level.Warn(t.logger).Log("msg", "Skipping resharding, resharding is disabled while waiting for recoverable errors", "disabled_at", disabledAt, "disabled_for", disabledFor) + return false + } return true } @@ -1622,7 +1631,7 @@ func (s *shards) sendSamplesWithBackoff(ctx context.Context, samples []prompb.Ti s.qm.metrics.retriedHistogramsTotal.Add(float64(histogramCount)) } - err = sendWriteRequestWithBackoff(ctx, s.qm.cfg, s.qm.logger, attemptStore, onRetry) + err = s.qm.sendWriteRequestWithBackoff(ctx, attemptStore, onRetry) if errors.Is(err, context.Canceled) { // When there is resharding, we cancel the context for this queue, which means the data is not sent. // So we exit early to not update the metrics. @@ -1635,8 +1644,8 @@ func (s *shards) sendSamplesWithBackoff(ctx context.Context, samples []prompb.Ti return err } -func sendWriteRequestWithBackoff(ctx context.Context, cfg config.QueueConfig, l log.Logger, attempt func(int) error, onRetry func()) error { - backoff := cfg.MinBackoff +func (t *QueueManager) sendWriteRequestWithBackoff(ctx context.Context, attempt func(int) error, onRetry func()) error { + backoff := t.cfg.MinBackoff sleepDuration := model.Duration(0) try := 0 @@ -1663,9 +1672,26 @@ func sendWriteRequestWithBackoff(ctx context.Context, cfg config.QueueConfig, l switch { case backoffErr.retryAfter > 0: sleepDuration = backoffErr.retryAfter - level.Info(l).Log("msg", "Retrying after duration specified by Retry-After header", "duration", sleepDuration) + level.Info(t.logger).Log("msg", "Retrying after duration specified by Retry-After header", "duration", sleepDuration) case backoffErr.retryAfter < 0: - level.Debug(l).Log("msg", "retry-after cannot be in past, retrying using default backoff mechanism") + level.Debug(t.logger).Log("msg", "retry-after cannot be in past, retrying using default backoff mechanism") + } + + // We should never reshard for a recoverable error; increasing shards could + // make the problem worse, particularly if we're getting rate limited. + // + // reshardDisableTimestamp holds the unix timestamp until which resharding + // is diableld. We'll update that timestamp if the period we were just told + // to sleep for is newer than the existing disabled timestamp. + reshardWaitPeriod := time.Now().Add(time.Duration(sleepDuration) * 2) + if oldTS, updated := setAtomicToNewer(&t.reshardDisableEndTimestamp, reshardWaitPeriod.Unix()); updated { + // If the old timestamp was in the past, then resharding was previously + // enabled. We want to track the time where it initially got disabled for + // logging purposes. + disableTime := time.Now().Unix() + if oldTS < disableTime { + t.reshardDisableStartTimestamp.Store(disableTime) + } } select { @@ -1675,18 +1701,38 @@ func sendWriteRequestWithBackoff(ctx context.Context, cfg config.QueueConfig, l // If we make it this far, we've encountered a recoverable error and will retry. onRetry() - level.Warn(l).Log("msg", "Failed to send batch, retrying", "err", err) + level.Warn(t.logger).Log("msg", "Failed to send batch, retrying", "err", err) backoff = sleepDuration * 2 - if backoff > cfg.MaxBackoff { - backoff = cfg.MaxBackoff + if backoff > t.cfg.MaxBackoff { + backoff = t.cfg.MaxBackoff } try++ } } +// setAtomicToNewer atomically sets a value to the newer int64 between itself +// and the provided newValue argument. setAtomicToNewer returns whether the +// atomic value was updated and what the previous value was. +func setAtomicToNewer(value *atomic.Int64, newValue int64) (previous int64, updated bool) { + for { + current := value.Load() + if current >= newValue { + // If the current stored value is newer than newValue; abort. + return current, false + } + + // Try to swap the value. If the atomic value has changed, we loop back to + // the beginning until we've successfully swapped out the value or the + // value stored in it is newer than newValue. + if value.CompareAndSwap(current, newValue) { + return current, true + } + } +} + func buildTimeSeries(timeSeries []prompb.TimeSeries, filter func(prompb.TimeSeries) bool) (int64, int64, []prompb.TimeSeries, int, int, int) { var highest int64 var lowest int64 diff --git a/storage/remote/queue_manager_test.go b/storage/remote/queue_manager_test.go index e9de8beba4..028120c05c 100644 --- a/storage/remote/queue_manager_test.go +++ b/storage/remote/queue_manager_test.go @@ -520,6 +520,69 @@ func TestShouldReshard(t *testing.T) { } } +// TestDisableReshardOnRetry asserts that resharding should be disabled when a +// recoverable error is returned from remote_write. +func TestDisableReshardOnRetry(t *testing.T) { + onStoredContext, onStoreCalled := context.WithCancel(context.Background()) + defer onStoreCalled() + + var ( + fakeSamples, fakeSeries = createTimeseries(100, 100) + + cfg = config.DefaultQueueConfig + mcfg = config.DefaultMetadataConfig + retryAfter = time.Second + + metrics = newQueueManagerMetrics(nil, "", "") + + client = &MockWriteClient{ + StoreFunc: func(ctx context.Context, b []byte, i int) error { + onStoreCalled() + + return RecoverableError{ + error: fmt.Errorf("fake error"), + retryAfter: model.Duration(retryAfter), + } + }, + NameFunc: func() string { return "mock" }, + EndpointFunc: func() string { return "http://fake:9090/api/v1/write" }, + } + ) + + m := NewQueueManager(metrics, nil, nil, nil, "", newEWMARate(ewmaWeight, shardUpdateDuration), cfg, mcfg, labels.EmptyLabels(), nil, client, 0, newPool(), newHighestTimestampMetric(), nil, false, false) + m.StoreSeries(fakeSeries, 0) + + // Attempt to samples while the manager is running. We immediately stop the + // manager after the recoverable error is generated to prevent the manager + // from resharding itself. + m.Start() + { + m.Append(fakeSamples) + + select { + case <-onStoredContext.Done(): + case <-time.After(time.Minute): + require.FailNow(t, "timed out waiting for client to be sent metrics") + } + } + m.Stop() + + require.Eventually(t, func() bool { + // Force m.lastSendTimestamp to be current so the last send timestamp isn't + // the reason resharding is disabled. + m.lastSendTimestamp.Store(time.Now().Unix()) + return m.shouldReshard(m.numShards+1) == false + }, time.Minute, 10*time.Millisecond, "shouldReshard was never disabled") + + // After 2x retryAfter, resharding should be enabled again. + require.Eventually(t, func() bool { + // Force m.lastSendTimestamp to be current so the last send timestamp isn't + // the reason resharding is disabled. + m.lastSendTimestamp.Store(time.Now().Unix()) + return m.shouldReshard(m.numShards+1) == true + }, time.Minute, retryAfter, "shouldReshard should have been re-enabled") +} + func createTimeseries(numSamples, numSeries int, extraLabels ...labels.Label) ([]record.RefSample, []record.RefSeries) { samples := make([]record.RefSample, 0, numSamples) series := make([]record.RefSeries, 0, numSeries) @@ -844,6 +907,18 @@ func (c *NopWriteClient) Store(context.Context, []byte, int) error { return nil func (c *NopWriteClient) Name() string { return "nopwriteclient" } func (c *NopWriteClient) Endpoint() string { return "http://test-remote.com/1234" } +type MockWriteClient struct { + StoreFunc func(context.Context, []byte, int) error + NameFunc func() string + EndpointFunc func() string +} + +func (c *MockWriteClient) Store(ctx context.Context, bb []byte, n int) error { + return c.StoreFunc(ctx, bb, n) +} +func (c *MockWriteClient) Name() string { return c.NameFunc() } +func (c *MockWriteClient) Endpoint() string { return c.EndpointFunc() } + // Extra labels to make a more realistic workload - taken from Kubernetes' embedded cAdvisor metrics. var extraLabels []labels.Label = []labels.Label{ {Name: "kubernetes_io_arch", Value: "amd64"}, From ab9b770aea96e035e60958e2a3fac539dc3e0e72 Mon Sep 17 00:00:00 2001 From: Manik Rana Date: Thu, 29 Feb 2024 18:51:15 +0530 Subject: [PATCH 081/253] ui (histograms): Add native histogram chart to Table view (#13658) * feat: initial add histogram table Signed-off-by: Manik Rana * feat: add x-axis scale toggle Signed-off-by: Manik Rana * refac: adjust histogram summary styles Signed-off-by: Manik Rana * feat: initial add histogram table Signed-off-by: Manik Rana * feat: add x-axis scale toggle Signed-off-by: Manik Rana * refac: adjust histogram summary styles Signed-off-by: Manik Rana * chore: remove unused code Signed-off-by: Manik Rana * tests: test for HistogramChart instead of HistogramString Signed-off-by: Manik Rana * fix: remove histogramChart from a test Signed-off-by: Manik Rana * chore: rename style classes Signed-off-by: Manik Rana * refac: suppress test errors Signed-off-by: Manik Rana --------- Signed-off-by: Manik Rana --- .../src/pages/graph/DataTable.test.tsx | 29 +--- .../react-app/src/pages/graph/DataTable.tsx | 99 +++++++++--- .../src/pages/graph/HistogramChart.tsx | 92 +++++++++++ web/ui/react-app/src/themes/_shared.scss | 150 ++++++++++++++++-- web/ui/react-app/src/themes/dark.scss | 4 + web/ui/react-app/src/themes/light.scss | 4 + 6 files changed, 318 insertions(+), 60 deletions(-) create mode 100644 web/ui/react-app/src/pages/graph/HistogramChart.tsx diff --git a/web/ui/react-app/src/pages/graph/DataTable.test.tsx b/web/ui/react-app/src/pages/graph/DataTable.test.tsx index 61bc55486b..dbc1b18b8e 100755 --- a/web/ui/react-app/src/pages/graph/DataTable.test.tsx +++ b/web/ui/react-app/src/pages/graph/DataTable.test.tsx @@ -71,7 +71,7 @@ describe('DataTable', () => { const table = dataTable.find(Table); table.find('tr').forEach((row, idx) => { expect(row.find(SeriesName)).toHaveLength(1); - expect(row.find('td').at(1).text()).toEqual(`${idx} `); + expect(row.find('td').at(1).text()).toEqual(`${idx}`); }); }); }); @@ -129,42 +129,21 @@ describe('DataTable', () => { }, useLocalTime: false, }; - const dataTable = mount(); + const dataTable = shallow(); it('renders a table', () => { - const table = dataTable.find(Table); + const table = dataTable.find(Table).first(); expect(table.prop('hover')).toBe(true); expect(table.prop('size')).toEqual('sm'); expect(table.prop('className')).toEqual('data-table'); - expect(table.find('tbody')).toHaveLength(1); + expect(table.find('tbody')).toHaveLength(dataTableProps.data?.result.length as number); }); it('renders rows', () => { const table = dataTable.find(Table); - const histogramData = [{ - count: '10', - sum: '3.3', - buckets: [ - [1, '-1', '-0.5', '2'], - [3, '-0.5', '0.5', '3'], - [0, '0.5', '1', '5'], - ] - }, - { - count: '5', - sum: '1.11', - buckets: [ - [0, '0.5', '1', '2'], - [0, '1', '2', '3'], - ], - }]; table.find('tr').forEach((row, idx) => { const seriesNameComponent = dataTable.find('SeriesName'); expect(seriesNameComponent).toHaveLength(dataTableProps.data?.result.length as number); - - const histogramStringComponent = row.find('HistogramString'); - expect(histogramStringComponent).toHaveLength(1); - expect(histogramStringComponent.prop('h')).toEqual(histogramData[idx]); }); }); }); diff --git a/web/ui/react-app/src/pages/graph/DataTable.tsx b/web/ui/react-app/src/pages/graph/DataTable.tsx index 1885c7a80f..add28f182b 100644 --- a/web/ui/react-app/src/pages/graph/DataTable.tsx +++ b/web/ui/react-app/src/pages/graph/DataTable.tsx @@ -1,12 +1,14 @@ import React, { FC, ReactNode } from 'react'; -import { Alert, Table } from 'reactstrap'; +import { Alert, Button, ButtonGroup, Table } from 'reactstrap'; import SeriesName from './SeriesName'; import { Metric, Histogram } from '../../types/types'; import moment from 'moment'; +import HistogramChart from './HistogramChart'; + export interface DataTableProps { data: | null @@ -54,6 +56,8 @@ const limitSeries = (series: S[]): S[] = }; const DataTable: FC = ({ data, useLocalTime }) => { + const [scale, setScale] = React.useState<'linear' | 'exponential'>('exponential'); + if (data === null) { return No data queried yet; } @@ -75,7 +79,42 @@ const DataTable: FC = ({ data, useLocalTime }) => { - {s.value && s.value[1]} + {s.value && s.value[1]} + {s.histogram && ( + <> + +
+
+ + Total count: {s.histogram[1].count} + + + Sum: {s.histogram[1].sum} + +
+
+ x-axis scale: + + + + +
+
+ {histogramTable(s.histogram[1])} + + )} ); @@ -100,7 +139,7 @@ const DataTable: FC = ({ data, useLocalTime }) => { const printedDatetime = moment.unix(h[0]).toISOString(useLocalTime); return ( - @{{h[0]}} + {histogramTable(h[1])} @{{h[0]}}
); @@ -159,29 +198,39 @@ const DataTable: FC = ({ data, useLocalTime }) => { ); }; -export interface HistogramStringProps { - h?: Histogram; -} +const leftDelim = (br: number): string => (br === 3 || br === 1 ? '[' : '('); +const rightDelim = (br: number): string => (br === 3 || br === 0 ? ']' : ')'); -export const HistogramString: FC = ({ h }) => { - if (!h) { - return <>; - } - const buckets: string[] = []; - - if (h.buckets) { - for (const bucket of h.buckets) { - const left = bucket[0] === 3 || bucket[0] === 1 ? '[' : '('; - const right = bucket[0] === 3 || bucket[0] === 0 ? ']' : ')'; - buckets.push(left + bucket[1] + ',' + bucket[2] + right + ':' + bucket[3] + ' '); - } - } - - return ( - <> - {'{'} count:{h.count} sum:{h.sum} {buckets} {'}'} - - ); +export const bucketRangeString = ([boundaryRule, leftBoundary, rightBoundary, _]: [ + number, + string, + string, + string +]): string => { + return `${leftDelim(boundaryRule)}${leftBoundary} -> ${rightBoundary}${rightDelim(boundaryRule)}`; }; +export const histogramTable = (h: Histogram): ReactNode => ( + + + + + + + + + + + + {h.buckets?.map((b, i) => ( + + + + + ))} + +
+ Histogram Sample +
RangeCount
{bucketRangeString(b)}{b[3]}
+); export default DataTable; diff --git a/web/ui/react-app/src/pages/graph/HistogramChart.tsx b/web/ui/react-app/src/pages/graph/HistogramChart.tsx new file mode 100644 index 0000000000..ae171c5e43 --- /dev/null +++ b/web/ui/react-app/src/pages/graph/HistogramChart.tsx @@ -0,0 +1,92 @@ +import React, { FC } from 'react'; +import { UncontrolledTooltip } from 'reactstrap'; +import { Histogram } from '../../types/types'; +import { bucketRangeString } from './DataTable'; + +type ScaleType = 'linear' | 'exponential'; + +const HistogramChart: FC<{ histogram: Histogram; index: number; scale: ScaleType }> = ({ index, histogram, scale }) => { + const { buckets } = histogram; + const rangeMax = buckets ? parseFloat(buckets[buckets.length - 1][2]) : 0; + const countMax = buckets ? buckets.map((b) => parseFloat(b[3])).reduce((a, b) => Math.max(a, b)) : 0; + const formatter = Intl.NumberFormat('en', { notation: 'compact' }); + const positiveBuckets = buckets?.filter((b) => parseFloat(b[1]) >= 0); // we only want to show buckets with range >= 0 + const xLabelTicks = scale === 'linear' ? [0.25, 0.5, 0.75, 1] : [1]; + return ( +
+
+ {[1, 0.75, 0.5, 0.25].map((i) => ( +
+ {formatter.format(countMax * i)} +
+ ))} +
+ 0 +
+
+
+
+ {[0, 0.25, 0.5, 0.75, 1].map((i) => ( + +
+
+
+
+
+ ))} + {positiveBuckets?.map((b, bIdx) => { + const bucketIdx = `bucket-${index}-${bIdx}-${Math.ceil(parseFloat(b[3]) * 100)}`; + const bucketLeft = + scale === 'linear' ? (parseFloat(b[1]) / rangeMax) * 100 + '%' : (bIdx / positiveBuckets.length) * 100 + '%'; + const bucketWidth = + scale === 'linear' + ? ((parseFloat(b[2]) - parseFloat(b[1])) / rangeMax) * 100 + '%' + : 100 / positiveBuckets.length + '%'; + return ( + +
+
+ + range: {bucketRangeString(b)} +
+ count: {b[3]} +
+
+
+ ); + })} +
+
+
+
+ 0 +
+ {xLabelTicks.map((i) => ( +
+
{formatter.format(rangeMax * i)}
+
+ ))} +
+
+
+ ); +}; + +export default HistogramChart; diff --git a/web/ui/react-app/src/themes/_shared.scss b/web/ui/react-app/src/themes/_shared.scss index 8745a6d775..e43901ca6b 100644 --- a/web/ui/react-app/src/themes/_shared.scss +++ b/web/ui/react-app/src/themes/_shared.scss @@ -111,7 +111,7 @@ button.execute-btn { } .navbar-brand svg.animate path { - animation: flamecolor 4s ease-in 1 forwards,flame 1s ease-in infinite; + animation: flamecolor 4s ease-in 1 forwards, flame 1s ease-in infinite; } .navbar-brand { @@ -122,6 +122,126 @@ input[type='checkbox']:checked + label { color: $checked-checkbox-color; } +.histogram-summary-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; +} + +.histogram-summary { + display: flex; + align-items: center; + gap: 1rem; +} + +.histogram-y-wrapper { + display: flex; + flex-wrap: nowrap; + align-items: flex-start; + box-sizing: border-box; + margin: 15px 0; + width: 100%; +} + +.histogram-y-labels { + height: 200px; + display: flex; + flex-direction: column; +} + +.histogram-y-label { + margin-right: 8px; + height: 25%; + text-align: right; +} + +.histogram-x-wrapper { + flex: 1 1 auto; + display: flex; + flex-direction: column; + margin-right: 8px; +} + +.histogram-x-labels { + display: flex; +} + +.histogram-x-label { + position: relative; + margin-top: 5px; + width: 100%; + text-align: right; +} + +.histogram-container { + margin-top: 9px; + position: relative; + height: 200px; +} + +.histogram-axes { + position: absolute; + width: 100%; + height: 100%; + border-bottom: 1px solid $histogram-chart-axis-color; + border-left: 1px solid $histogram-chart-axis-color; + pointer-events: none; +} + +.histogram-y-grid { + position: absolute; + border-bottom: 1px dashed $histogram-chart-grid-color; + width: 100%; +} + +.histogram-y-tick { + position: absolute; + border-bottom: 1px solid $histogram-chart-axis-color; + left: -5px; + height: 0px; + width: 5px; +} + +.histogram-x-grid { + position: absolute; + border-left: 1px dashed $histogram-chart-grid-color; + height: 100%; + width: 0; +} + +.histogram-x-tick { + position: absolute; + border-left: 1px solid $histogram-chart-axis-color; + height: 5px; + width: 0; + bottom: -5px; +} + +.histogram-bucket-slot { + position: absolute; + bottom: 0; + top: 0; +} + +.histogram-bucket { + position: absolute; + width: 100%; + bottom: 0; + background-color: #2db453; + border: 1px solid #77de94; + pointer-events: none; +} + +.histogram-bucket-slot:hover { + background-color: $histogram-chart-hover-color; +} + +.histogram-bucket-slot:hover .histogram-bucket { + background-color: #88e1a1; + border: 1px solid #77de94; +} + .custom-control-label { cursor: pointer; } @@ -151,7 +271,7 @@ input[type='checkbox']:checked + label { .alert { padding: 10px; - margin-bottom: .2rem; + margin-bottom: 0.2rem; } .nav-tabs .nav-link { @@ -364,14 +484,24 @@ input[type='checkbox']:checked + label { } @keyframes flamecolor { - 100% { - fill: #e95224; - } + 100% { + fill: #e95224; + } } @keyframes flame { - 0% { d: path("M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 8.712,-21.285 5.569,-29.308 3.059,0.249 6.331,6.456 6.552,16.161 3.252,-4.494 4.613,-12.701 4.613,-17.733 0,-5.21 3.433,-11.262 6.867,-11.469 -3.061,5.045 0.793,9.37 4.219,20.099 1.285,4.03 1.121,10.812 2.113,15.113 C 63.797,33.534 65.333,20.5 71,16 c -2.5,5.667 0.37,12.758 2.333,16.167 3.167,5.5 5.087,9.667 5.087,17.548 0,5.284 -1.951,10.259 -5.242,14.148 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z"); - } - 50% { d: path("M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 1.640181,-23.047128 7.294982,-29.291475 C 39.391377,29.509803 45.435,26.752 45.656,36.457 c 3.252,-4.494 7.100362,-8.366957 7.100362,-13.398957 0,-5.21 0.137393,-8.650513 -3.479689,-15.0672265 7.834063,1.6180944 8.448052,4.2381285 11.874052,14.9671285 1.285,4.03 1.325275,15.208055 2.317275,19.509055 0.329,-8.933 6.441001,-14.01461 5.163951,-21.391003 5.755224,5.771457 4.934508,10.495521 7.126537,14.288218 3.167,5.5 2.382625,7.496239 2.382625,15.377239 0,5.284 -1.672113,9.232546 -4.963113,13.121546 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z"); } - 100% { - d: path("M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 8.712,-21.285 5.569,-29.308 3.059,0.249 6.331,6.456 6.552,16.161 3.252,-4.494 4.613,-12.701 4.613,-17.733 0,-5.21 3.433,-11.262 6.867,-11.469 -3.061,5.045 0.793,9.37 4.219,20.099 1.285,4.03 1.121,10.812 2.113,15.113 C 63.797,33.534 65.333,20.5 71,16 c -2.5,5.667 0.37,12.758 2.333,16.167 3.167,5.5 5.087,9.667 5.087,17.548 0,5.284 -1.951,10.259 -5.242,14.148 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z"); } + 0% { + d: path( + 'M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 8.712,-21.285 5.569,-29.308 3.059,0.249 6.331,6.456 6.552,16.161 3.252,-4.494 4.613,-12.701 4.613,-17.733 0,-5.21 3.433,-11.262 6.867,-11.469 -3.061,5.045 0.793,9.37 4.219,20.099 1.285,4.03 1.121,10.812 2.113,15.113 C 63.797,33.534 65.333,20.5 71,16 c -2.5,5.667 0.37,12.758 2.333,16.167 3.167,5.5 5.087,9.667 5.087,17.548 0,5.284 -1.951,10.259 -5.242,14.148 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z' + ); + } + 50% { + d: path( + 'M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 1.640181,-23.047128 7.294982,-29.291475 C 39.391377,29.509803 45.435,26.752 45.656,36.457 c 3.252,-4.494 7.100362,-8.366957 7.100362,-13.398957 0,-5.21 0.137393,-8.650513 -3.479689,-15.0672265 7.834063,1.6180944 8.448052,4.2381285 11.874052,14.9671285 1.285,4.03 1.325275,15.208055 2.317275,19.509055 0.329,-8.933 6.441001,-14.01461 5.163951,-21.391003 5.755224,5.771457 4.934508,10.495521 7.126537,14.288218 3.167,5.5 2.382625,7.496239 2.382625,15.377239 0,5.284 -1.672113,9.232546 -4.963113,13.121546 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z' + ); + } + 100% { + d: path( + 'M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 8.712,-21.285 5.569,-29.308 3.059,0.249 6.331,6.456 6.552,16.161 3.252,-4.494 4.613,-12.701 4.613,-17.733 0,-5.21 3.433,-11.262 6.867,-11.469 -3.061,5.045 0.793,9.37 4.219,20.099 1.285,4.03 1.121,10.812 2.113,15.113 C 63.797,33.534 65.333,20.5 71,16 c -2.5,5.667 0.37,12.758 2.333,16.167 3.167,5.5 5.087,9.667 5.087,17.548 0,5.284 -1.951,10.259 -5.242,14.148 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z' + ); + } } diff --git a/web/ui/react-app/src/themes/dark.scss b/web/ui/react-app/src/themes/dark.scss index 0989c833ca..2212028947 100644 --- a/web/ui/react-app/src/themes/dark.scss +++ b/web/ui/react-app/src/themes/dark.scss @@ -19,6 +19,10 @@ $clear-time-btn-bg: $secondary; $checked-checkbox-color: #60a5fa; +$histogram-chart-axis-color: $gray-700; +$histogram-chart-grid-color: $gray-600; +$histogram-chart-hover-color: $gray-400; + .bootstrap-dark { @import './shared'; } diff --git a/web/ui/react-app/src/themes/light.scss b/web/ui/react-app/src/themes/light.scss index 8e6b10e804..c6f8a68d88 100644 --- a/web/ui/react-app/src/themes/light.scss +++ b/web/ui/react-app/src/themes/light.scss @@ -18,6 +18,10 @@ $clear-time-btn-bg: $white; $checked-checkbox-color: #286090; +$histogram-chart-axis-color: $gray-700; +$histogram-chart-grid-color: $gray-600; +$histogram-chart-hover-color: $gray-400; + .bootstrap { @import './shared'; } From 873677205331cccd94aa21a8f086e5282f82dfae Mon Sep 17 00:00:00 2001 From: Kartikay <120778728+kartikaysaxena@users.noreply.github.com> Date: Thu, 29 Feb 2024 21:01:13 +0530 Subject: [PATCH 082/253] web/api: add limit param on series, labels, label-values (#13396) Support limit parameter in queries to restrict output data to the specified size, on the following endpoints: /api/v1/series /api/v1/labels /api/v1/label/:name:/values Signed-off-by: Pranshu Srivastava Signed-off-by: Kartikay --- docs/querying/api.md | 3 +++ web/api/v1/api.go | 54 +++++++++++++++++++++++++++++++++++++++--- web/api/v1/api_test.go | 31 ++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/docs/querying/api.md b/docs/querying/api.md index 04ba3e8c6e..46e79181ed 100644 --- a/docs/querying/api.md +++ b/docs/querying/api.md @@ -256,6 +256,7 @@ URL query parameters: series to return. At least one `match[]` argument must be provided. - `start=`: Start timestamp. - `end=`: End timestamp. +- `limit=`: Maximum number of returned series. Optional. You can URL-encode these parameters directly in the request body by using the `POST` method and `Content-Type: application/x-www-form-urlencoded` header. This is useful when specifying a large @@ -306,6 +307,7 @@ URL query parameters: - `end=`: End timestamp. Optional. - `match[]=`: Repeated series selector argument that selects the series from which to read the label names. Optional. +- `limit=`: Maximum number of returned series. Optional. The `data` section of the JSON response is a list of string label names. @@ -356,6 +358,7 @@ URL query parameters: - `end=`: End timestamp. Optional. - `match[]=`: Repeated series selector argument that selects the series from which to read the label values. Optional. +- `limit=`: Maximum number of returned series. Optional. The `data` section of the JSON response is a list of string label values. diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 59e20004cd..48938fce12 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -644,6 +644,11 @@ func returnAPIError(err error) *apiError { } func (api *API) labelNames(r *http.Request) apiFuncResult { + limit, err := parseLimitParam(r.FormValue("limit")) + if err != nil { + return invalidParamError(err, "limit") + } + start, err := parseTimeParam(r, "start", MinTime) if err != nil { return invalidParamError(err, "start") @@ -703,6 +708,11 @@ func (api *API) labelNames(r *http.Request) apiFuncResult { if names == nil { names = []string{} } + + if len(names) >= limit { + names = names[:limit] + warnings = warnings.Add(errors.New("results truncated due to limit")) + } return apiFuncResult{names, nil, warnings, nil} } @@ -714,6 +724,11 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) { return apiFuncResult{nil, &apiError{errorBadData, fmt.Errorf("invalid label name: %q", name)}, nil, nil} } + limit, err := parseLimitParam(r.FormValue("limit")) + if err != nil { + return invalidParamError(err, "limit") + } + start, err := parseTimeParam(r, "start", MinTime) if err != nil { return invalidParamError(err, "start") @@ -783,6 +798,11 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) { slices.Sort(vals) + if len(vals) >= limit { + vals = vals[:limit] + warnings = warnings.Add(errors.New("results truncated due to limit")) + } + return apiFuncResult{vals, nil, warnings, closer} } @@ -809,6 +829,11 @@ func (api *API) series(r *http.Request) (result apiFuncResult) { return apiFuncResult{nil, &apiError{errorBadData, errors.New("no match[] parameter provided")}, nil, nil} } + limit, err := parseLimitParam(r.FormValue("limit")) + if err != nil { + return invalidParamError(err, "limit") + } + start, err := parseTimeParam(r, "start", MinTime) if err != nil { return invalidParamError(err, "start") @@ -860,11 +885,17 @@ func (api *API) series(r *http.Request) (result apiFuncResult) { } metrics := []labels.Labels{} - for set.Next() { - metrics = append(metrics, set.At().Labels()) - } warnings := set.Warnings() + + for set.Next() { + metrics = append(metrics, set.At().Labels()) + + if len(metrics) >= limit { + warnings.Add(errors.New("results truncated due to limit")) + return apiFuncResult{metrics, nil, warnings, closer} + } + } if set.Err() != nil { return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer} } @@ -1867,3 +1898,20 @@ OUTER: } return matcherSets, nil } + +func parseLimitParam(limitStr string) (limit int, err error) { + limit = math.MaxInt + if limitStr == "" { + return limit, nil + } + + limit, err = strconv.Atoi(limitStr) + if err != nil { + return limit, err + } + if limit <= 0 { + return limit, errors.New("limit must be positive") + } + + return limit, nil +} diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index d3013b2eef..eae4b9c64b 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -1389,6 +1389,16 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E }, }, // Missing match[] query params in series requests. + { + endpoint: api.series, + query: url.Values{ + "match[]": []string{"test_metric1"}, + "limit": []string{"1"}, + }, + response: []labels.Labels{ + labels.FromStrings("__name__", "test_metric1", "foo", "bar"), + }, + }, { endpoint: api.series, errType: errorBadData, @@ -2660,6 +2670,19 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E "boo", }, }, + { + endpoint: api.labelValues, + params: map[string]string{ + "name": "foo", + }, + query: url.Values{ + "match[]": []string{"test_metric4"}, + "limit": []string{"1"}, + }, + response: []string{ + "bar", + }, + }, // Label names. { endpoint: api.labelNames, @@ -2799,6 +2822,14 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E }, response: []string{"__name__", "foo"}, }, + { + endpoint: api.labelNames, + query: url.Values{ + "match[]": []string{"test_metric2"}, + "limit": []string{"1"}, + }, + response: []string{"__name__"}, + }, }...) } From 2e30f1231b6686e69afe1abb199c57dfe98fba07 Mon Sep 17 00:00:00 2001 From: Ondrej Kokes Date: Thu, 29 Feb 2024 16:40:53 +0100 Subject: [PATCH 083/253] docs: textparse.Parser return type mismatch The docs suggest the Next method returns a bool, but that's not the case (`Entry` is an int). ``` // Next advances the parser to the next sample. It returns false if no // more samples were read or an error occurred. Next() (Entry, error) ``` The docs were first added in d80a3de235b5f1349591420c55925d82ca49204e in 2017. Back then the signature was indeed `func (p *Parser) Next() bool`. But then it got refactored in 76a4a46cb0b78ab5b25f099693e9ddd23860a38d and the signature changed with it, yet docs stayed the same - and eventually made their way into the `Parser` interface. However, the Protobuf parser does have the right wording: 5de2df752f39de05c6ab53a9ec93f797027da0b9 ``` // Next advances the parser to the next "sample" (emulating the behavior of a // text format parser). It returns (EntryInvalid, io.EOF) if no samples were // read. ``` Changing all other implementations (and the interface itself) to match this doc. Signed-off-by: Ondrej Kokes --- model/textparse/interface.go | 4 ++-- model/textparse/openmetricsparse.go | 4 ++-- model/textparse/promparse.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/model/textparse/interface.go b/model/textparse/interface.go index 2e8c40e72f..df01dbc34f 100644 --- a/model/textparse/interface.go +++ b/model/textparse/interface.go @@ -71,8 +71,8 @@ type Parser interface { // if the scrape protocol or metric type does not support created timestamps. CreatedTimestamp() *int64 - // Next advances the parser to the next sample. It returns false if no - // more samples were read or an error occurred. + // Next advances the parser to the next sample. + // It returns (EntryInvalid, io.EOF) if no samples were read. Next() (Entry, error) } diff --git a/model/textparse/openmetricsparse.go b/model/textparse/openmetricsparse.go index ea92bc55f4..b7ad1dd85c 100644 --- a/model/textparse/openmetricsparse.go +++ b/model/textparse/openmetricsparse.go @@ -239,8 +239,8 @@ func (p *OpenMetricsParser) parseError(exp string, got token) error { return fmt.Errorf("%s, got %q (%q) while parsing: %q", exp, p.l.b[p.l.start:e], got, p.l.b[p.start:e]) } -// Next advances the parser to the next sample. It returns false if no -// more samples were read or an error occurred. +// Next advances the parser to the next sample. +// It returns (EntryInvalid, io.EOF) if no samples were read. func (p *OpenMetricsParser) Next() (Entry, error) { var err error diff --git a/model/textparse/promparse.go b/model/textparse/promparse.go index 54b5306e6a..a611f3aea7 100644 --- a/model/textparse/promparse.go +++ b/model/textparse/promparse.go @@ -280,8 +280,8 @@ func (p *PromParser) parseError(exp string, got token) error { return fmt.Errorf("%s, got %q (%q) while parsing: %q", exp, p.l.b[p.l.start:e], got, p.l.b[p.start:e]) } -// Next advances the parser to the next sample. It returns false if no -// more samples were read or an error occurred. +// Next advances the parser to the next sample. +// It returns (EntryInvalid, io.EOF) if no samples were read. func (p *PromParser) Next() (Entry, error) { var err error From e01e7d36e284857cd6b961cc1627bedbd62be890 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Thu, 29 Feb 2024 10:22:03 -0500 Subject: [PATCH 084/253] fix: restore ability to match __name__ multiple times in selector Add tests to cover this case. Signed-off-by: Owen Williams --- promql/parser/parse.go | 13 ----------- promql/parser/parse_test.go | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/promql/parser/parse.go b/promql/parser/parse.go index 6a05e4a792..eca4396524 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -791,20 +791,7 @@ func (p *parser) checkAST(node Node) (typ ValueType) { // Skip the check for non-empty matchers because an explicit // metric name is a non-empty matcher. break - } else { - // We also have to make sure a metric name was not set twice inside the - // braces. - foundMetricName := "" - for _, m := range n.LabelMatchers { - if m != nil && m.Name == labels.MetricName { - if foundMetricName != "" { - p.addParseErrf(n.PositionRange(), "metric name must not be set twice: %q or %q", foundMetricName, m.Value) - } - foundMetricName = m.Value - } - } } - // A Vector selector must contain at least one non-empty matcher to prevent // implicit selection of all metrics (e.g. by a typo). notEmpty := false diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index bd696ae969..48d7426538 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -1852,6 +1852,48 @@ var testExpr = []struct { }, }, }, + { + // Specifying __name__ twice inside the braces is ok. + input: `{__name__=~"bar", __name__!~"baz"}`, + expected: &VectorSelector{ + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchRegexp, model.MetricNameLabel, "bar"), + MustLabelMatcher(labels.MatchNotRegexp, model.MetricNameLabel, "baz"), + }, + PosRange: posrange.PositionRange{ + Start: 0, + End: 34, + }, + }, + }, + { + // Specifying __name__ with equality twice inside the braces is even allowed. + input: `{__name__="bar", __name__="baz"}`, + expected: &VectorSelector{ + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "bar"), + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "baz"), + }, + PosRange: posrange.PositionRange{ + Start: 0, + End: 32, + }, + }, + }, + { + // Because the above are allowed, this is also allowed. + input: `{"bar", __name__="baz"}`, + expected: &VectorSelector{ + LabelMatchers: []*labels.Matcher{ + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "bar"), + MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "baz"), + }, + PosRange: posrange.PositionRange{ + Start: 0, + End: 23, + }, + }, + }, { input: `{`, fail: true, @@ -1934,6 +1976,8 @@ var testExpr = []struct { fail: true, errMsg: "vector selector must contain at least one non-empty matcher", }, + // Although {"bar", __name__="baz"} is allowed (see above), specifying a + // metric name inside and outside the braces is not. { input: `foo{__name__="bar"}`, fail: true, From 7d364c0451957f24715541d58523e4795a8ebec4 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 14 Feb 2024 19:39:59 +0100 Subject: [PATCH 085/253] promql: remove redundant line Signed-off-by: beorn7 --- promql/engine.go | 1 - 1 file changed, 1 deletion(-) diff --git a/promql/engine.go b/promql/engine.go index 68e0502907..8619b7675a 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1221,7 +1221,6 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } - ev.samplesStats.UpdatePeak(ev.currentSamples) // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { From f46dd34982d94e4729d2327ba7fe701cb15474fe Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 28 Feb 2024 16:13:15 +0100 Subject: [PATCH 086/253] promql: Add code comment Signed-off-by: beorn7 --- promql/engine.go | 3 +++ promql/engine_test.go | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/promql/engine.go b/promql/engine.go index 8619b7675a..f4b95c3759 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1196,6 +1196,9 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) if prepSeries != nil { bufHelpers[i] = append(bufHelpers[i], seriesHelpers[i][si]) } + // Don't add histogram size here because we only + // copy the pointer above, not the whole + // histogram. ev.currentSamples++ if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) diff --git a/promql/engine_test.go b/promql/engine_test.go index 105108d5b2..e541957f26 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -755,6 +755,7 @@ load 10s metricWith3SampleEvery10Seconds{a="1",b="1"} 1+1x100 metricWith3SampleEvery10Seconds{a="2",b="2"} 1+1x100 metricWith3SampleEvery10Seconds{a="3",b="2"} 1+1x100 + metricWith1HistogramsEvery10Seconds {{schema:1 count:5 sum:20 buckets:[1 2 1 1]}}+{{schema:1 count:10 sum:5 buckets:[1 2 3 4]}}x100 `) t.Cleanup(func() { storage.Close() }) @@ -795,6 +796,15 @@ load 10s 21000: 1, }, }, + { + Query: "metricWith1HistogramEvery10Seconds", + Start: time.Unix(21, 0), + PeakSamples: 1, + TotalSamples: 1, // 1 sample / 10 seconds + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 21000: 1, + }, + }, { // timestamp function has a special handling. Query: "timestamp(metricWith1SampleEvery10Seconds)", @@ -1041,7 +1051,7 @@ load 10s End: time.Unix(220, 0), Interval: 5 * time.Second, PeakSamples: 5, - TotalSamples: 4, // (1 sample / 10 seconds) * 4 steps + TotalSamples: 4, // 1 sample per query * 4 steps TotalSamplesPerStep: stats.TotalSamplesPerStep{ 201000: 1, 206000: 1, From f48c7a5503a2da9d90c638c5aef14696cfbddbf1 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 28 Feb 2024 18:10:46 +0100 Subject: [PATCH 087/253] promql: Add histograms to TestQueryStatistics Also, fix the bugs exposed by the tests. Signed-off-by: beorn7 --- promql/engine.go | 63 +++++++++++++++++----------------- promql/engine_test.go | 80 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 38 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index f4b95c3759..151b8657a8 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1542,13 +1542,12 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio histSamples := totalHPointSize(ss.Histograms) if len(ss.Floats)+histSamples > 0 { - if ev.currentSamples+len(ss.Floats)+histSamples <= ev.maxSamples { - mat = append(mat, ss) - prevSS = &mat[len(mat)-1] - ev.currentSamples += len(ss.Floats) + histSamples - } else { + if ev.currentSamples+len(ss.Floats)+histSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } + mat = append(mat, ss) + prevSS = &mat[len(mat)-1] + ev.currentSamples += len(ss.Floats) + histSamples } ev.samplesStats.UpdatePeak(ev.currentSamples) @@ -1711,26 +1710,28 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio step++ _, f, h, ok := ev.vectorSelectorSingle(it, e, ts) if ok { - if ev.currentSamples < ev.maxSamples { - if h == nil { - if ss.Floats == nil { - ss.Floats = reuseOrGetFPointSlices(prevSS, numSteps) - } - ss.Floats = append(ss.Floats, FPoint{F: f, T: ts}) - ev.currentSamples++ - ev.samplesStats.IncrementSamplesAtStep(step, 1) - } else { - if ss.Histograms == nil { - ss.Histograms = reuseOrGetHPointSlices(prevSS, numSteps) - } - point := HPoint{H: h, T: ts} - ss.Histograms = append(ss.Histograms, point) - histSize := point.size() - ev.currentSamples += histSize - ev.samplesStats.IncrementSamplesAtStep(step, int64(histSize)) + if h == nil { + ev.currentSamples++ + ev.samplesStats.IncrementSamplesAtStep(step, 1) + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) } + if ss.Floats == nil { + ss.Floats = reuseOrGetFPointSlices(prevSS, numSteps) + } + ss.Floats = append(ss.Floats, FPoint{F: f, T: ts}) } else { - ev.error(ErrTooManySamples(env)) + point := HPoint{H: h, T: ts} + histSize := point.size() + ev.currentSamples += histSize + ev.samplesStats.IncrementSamplesAtStep(step, int64(histSize)) + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) + } + if ss.Histograms == nil { + ss.Histograms = reuseOrGetHPointSlices(prevSS, numSteps) + } + ss.Histograms = append(ss.Histograms, point) } } } @@ -2170,10 +2171,10 @@ loop: histograms = histograms[:n] continue loop } - if ev.currentSamples >= ev.maxSamples { + ev.currentSamples += histograms[n].size() + if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } - ev.currentSamples += histograms[n].size() } case chunkenc.ValFloat: t, f := buf.At() @@ -2182,10 +2183,10 @@ loop: } // Values in the buffer are guaranteed to be smaller than maxt. if t >= mintFloats { - if ev.currentSamples >= ev.maxSamples { + ev.currentSamples++ + if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } - ev.currentSamples++ if floats == nil { floats = getFPointSlice(16) } @@ -2213,22 +2214,22 @@ loop: histograms = histograms[:n] break } - if ev.currentSamples >= ev.maxSamples { + ev.currentSamples += histograms[n].size() + if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } - ev.currentSamples += histograms[n].size() case chunkenc.ValFloat: t, f := it.At() if t == maxt && !value.IsStaleNaN(f) { - if ev.currentSamples >= ev.maxSamples { + ev.currentSamples++ + if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } if floats == nil { floats = getFPointSlice(16) } floats = append(floats, FPoint{T: t, F: f}) - ev.currentSamples++ } } ev.samplesStats.UpdatePeak(ev.currentSamples) diff --git a/promql/engine_test.go b/promql/engine_test.go index e541957f26..cc5d0ee780 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -755,7 +755,7 @@ load 10s metricWith3SampleEvery10Seconds{a="1",b="1"} 1+1x100 metricWith3SampleEvery10Seconds{a="2",b="2"} 1+1x100 metricWith3SampleEvery10Seconds{a="3",b="2"} 1+1x100 - metricWith1HistogramsEvery10Seconds {{schema:1 count:5 sum:20 buckets:[1 2 1 1]}}+{{schema:1 count:10 sum:5 buckets:[1 2 3 4]}}x100 + metricWith1HistogramEvery10Seconds {{schema:1 count:5 sum:20 buckets:[1 2 1 1]}}+{{schema:1 count:10 sum:5 buckets:[1 2 3 4]}}x100 `) t.Cleanup(func() { storage.Close() }) @@ -799,10 +799,10 @@ load 10s { Query: "metricWith1HistogramEvery10Seconds", Start: time.Unix(21, 0), - PeakSamples: 1, - TotalSamples: 1, // 1 sample / 10 seconds + PeakSamples: 12, + TotalSamples: 12, // 1 histogram sample of size 12 / 10 seconds TotalSamplesPerStep: stats.TotalSamplesPerStep{ - 21000: 1, + 21000: 12, }, }, { @@ -815,6 +815,15 @@ load 10s 21000: 1, }, }, + { + Query: "timestamp(metricWith1HistogramEvery10Seconds)", + Start: time.Unix(21, 0), + PeakSamples: 13, // histogram size 12 + 1 extra because of timestamp + TotalSamples: 1, // 1 float sample (because of timestamp) / 10 seconds + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 21000: 1, + }, + }, { Query: "metricWith1SampleEvery10Seconds", Start: time.Unix(22, 0), @@ -887,11 +896,20 @@ load 10s 201000: 6, }, }, + { + Query: "metricWith1HistogramEvery10Seconds[60s]", + Start: time.Unix(201, 0), + PeakSamples: 72, + TotalSamples: 72, // 1 histogram (size 12) / 10 seconds * 60 seconds + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 201000: 72, + }, + }, { Query: "max_over_time(metricWith1SampleEvery10Seconds[59s])[20s:5s]", Start: time.Unix(201, 0), PeakSamples: 10, - TotalSamples: 24, // (1 sample / 10 seconds * 60 seconds) * 60/5 (using 59s so we always return 6 samples + TotalSamples: 24, // (1 sample / 10 seconds * 60 seconds) * 20/5 (using 59s so we always return 6 samples // as if we run a query on 00 looking back 60 seconds we will return 7 samples; // see next test). TotalSamplesPerStep: stats.TotalSamplesPerStep{ @@ -902,12 +920,22 @@ load 10s Query: "max_over_time(metricWith1SampleEvery10Seconds[60s])[20s:5s]", Start: time.Unix(201, 0), PeakSamples: 11, - TotalSamples: 26, // (1 sample / 10 seconds * 60 seconds) + 2 as + TotalSamples: 26, // (1 sample / 10 seconds * 60 seconds) * 4 + 2 as // max_over_time(metricWith1SampleEvery10Seconds[60s]) @ 190 and 200 will return 7 samples. TotalSamplesPerStep: stats.TotalSamplesPerStep{ 201000: 26, }, }, + { + Query: "max_over_time(metricWith1HistogramEvery10Seconds[60s])[20s:5s]", + Start: time.Unix(201, 0), + PeakSamples: 72, + TotalSamples: 312, // (1 histogram (size 12) / 10 seconds * 60 seconds) * 4 + 2 * 12 as + // max_over_time(metricWith1SampleEvery10Seconds[60s]) @ 190 and 200 will return 7 samples. + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 201000: 312, + }, + }, { Query: "metricWith1SampleEvery10Seconds[60s] @ 30", Start: time.Unix(201, 0), @@ -917,6 +945,15 @@ load 10s 201000: 4, }, }, + { + Query: "metricWith1HistogramEvery10Seconds[60s] @ 30", + Start: time.Unix(201, 0), + PeakSamples: 48, + TotalSamples: 48, // @ modifier force the evaluation to at 30 seconds - So it brings 4 datapoints (0, 10, 20, 30 seconds) * 1 series + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 201000: 48, + }, + }, { Query: "sum(max_over_time(metricWith3SampleEvery10Seconds[60s] @ 30))", Start: time.Unix(201, 0), @@ -1045,7 +1082,21 @@ load 10s }, }, { - // timestamp function as a special handling + Query: `metricWith1HistogramEvery10Seconds`, + Start: time.Unix(204, 0), + End: time.Unix(223, 0), + Interval: 5 * time.Second, + PeakSamples: 48, + TotalSamples: 48, // 1 histogram (size 12) per query * 4 steps + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 204000: 12, // aligned to the step time, not the sample time + 209000: 12, + 214000: 12, + 219000: 12, + }, + }, + { + // timestamp function has a special handling Query: "timestamp(metricWith1SampleEvery10Seconds)", Start: time.Unix(201, 0), End: time.Unix(220, 0), @@ -1059,6 +1110,21 @@ load 10s 216000: 1, }, }, + { + // timestamp function has a special handling + Query: "timestamp(metricWith1HistogramEvery10Seconds)", + Start: time.Unix(201, 0), + End: time.Unix(220, 0), + Interval: 5 * time.Second, + PeakSamples: 16, + TotalSamples: 4, // 1 sample per query * 4 steps + TotalSamplesPerStep: stats.TotalSamplesPerStep{ + 201000: 1, + 206000: 1, + 211000: 1, + 216000: 1, + }, + }, { Query: `max_over_time(metricWith3SampleEvery10Seconds{a="1"}[10s])`, Start: time.Unix(991, 0), From 4d4d822c36b7fdda555aec124eb7b031ed0daa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Fri, 1 Mar 2024 14:04:54 +0100 Subject: [PATCH 088/253] Add native histograms to latency/duration metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dogfood native histograms. Allow dependent projects to migrate to native histograms. I took the defaults from client_golang. Signed-off-by: György Krajcsovits --- .../remote_storage/remote_storage_adapter/main.go | 9 ++++++--- storage/remote/client.go | 13 ++++++++----- storage/remote/queue_manager.go | 15 +++++++++------ tsdb/compact.go | 9 ++++++--- tsdb/db.go | 7 +++++-- tsdb/head.go | 3 +++ web/web.go | 9 ++++++--- 7 files changed, 43 insertions(+), 22 deletions(-) diff --git a/documentation/examples/remote_storage/remote_storage_adapter/main.go b/documentation/examples/remote_storage/remote_storage_adapter/main.go index 85ef1839a1..bb348aba7f 100644 --- a/documentation/examples/remote_storage/remote_storage_adapter/main.go +++ b/documentation/examples/remote_storage/remote_storage_adapter/main.go @@ -83,9 +83,12 @@ var ( ) sentBatchDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Name: "sent_batch_duration_seconds", - Help: "Duration of sample batch send calls to the remote storage.", - Buckets: prometheus.DefBuckets, + Name: "sent_batch_duration_seconds", + Help: "Duration of sample batch send calls to the remote storage.", + Buckets: prometheus.DefBuckets, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }, []string{"remote"}, ) diff --git a/storage/remote/client.go b/storage/remote/client.go index e765b47c3e..5ba0f7117f 100644 --- a/storage/remote/client.go +++ b/storage/remote/client.go @@ -64,11 +64,14 @@ var ( ) remoteReadQueryDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "read_request_duration_seconds", - Help: "Histogram of the latency for remote read requests.", - Buckets: append(prometheus.DefBuckets, 25, 60), + Namespace: namespace, + Subsystem: subsystem, + Name: "read_request_duration_seconds", + Help: "Histogram of the latency for remote read requests.", + Buckets: append(prometheus.DefBuckets, 25, 60), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }, []string{remoteName, endpoint}, ) diff --git a/storage/remote/queue_manager.go b/storage/remote/queue_manager.go index 98e4aa54c1..01d2db06a5 100644 --- a/storage/remote/queue_manager.go +++ b/storage/remote/queue_manager.go @@ -214,12 +214,15 @@ func newQueueManagerMetrics(r prometheus.Registerer, rn, e string) *queueManager ConstLabels: constLabels, }) m.sentBatchDuration = prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "sent_batch_duration_seconds", - Help: "Duration of send calls to the remote storage.", - Buckets: append(prometheus.DefBuckets, 25, 60, 120, 300), - ConstLabels: constLabels, + Namespace: namespace, + Subsystem: subsystem, + Name: "sent_batch_duration_seconds", + Help: "Duration of send calls to the remote storage.", + Buckets: append(prometheus.DefBuckets, 25, 60, 120, 300), + ConstLabels: constLabels, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }) m.highestSentTimestamp = &maxTimestamp{ Gauge: prometheus.NewGauge(prometheus.GaugeOpts{ diff --git a/tsdb/compact.go b/tsdb/compact.go index b21ac4d317..3d8d9130c4 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -112,9 +112,12 @@ func newCompactorMetrics(r prometheus.Registerer) *CompactorMetrics { Help: "Total number of compactions done on overlapping blocks.", }) m.Duration = prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "prometheus_tsdb_compaction_duration_seconds", - Help: "Duration of compaction runs", - Buckets: prometheus.ExponentialBuckets(1, 2, 14), + Name: "prometheus_tsdb_compaction_duration_seconds", + Help: "Duration of compaction runs", + Buckets: prometheus.ExponentialBuckets(1, 2, 14), + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }) m.ChunkSize = prometheus.NewHistogram(prometheus.HistogramOpts{ Name: "prometheus_tsdb_compaction_chunk_size_bytes", diff --git a/tsdb/db.go b/tsdb/db.go index f29315517b..4998da6aa7 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -319,8 +319,11 @@ func newDBMetrics(db *DB, r prometheus.Registerer) *dbMetrics { return float64(db.blocks[0].meta.MinTime) }) m.tombCleanTimer = prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "prometheus_tsdb_tombstone_cleanup_seconds", - Help: "The time taken to recompact blocks to remove tombstones.", + Name: "prometheus_tsdb_tombstone_cleanup_seconds", + Help: "The time taken to recompact blocks to remove tombstones.", + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }) m.blocksBytes = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "prometheus_tsdb_storage_blocks_bytes", diff --git a/tsdb/head.go b/tsdb/head.go index dd2142e528..7e6fda9c7e 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -480,6 +480,9 @@ func newHeadMetrics(h *Head, r prometheus.Registerer) *headMetrics { 60 * 60 * 6, // 6h 60 * 60 * 12, // 12h }, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }), mmapChunksTotal: prometheus.NewCounter(prometheus.CounterOpts{ Name: "prometheus_tsdb_mmap_chunks_total", diff --git a/web/web.go b/web/web.go index 43b79c235d..a87759fb2e 100644 --- a/web/web.go +++ b/web/web.go @@ -123,9 +123,12 @@ func newMetrics(r prometheus.Registerer) *metrics { ), requestDuration: prometheus.NewHistogramVec( prometheus.HistogramOpts{ - Name: "prometheus_http_request_duration_seconds", - Help: "Histogram of latencies for HTTP requests.", - Buckets: []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, + Name: "prometheus_http_request_duration_seconds", + Help: "Histogram of latencies for HTTP requests.", + Buckets: []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + NativeHistogramMinResetDuration: 1 * time.Hour, }, []string{"handler"}, ), From d5ab1851dc52c046401353c679f8e3c87fcff440 Mon Sep 17 00:00:00 2001 From: Yuri Nikolic Date: Fri, 1 Mar 2024 14:49:42 +0100 Subject: [PATCH 089/253] SampleRingIterator: add currType field Signed-off-by: Yuri Nikolic --- storage/buffer.go | 53 ++++++++++++++++++++++------------- storage/buffer_test.go | 63 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 19 deletions(-) diff --git a/storage/buffer.go b/storage/buffer.go index b3c789e97d..545b7ed148 100644 --- a/storage/buffer.go +++ b/storage/buffer.go @@ -316,35 +316,40 @@ func (r *sampleRing) iterator() *SampleRingIterator { // SampleRingIterator is returned by BufferedSeriesIterator.Buffer() and can be // used to iterate samples buffered in the lookback window. type SampleRingIterator struct { - r *sampleRing - i int - t int64 - f float64 - h *histogram.Histogram - fh *histogram.FloatHistogram + r *sampleRing + i int + t int64 + f float64 + h *histogram.Histogram + fh *histogram.FloatHistogram + currType chunkenc.ValueType } func (it *SampleRingIterator) Next() chunkenc.ValueType { it.i++ + it.currType = chunkenc.ValNone if it.i >= it.r.l { - return chunkenc.ValNone + return it.currType } switch it.r.bufInUse { case fBuf: s := it.r.atF(it.i) it.t = s.t it.f = s.f - return chunkenc.ValFloat + it.currType = chunkenc.ValFloat case hBuf: s := it.r.atH(it.i) it.t = s.t it.h = s.h - return chunkenc.ValHistogram + it.currType = chunkenc.ValHistogram case fhBuf: s := it.r.atFH(it.i) it.t = s.t it.fh = s.fh - return chunkenc.ValFloatHistogram + it.currType = chunkenc.ValFloatHistogram + } + if it.currType != chunkenc.ValNone { + return it.currType } s := it.r.at(it.i) it.t = s.T() @@ -352,24 +357,31 @@ func (it *SampleRingIterator) Next() chunkenc.ValueType { case chunkenc.ValHistogram: it.h = s.H() it.fh = nil - return chunkenc.ValHistogram + it.currType = chunkenc.ValHistogram case chunkenc.ValFloatHistogram: it.fh = s.FH() it.h = nil - return chunkenc.ValFloatHistogram + it.currType = chunkenc.ValFloatHistogram default: it.f = s.F() - return chunkenc.ValFloat + it.currType = chunkenc.ValFloat } + return it.currType } // At returns the current float element of the iterator. func (it *SampleRingIterator) At() (int64, float64) { + if it.currType != chunkenc.ValFloat { + panic(fmt.Sprintf("SampleRingIterator: impossible to read a float, current value type is %v", it.currType)) + } return it.t, it.f } // AtHistogram returns the current histogram element of the iterator. func (it *SampleRingIterator) AtHistogram() (int64, *histogram.Histogram) { + if it.currType != chunkenc.ValHistogram { + panic(fmt.Sprintf("SampleRingIterator: impossible to read a histogram, current value type is %v", it.currType)) + } return it.t, it.h } @@ -378,14 +390,17 @@ func (it *SampleRingIterator) AtHistogram() (int64, *histogram.Histogram) { // An optional histogram.FloatHistogram can be provided to avoid allocating a new // object for the conversion. func (it *SampleRingIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) { - if it.fh == nil { - return it.t, it.h.ToFloat(fh) + if it.currType != chunkenc.ValHistogram && it.currType != chunkenc.ValFloatHistogram { + panic(fmt.Sprintf("SampleRingIterator: impossible to read a float histogram, current value type is %v", it.currType)) } - if fh != nil { - it.fh.CopyTo(fh) - return it.t, fh + if it.currType == chunkenc.ValFloatHistogram { + if fh != nil { + it.fh.CopyTo(fh) + return it.t, fh + } + return it.t, it.fh.Copy() } - return it.t, it.fh.Copy() + return it.t, it.h.ToFloat(fh) } func (it *SampleRingIterator) AtT() int64 { diff --git a/storage/buffer_test.go b/storage/buffer_test.go index 61074c2122..1b24e5da22 100644 --- a/storage/buffer_test.go +++ b/storage/buffer_test.go @@ -138,6 +138,69 @@ func TestSampleRingMixed(t *testing.T) { require.Equal(t, chunkenc.ValNone, it.Next()) } +func TestSampleRingAtFloatHistogram(t *testing.T) { + fh1 := tsdbutil.GenerateTestFloatHistogram(1) + fh2 := tsdbutil.GenerateTestFloatHistogram(2) + h1 := tsdbutil.GenerateTestHistogram(3) + h2 := tsdbutil.GenerateTestHistogram(4) + + // With ValNone as the preferred type, nothing should be initialized. + r := newSampleRing(10, 2, chunkenc.ValNone) + require.Zero(t, len(r.fBuf)) + require.Zero(t, len(r.hBuf)) + require.Zero(t, len(r.fhBuf)) + require.Zero(t, len(r.iBuf)) + + var ( + h *histogram.Histogram + fh *histogram.FloatHistogram + ts int64 + ) + + it := r.iterator() + require.Equal(t, chunkenc.ValNone, it.Next()) + + r.addFH(fhSample{t: 1, fh: fh1}) + r.addFH(fhSample{t: 2, fh: fh2}) + + it = r.iterator() + + require.Equal(t, chunkenc.ValFloatHistogram, it.Next()) + ts, fh = it.AtFloatHistogram(fh) + require.Equal(t, int64(1), ts) + require.Equal(t, fh1, fh) + require.Equal(t, chunkenc.ValFloatHistogram, it.Next()) + ts, fh = it.AtFloatHistogram(fh) + require.Equal(t, int64(2), ts) + require.Equal(t, fh2, fh) + require.Equal(t, chunkenc.ValNone, it.Next()) + + r.reset() + it = r.iterator() + require.Equal(t, chunkenc.ValNone, it.Next()) + + r.addH(hSample{t: 3, h: h1}) + r.addH(hSample{t: 4, h: h2}) + + it = r.iterator() + + require.Equal(t, chunkenc.ValHistogram, it.Next()) + ts, h = it.AtHistogram() + require.Equal(t, int64(3), ts) + require.Equal(t, h1, h) + ts, fh = it.AtFloatHistogram(fh) + require.Equal(t, int64(3), ts) + require.Equal(t, h1.ToFloat(nil), fh) + require.Equal(t, chunkenc.ValHistogram, it.Next()) + ts, h = it.AtHistogram() + require.Equal(t, int64(4), ts) + require.Equal(t, h2, h) + ts, fh = it.AtFloatHistogram(fh) + require.Equal(t, int64(4), ts) + require.Equal(t, h2.ToFloat(nil), fh) + require.Equal(t, chunkenc.ValNone, it.Next()) +} + func TestBufferedSeriesIterator(t *testing.T) { var it *BufferedSeriesIterator From c14419a38b7c37767624906fa4213879f2626f39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:20:31 +0000 Subject: [PATCH 090/253] build(deps): bump golangci/golangci-lint-action in /scripts Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.7.0 to 4.0.0. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/3a919529898de77ec3da873e3063ca4b10e7f5cc...3cfe3a4abbb849e10058ce4af15d205b6da42804) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- scripts/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/golangci-lint.yml b/scripts/golangci-lint.yml index 0e8515722f..4dc7b830f6 100644 --- a/scripts/golangci-lint.yml +++ b/scripts/golangci-lint.yml @@ -33,6 +33,6 @@ jobs: run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 with: version: v1.55.2 From e70b100ae8815d4b26c91ca4357a7c6b4c803e0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:44:11 +0000 Subject: [PATCH 091/253] build(deps): bump the go-opentelemetry-io group with 10 updates Bumps the go-opentelemetry-io group with 10 updates: | Package | From | To | | --- | --- | --- | | [go.opentelemetry.io/collector/featuregate](https://github.com/open-telemetry/opentelemetry-collector) | `1.0.1` | `1.2.0` | | [go.opentelemetry.io/collector/pdata](https://github.com/open-telemetry/opentelemetry-collector) | `1.0.1` | `1.2.0` | | [go.opentelemetry.io/collector/semconv](https://github.com/open-telemetry/opentelemetry-collector) | `0.93.0` | `0.95.0` | | [go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp](https://github.com/open-telemetry/opentelemetry-go-contrib) | `0.47.0` | `0.49.0` | | [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) | `1.22.0` | `1.24.0` | | [go.opentelemetry.io/otel/exporters/otlp/otlptrace](https://github.com/open-telemetry/opentelemetry-go) | `1.22.0` | `1.24.0` | | [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc](https://github.com/open-telemetry/opentelemetry-go) | `1.22.0` | `1.24.0` | | [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) | `1.22.0` | `1.24.0` | | [go.opentelemetry.io/otel/sdk](https://github.com/open-telemetry/opentelemetry-go) | `1.22.0` | `1.24.0` | | [go.opentelemetry.io/otel/trace](https://github.com/open-telemetry/opentelemetry-go) | `1.22.0` | `1.24.0` | Updates `go.opentelemetry.io/collector/featuregate` from 1.0.1 to 1.2.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-collector/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CHANGELOG-API.md) - [Commits](https://github.com/open-telemetry/opentelemetry-collector/compare/pdata/v1.0.1...pdata/v1.2.0) Updates `go.opentelemetry.io/collector/pdata` from 1.0.1 to 1.2.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-collector/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CHANGELOG-API.md) - [Commits](https://github.com/open-telemetry/opentelemetry-collector/compare/pdata/v1.0.1...pdata/v1.2.0) Updates `go.opentelemetry.io/collector/semconv` from 0.93.0 to 0.95.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-collector/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CHANGELOG-API.md) - [Commits](https://github.com/open-telemetry/opentelemetry-collector/compare/v0.93.0...v0.95.0) Updates `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` from 0.47.0 to 0.49.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go-contrib/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go-contrib/compare/zpages/v0.47.0...zpages/v0.49.0) Updates `go.opentelemetry.io/otel` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.22.0...v1.24.0) Updates `go.opentelemetry.io/otel/exporters/otlp/otlptrace` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.22.0...v1.24.0) Updates `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.22.0...v1.24.0) Updates `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.22.0...v1.24.0) Updates `go.opentelemetry.io/otel/sdk` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.22.0...v1.24.0) Updates `go.opentelemetry.io/otel/trace` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.22.0...v1.24.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/collector/featuregate dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/collector/pdata dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/collector/semconv dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/sdk dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/otel/trace dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io ... Signed-off-by: dependabot[bot] --- go.mod | 28 ++++++++++++++-------------- go.sum | 56 ++++++++++++++++++++++++++++---------------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index f2d3954428..ac33fc76d5 100644 --- a/go.mod +++ b/go.mod @@ -60,16 +60,16 @@ require ( github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c github.com/stretchr/testify v1.8.4 github.com/vultr/govultr/v2 v2.17.2 - go.opentelemetry.io/collector/featuregate v1.0.1 - go.opentelemetry.io/collector/pdata v1.0.1 - go.opentelemetry.io/collector/semconv v0.93.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 - go.opentelemetry.io/otel v1.22.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 - go.opentelemetry.io/otel/sdk v1.22.0 - go.opentelemetry.io/otel/trace v1.22.0 + go.opentelemetry.io/collector/featuregate v1.2.0 + go.opentelemetry.io/collector/pdata v1.2.0 + go.opentelemetry.io/collector/semconv v0.95.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 + go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 go.uber.org/atomic v1.11.0 go.uber.org/automaxprocs v1.5.3 go.uber.org/goleak v1.3.0 @@ -83,7 +83,7 @@ require ( golang.org/x/tools v0.17.0 google.golang.org/api v0.157.0 google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac - google.golang.org/grpc v1.61.0 + google.golang.org/grpc v1.61.1 google.golang.org/protobuf v1.32.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -142,7 +142,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.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 @@ -183,8 +183,8 @@ require ( github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.mongodb.org/mongo-driver v1.13.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect golang.org/x/crypto v0.19.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/term v0.17.0 // indirect diff --git a/go.sum b/go.sum index 7763694706..6ed3a69c98 100644 --- a/go.sum +++ b/go.sum @@ -399,8 +399,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 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.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8= @@ -801,30 +801,30 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= -go.opentelemetry.io/collector/featuregate v1.0.1/go.mod h1:QQXjP4etmJQhkQ20j4P/rapWuItYxoFozg/iIwuKnYg= -go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftbVCLzeyNvA= -go.opentelemetry.io/collector/pdata v1.0.1/go.mod h1:jutXeu0QOXYY8wcZ/hege+YAnSBP3+jpTqYU1+JTI5Y= -go.opentelemetry.io/collector/semconv v0.93.0 h1:eBlMcVNTwYYsVdAsCVDs4wvVYs75K1xcIDpqj16PG4c= -go.opentelemetry.io/collector/semconv v0.93.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/collector/featuregate v1.2.0 h1:nF8OGq5PsSNSLeuNwTWlOqThxbLW6v6DOCvSqQMc108= +go.opentelemetry.io/collector/featuregate v1.2.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A= +go.opentelemetry.io/collector/pdata v1.2.0 h1:N6VdyEFYJyoHIKqHd0F372eNVD5b+AbH0ZQf7Z2jJ9I= +go.opentelemetry.io/collector/pdata v1.2.0/go.mod h1:mKXb6527Syb8PT4P9CZOJNbkuHOHjjGTZNNwSKESJhc= +go.opentelemetry.io/collector/semconv v0.95.0 h1:Oa7NXmoatwKLS+RzuXtdjq9oXAeg8P0g3x238fKF0Do= +go.opentelemetry.io/collector/semconv v0.95.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -1201,8 +1201,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 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.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= 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= From af04032bfaec865752a95a948e64e52a49ac497e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:44:18 +0000 Subject: [PATCH 092/253] build(deps): bump golang.org/x/oauth2 from 0.16.0 to 0.17.0 Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.16.0 to 0.17.0. - [Commits](https://github.com/golang/oauth2/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f2d3954428..3455f20c62 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( go.uber.org/multierr v1.11.0 golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/net v0.21.0 - golang.org/x/oauth2 v0.16.0 + golang.org/x/oauth2 v0.17.0 golang.org/x/sync v0.6.0 golang.org/x/sys v0.17.0 golang.org/x/time v0.5.0 diff --git a/go.sum b/go.sum index 7763694706..907ae06a14 100644 --- a/go.sum +++ b/go.sum @@ -946,8 +946,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= From 091ad1c4108b2cabaa58304c18f79223a666d2f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:44:24 +0000 Subject: [PATCH 093/253] build(deps): bump actions/upload-artifact from 4.0.0 to 4.3.1 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.0.0 to 4.3.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/c7d193f32edcb7bfad88892161225aeda64e9392...5d5d22a31266ced268874388b861e4b58bb5c2f3) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/fuzzing.yml | 2 +- .github/workflows/scorecards.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 5997570607..4c19563eb4 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -21,7 +21,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a668a4ceb0..d81013c3d3 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -37,7 +37,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v4.0.0 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 with: name: SARIF file path: results.sarif From 3cb6752b34eb5750889e9c55f82343cf0cee4288 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:44:42 +0000 Subject: [PATCH 094/253] build(deps): bump github.com/prometheus/alertmanager Bumps [github.com/prometheus/alertmanager](https://github.com/prometheus/alertmanager) from 0.26.0 to 0.27.0. - [Release notes](https://github.com/prometheus/alertmanager/releases) - [Changelog](https://github.com/prometheus/alertmanager/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/alertmanager/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: github.com/prometheus/alertmanager dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++---- go.sum | 128 ++++++++------------------------------------------------- 2 files changed, 26 insertions(+), 118 deletions(-) diff --git a/go.mod b/go.mod index f2d3954428..9e0e1b15c8 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/oklog/run v1.1.0 github.com/oklog/ulid v1.3.1 github.com/ovh/go-ovh v1.4.3 - github.com/prometheus/alertmanager v0.26.0 + github.com/prometheus/alertmanager v0.27.0 github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.47.0 @@ -121,14 +121,14 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/analysis v0.22.2 // indirect github.com/go-openapi/errors v0.21.0 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // 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/validate v0.23.0 // indirect github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/golang-jwt/jwt/v5 v5.2.0 // indirect diff --git a/go.sum b/go.sum index 7763694706..35da077f33 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/KimMachineGun/automemlimit v0.5.0/go.mod h1:di3GCKiu9Y+1fs92erCbUvKzP github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -87,7 +85,6 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= @@ -136,7 +133,6 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -216,43 +212,24 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE9Vpj0= +github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo= github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +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/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= +github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8= +github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do= +github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +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/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.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -261,30 +238,6 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -373,7 +326,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -436,8 +388,8 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-sockaddr v1.0.6 h1:RSG8rKU28VTUTvEKghe5gIhIQpv8evvNpnDEyqO4u9I= +github.com/hashicorp/go-sockaddr v1.0.6/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -480,7 +432,6 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -500,8 +451,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -511,11 +460,9 @@ github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6K github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -529,13 +476,8 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U github.com/linode/linodego v1.29.0 h1:gDSQWAbKMAQX8db9FDCXHhodQPrJmLcmthjx6m+PyV4= github.com/linode/linodego v1.29.0/go.mod h1:3k6WvCM10gillgYcnoLqIL23ST27BD9HhMsCJWb3Bpk= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -573,8 +515,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= @@ -601,7 +541,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM= github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -643,7 +582,6 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -661,8 +599,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= -github.com/prometheus/alertmanager v0.26.0/go.mod h1:rVcnARltVjavgVaNnmevxK7kOn7IZavyf0KNgHkbEpU= +github.com/prometheus/alertmanager v0.27.0 h1:V6nTa2J5V4s8TG4C4HtrBP/WNSebCCTYGGv4qecA/+I= +github.com/prometheus/alertmanager v0.27.0/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -706,8 +644,6 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= @@ -728,8 +664,6 @@ github.com/simonpasquier/klog-gokit v0.3.0/go.mod h1:+SUlDQNrhVtGt2FieaqNftzzk8P github.com/simonpasquier/klog-gokit/v3 v3.3.0 h1:HMzH999kO5gEgJTaWWO+xjncW5oycspcsBnjn9b853Q= github.com/simonpasquier/klog-gokit/v3 v3.3.0/go.mod h1:uSbnWC3T7kt1dQyY9sjv0Ao1SehMAJdVnUNSKhjaDsg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -754,7 +688,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= @@ -762,7 +695,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -770,11 +702,7 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= @@ -787,9 +715,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -843,13 +768,11 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -931,7 +854,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY 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-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -952,7 +874,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -975,13 +896,10 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1014,7 +932,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1046,7 +963,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= @@ -1071,13 +987,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1221,7 +1133,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1246,9 +1157,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= From 0103ab8daa362e63f708042e5adc69b2f8070356 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:48:17 +0000 Subject: [PATCH 095/253] build(deps): bump github.com/influxdata/influxdb Bumps [github.com/influxdata/influxdb](https://github.com/influxdata/influxdb) from 1.11.4 to 1.11.5. - [Release notes](https://github.com/influxdata/influxdb/releases) - [Commits](https://github.com/influxdata/influxdb/compare/v1.11.4...v1.11.5) --- updated-dependencies: - dependency-name: github.com/influxdata/influxdb dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- documentation/examples/remote_storage/go.mod | 4 ++-- documentation/examples/remote_storage/go.sum | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index e7b5bb8be5..f35ee80ad7 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-kit/log v0.2.1 github.com/gogo/protobuf v1.3.2 github.com/golang/snappy v0.0.4 - github.com/influxdata/influxdb v1.11.4 + github.com/influxdata/influxdb v1.11.5 github.com/prometheus/client_golang v1.18.0 github.com/prometheus/common v0.46.0 github.com/prometheus/prometheus v0.48.1 @@ -58,7 +58,7 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.18.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sys v0.16.0 // indirect diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index 9b8208baa2..410c66f689 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -165,8 +165,8 @@ github.com/hetznercloud/hcloud-go/v2 v2.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyu github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= 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/influxdata/influxdb v1.11.4 h1:H3pVW+/tWQ4lkHhZxVQ13Ov1hmhHYaAzz8L5aq3ZNtw= -github.com/influxdata/influxdb v1.11.4/go.mod h1:VO6X2zlamfmEf+Esc9dR+7UQhdE/krspWNEZPwxCrp0= +github.com/influxdata/influxdb v1.11.5 h1:+em5VOl6lhAZubXj5o6SobCwvrRs3XDlBx/MUI4schI= +github.com/influxdata/influxdb v1.11.5/go.mod h1:k8sWREQl1/9t46VrkrH5adUM4UNGIt206ipO3plbkw8= github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -324,13 +324,13 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -360,8 +360,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ 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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.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= @@ -403,8 +403,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= From 3a5c07c51be2f82e64a59939c0b7057e0dd26794 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Mon, 4 Mar 2024 10:48:27 +0100 Subject: [PATCH 096/253] Bump hashicorp/nomand/api Update `github.com/hashicorp/nomad/api` now that we require Go 1.21. Signed-off-by: SuperQ --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index f2d3954428..4e88d1f7a3 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/consul/api v1.27.0 - github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c // Not upgrading this for now due to https://github.com/prometheus/prometheus/pull/13255#issuecomment-1845237409 + github.com/hashicorp/nomad/api v0.0.0-20240301140728-96acddbc131f github.com/hetznercloud/hcloud-go/v2 v2.6.0 github.com/ionos-cloud/sdk-go/v6 v6.1.11 github.com/json-iterator/go v1.1.12 diff --git a/go.sum b/go.sum index 7763694706..043ef3b7f4 100644 --- a/go.sum +++ b/go.sum @@ -457,8 +457,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 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-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= +github.com/hashicorp/nomad/api v0.0.0-20240301140728-96acddbc131f h1:cJPJco7rXUfY7QPpXGlklvyCctOTk0f76yRUJPeHEl0= +github.com/hashicorp/nomad/api v0.0.0-20240301140728-96acddbc131f/go.mod h1:z71gkJdrkAt/Rl6C7Q79VE7AwJ5lUF+M+fzFTyIHYB0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= @@ -718,8 +718,8 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2E github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shoenig/test v0.6.6 h1:Oe8TPH9wAbv++YPNDKJWUnI8Q4PPWCx3UbOfH+FxiMU= -github.com/shoenig/test v0.6.6/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shoenig/test v1.7.1 h1:UJcjSAI3aUKx52kfcfhblgyhZceouhvvs3OYdWgn+PY= +github.com/shoenig/test v1.7.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= From e28ed059afd90bf1094bc021b84752ec75c265a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:57:19 +0000 Subject: [PATCH 097/253] build(deps): bump github.com/stretchr/testify Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.4 to 1.9.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.8.4...v1.9.0) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- documentation/examples/remote_storage/go.mod | 2 +- documentation/examples/remote_storage/go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index f35ee80ad7..22a6116c8f 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -11,7 +11,7 @@ require ( github.com/prometheus/client_golang v1.18.0 github.com/prometheus/common v0.46.0 github.com/prometheus/prometheus v0.48.1 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 ) require ( diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index 410c66f689..fff62a45be 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -284,14 +284,14 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= From 1dc88dca88f40c423740c5ea19618acdeae63bcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:00:16 +0000 Subject: [PATCH 098/253] build(deps): bump actions/cache from 3.3.1 to 4.0.1 Bumps [actions/cache](https://github.com/actions/cache) from 3.3.1 to 4.0.1. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8...ab5e6d0c87105b4c9c2047343972218f562e4319) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8705b9d72d..4b7c726b83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -202,7 +202,7 @@ jobs: with: node-version-file: "web/ui/.nvmrc" registry-url: "https://registry.npmjs.org" - - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} From eb665988b0492812e1a5c691fac1c8ce1c0ad0e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:20:46 +0000 Subject: [PATCH 099/253] build(deps): bump google.golang.org/api from 0.157.0 to 0.167.0 Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.157.0 to 0.167.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.157.0...v0.167.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 8b6170a036..11f2c291c9 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/golang/snappy v0.0.4 github.com/google/go-cmp v0.6.0 github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 - github.com/google/uuid v1.5.0 + github.com/google/uuid v1.6.0 github.com/gophercloud/gophercloud v1.8.0 github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -81,8 +81,8 @@ require ( golang.org/x/sys v0.17.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.17.0 - google.golang.org/api v0.157.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac + google.golang.org/api v0.167.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 google.golang.org/grpc v1.61.1 google.golang.org/protobuf v1.32.0 gopkg.in/yaml.v2 v2.4.0 @@ -95,7 +95,7 @@ require ( ) require ( - cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go/compute v1.23.4 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect @@ -140,7 +140,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/gax-go/v2 v2.12.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect @@ -190,8 +190,8 @@ require ( golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gotest.tools/v3 v3.0.3 // indirect diff --git a/go.sum b/go.sum index 8d2747755e..0d6f5b95d0 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= +cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -327,14 +327,14 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.1 h1:9F8GV9r9ztXyAi00gsMQHNoF51xPZm8uj1dpYt2ZETM= +github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -1049,8 +1049,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.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.157.0 h1:ORAeqmbrrozeyw5NjnMxh7peHO0UzV4wWYSwZeCUb20= -google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g= +google.golang.org/api v0.167.0 h1:CKHrQD1BLRii6xdkatBDXyKzM0mkawt2QP+H3LtPmSE= +google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= 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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1089,12 +1089,12 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= +google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= From 61ce18950f168accd3bb9fb914feb68d007fcbb3 Mon Sep 17 00:00:00 2001 From: darshanime Date: Tue, 5 Mar 2024 00:45:07 +0530 Subject: [PATCH 100/253] Fix pipeline golangci-lint error Signed-off-by: darshanime --- notifier/notifier_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notifier/notifier_test.go b/notifier/notifier_test.go index 1c821b64b6..4f32994587 100644 --- a/notifier/notifier_test.go +++ b/notifier/notifier_test.go @@ -119,7 +119,7 @@ func newTestHTTPServerBuilder(expected *[]*Alert, errc chan<- error, u, p string b, err := io.ReadAll(r.Body) if err != nil { - err = fmt.Errorf("error reading body: %v", err) + err = fmt.Errorf("error reading body: %w", err) w.WriteHeader(http.StatusInternalServerError) return } From 7df0b9b92d5959b9ef14e8a1a6b5e7f357c126e9 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Tue, 5 Mar 2024 15:41:18 +0100 Subject: [PATCH 101/253] storage: simplify sampleRing fix Signed-off-by: beorn7 --- storage/buffer.go | 65 ++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/storage/buffer.go b/storage/buffer.go index 545b7ed148..651e5c83e8 100644 --- a/storage/buffer.go +++ b/storage/buffer.go @@ -306,50 +306,51 @@ func (r *sampleRing) reset() { r.iBuf = r.iBuf[:0] } -// Returns the current iterator. Invalidates previously returned iterators. +// Resets and returns the iterator. Invalidates previously returned iterators. func (r *sampleRing) iterator() *SampleRingIterator { - r.it.r = r - r.it.i = -1 + r.it.reset(r) return &r.it } // SampleRingIterator is returned by BufferedSeriesIterator.Buffer() and can be // used to iterate samples buffered in the lookback window. type SampleRingIterator struct { - r *sampleRing - i int - t int64 - f float64 - h *histogram.Histogram - fh *histogram.FloatHistogram - currType chunkenc.ValueType + r *sampleRing + i int + t int64 + f float64 + h *histogram.Histogram + fh *histogram.FloatHistogram +} + +func (it *SampleRingIterator) reset(r *sampleRing) { + it.r = r + it.i = -1 + it.h = nil + it.fh = nil } func (it *SampleRingIterator) Next() chunkenc.ValueType { it.i++ - it.currType = chunkenc.ValNone if it.i >= it.r.l { - return it.currType + return chunkenc.ValNone } switch it.r.bufInUse { case fBuf: s := it.r.atF(it.i) it.t = s.t it.f = s.f - it.currType = chunkenc.ValFloat + return chunkenc.ValFloat case hBuf: s := it.r.atH(it.i) it.t = s.t it.h = s.h - it.currType = chunkenc.ValHistogram + return chunkenc.ValHistogram case fhBuf: s := it.r.atFH(it.i) it.t = s.t it.fh = s.fh - it.currType = chunkenc.ValFloatHistogram - } - if it.currType != chunkenc.ValNone { - return it.currType + return chunkenc.ValFloatHistogram } s := it.r.at(it.i) it.t = s.T() @@ -357,31 +358,24 @@ func (it *SampleRingIterator) Next() chunkenc.ValueType { case chunkenc.ValHistogram: it.h = s.H() it.fh = nil - it.currType = chunkenc.ValHistogram + return chunkenc.ValHistogram case chunkenc.ValFloatHistogram: it.fh = s.FH() it.h = nil - it.currType = chunkenc.ValFloatHistogram + return chunkenc.ValFloatHistogram default: it.f = s.F() - it.currType = chunkenc.ValFloat + return chunkenc.ValFloat } - return it.currType } // At returns the current float element of the iterator. func (it *SampleRingIterator) At() (int64, float64) { - if it.currType != chunkenc.ValFloat { - panic(fmt.Sprintf("SampleRingIterator: impossible to read a float, current value type is %v", it.currType)) - } return it.t, it.f } // AtHistogram returns the current histogram element of the iterator. func (it *SampleRingIterator) AtHistogram() (int64, *histogram.Histogram) { - if it.currType != chunkenc.ValHistogram { - panic(fmt.Sprintf("SampleRingIterator: impossible to read a histogram, current value type is %v", it.currType)) - } return it.t, it.h } @@ -390,17 +384,14 @@ func (it *SampleRingIterator) AtHistogram() (int64, *histogram.Histogram) { // An optional histogram.FloatHistogram can be provided to avoid allocating a new // object for the conversion. func (it *SampleRingIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) { - if it.currType != chunkenc.ValHistogram && it.currType != chunkenc.ValFloatHistogram { - panic(fmt.Sprintf("SampleRingIterator: impossible to read a float histogram, current value type is %v", it.currType)) + if it.fh == nil { + return it.t, it.h.ToFloat(fh) } - if it.currType == chunkenc.ValFloatHistogram { - if fh != nil { - it.fh.CopyTo(fh) - return it.t, fh - } - return it.t, it.fh.Copy() + if fh != nil { + it.fh.CopyTo(fh) + return it.t, fh } - return it.t, it.h.ToFloat(fh) + return it.t, it.fh.Copy() } func (it *SampleRingIterator) AtT() int64 { From 4e77e8e5ef6e32027375732f8ce70d9702c42ea9 Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Wed, 6 Mar 2024 14:54:33 +1100 Subject: [PATCH 102/253] Allow using alternative PromQL engines for rule evaluation Signed-off-by: Charles Korn --- promql/engine.go | 7 +++++++ rules/manager.go | 2 +- web/api/v1/api.go | 11 ++--------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 68e0502907..0d37f184ee 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -115,6 +115,13 @@ func (e ErrStorage) Error() string { return e.Err.Error() } +// QueryEngine defines the interface for the *promql.Engine, so it can be replaced, wrapped or mocked. +type QueryEngine interface { + SetQueryLogger(l QueryLogger) + NewInstantQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, ts time.Time) (Query, error) + NewRangeQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) +} + // QueryLogger is an interface that can be used to log all the queries logged // by the engine. type QueryLogger interface { diff --git a/rules/manager.go b/rules/manager.go index e87d55b1e1..165dca144e 100644 --- a/rules/manager.go +++ b/rules/manager.go @@ -43,7 +43,7 @@ type QueryFunc func(ctx context.Context, q string, t time.Time) (promql.Vector, // EngineQueryFunc returns a new query function that executes instant queries against // the given engine. // It converts scalar into vector results. -func EngineQueryFunc(engine *promql.Engine, q storage.Queryable) QueryFunc { +func EngineQueryFunc(engine promql.QueryEngine, q storage.Queryable) QueryFunc { return func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) { q, err := engine.NewInstantQuery(ctx, q, nil, qs, t) if err != nil { diff --git a/web/api/v1/api.go b/web/api/v1/api.go index 48938fce12..b56026e45e 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -177,13 +177,6 @@ type TSDBAdminStats interface { WALReplayStatus() (tsdb.WALReplayStatus, error) } -// QueryEngine defines the interface for the *promql.Engine, so it can be replaced, wrapped or mocked. -type QueryEngine interface { - SetQueryLogger(l promql.QueryLogger) - NewInstantQuery(ctx context.Context, q storage.Queryable, opts promql.QueryOpts, qs string, ts time.Time) (promql.Query, error) - NewRangeQuery(ctx context.Context, q storage.Queryable, opts promql.QueryOpts, qs string, start, end time.Time, interval time.Duration) (promql.Query, error) -} - type QueryOpts interface { EnablePerStepStats() bool LookbackDelta() time.Duration @@ -193,7 +186,7 @@ type QueryOpts interface { // them using the provided storage and query engine. type API struct { Queryable storage.SampleAndChunkQueryable - QueryEngine QueryEngine + QueryEngine promql.QueryEngine ExemplarQueryable storage.ExemplarQueryable scrapePoolsRetriever func(context.Context) ScrapePoolsRetriever @@ -226,7 +219,7 @@ type API struct { // NewAPI returns an initialized API type. func NewAPI( - qe QueryEngine, + qe promql.QueryEngine, q storage.SampleAndChunkQueryable, ap storage.Appendable, eq storage.ExemplarQueryable, From 25f200bf85d2526eb77a77f6598ef0fbecc939a5 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 09:58:40 +0000 Subject: [PATCH 103/253] API tests: fix flaky TestEndpoints When a limit is specified, the API may return arbitrary rows, so don't check specific response values. Signed-off-by: Bryan Boreham --- web/api/v1/api_test.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index eae4b9c64b..6ccfdb5d7f 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -1054,7 +1054,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E params map[string]string query url.Values response interface{} - responseLen int + responseLen int // If nonzero, check only the length; `response` is ignored. responseMetadataTotal int responseAsJSON string errType errorType @@ -1388,17 +1388,16 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E labels.FromStrings("__name__", "test_metric2", "foo", "boo"), }, }, - // Missing match[] query params in series requests. + // Series request with limit. { endpoint: api.series, query: url.Values{ "match[]": []string{"test_metric1"}, "limit": []string{"1"}, }, - response: []labels.Labels{ - labels.FromStrings("__name__", "test_metric1", "foo", "bar"), - }, + responseLen: 1, // API does not specify which particular value will come back. }, + // Missing match[] query params in series requests. { endpoint: api.series, errType: errorBadData, @@ -2670,18 +2669,16 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E "boo", }, }, + // Label values with limit. { endpoint: api.labelValues, params: map[string]string{ - "name": "foo", + "name": "__name__", }, query: url.Values{ - "match[]": []string{"test_metric4"}, - "limit": []string{"1"}, - }, - response: []string{ - "bar", + "limit": []string{"2"}, }, + responseLen: 2, // API does not specify which particular values will come back. }, // Label names. { @@ -2822,13 +2819,13 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E }, response: []string{"__name__", "foo"}, }, + // Label names with limit. { endpoint: api.labelNames, query: url.Values{ - "match[]": []string{"test_metric2"}, - "limit": []string{"1"}, + "limit": []string{"2"}, }, - response: []string{"__name__"}, + responseLen: 2, // API does not specify which particular values will come back. }, }...) } From 63bc17ab9b29dc03290f4f9f6574892a2a15f990 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 10:32:11 +0000 Subject: [PATCH 104/253] CI: run main tests with --tags=stringlabels This is what we use for builds, so do the main testing (with -race) under that flag. Drop non-stringlabels tests from current Go version; previous Go version still runs them. Signed-off-by: Bryan Boreham --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b7c726b83..d71a4845c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,9 +16,8 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/setup_environment - - run: make GO_ONLY=1 SKIP_GOLANGCI_LINT=1 - - run: go test ./tsdb/ -test.tsdb-isolation=false - - run: go test --tags=stringlabels ./... + - run: make GOOPTS=--tags=stringlabels GO_ONLY=1 SKIP_GOLANGCI_LINT=1 + - run: go test --tags=stringlabels ./tsdb/ -test.tsdb-isolation=false - run: go test --tags=dedupelabels ./... - run: GOARCH=386 go test ./cmd/prometheus - run: make -C documentation/examples/remote_storage From 6998bfab59beecdbdaaf95c445eadd3dbd23769d Mon Sep 17 00:00:00 2001 From: machine424 Date: Tue, 5 Mar 2024 11:29:58 +0100 Subject: [PATCH 105/253] add a common-lint-fix make target to make golangci-lint fix found issues if it's supported by the linter clean up common-lint target Signed-off-by: machine424 --- Makefile.common | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile.common b/Makefile.common index 5fd1782371..92558151e3 100644 --- a/Makefile.common +++ b/Makefile.common @@ -169,12 +169,16 @@ common-vet: common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" -# 'go list' needs to be executed before staticcheck to prepopulate the modules cache. -# Otherwise staticcheck might fail randomly for some reason not yet explained. - $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) endif +.PHONY: common-lint-fix +common-lint-fix: $(GOLANGCI_LINT) +ifdef GOLANGCI_LINT + @echo ">> running golangci-lint fix" + $(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_OPTS) $(pkgs) +endif + .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" From 07355c9199e0913a76e1a992816e63b0683d16e7 Mon Sep 17 00:00:00 2001 From: Arthur Silva Sens Date: Wed, 6 Mar 2024 09:11:13 -0300 Subject: [PATCH 106/253] Bump client_golang to 1.19 Signed-off-by: Arthur Silva Sens --- cmd/prometheus/main.go | 3 ++- go.mod | 6 +++--- go.sum | 12 ++++++------ model/textparse/promparse_test.go | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index e36665857b..614d884637 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -42,6 +42,7 @@ import ( "github.com/mwitkow/go-conntrack" "github.com/oklog/run" "github.com/prometheus/client_golang/prometheus" + versioncollector "github.com/prometheus/client_golang/prometheus/collectors/version" "github.com/prometheus/common/model" "github.com/prometheus/common/promlog" promlogflag "github.com/prometheus/common/promlog/flag" @@ -99,7 +100,7 @@ var ( ) func init() { - prometheus.MustRegister(version.NewCollector(strings.ReplaceAll(appName, "-", "_"))) + prometheus.MustRegister(versioncollector.NewCollector(strings.ReplaceAll(appName, "-", "_"))) var err error defaultRetentionDuration, err = model.ParseDuration(defaultRetentionString) diff --git a/go.mod b/go.mod index 11f2c291c9..2a9dfffde2 100644 --- a/go.mod +++ b/go.mod @@ -50,9 +50,9 @@ require ( github.com/oklog/ulid v1.3.1 github.com/ovh/go-ovh v1.4.3 github.com/prometheus/alertmanager v0.27.0 - github.com/prometheus/client_golang v1.18.0 - github.com/prometheus/client_model v0.5.0 - github.com/prometheus/common v0.47.0 + github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/client_model v0.6.0 + github.com/prometheus/common v0.49.0 github.com/prometheus/common/assets v0.2.0 github.com/prometheus/common/sigv4 v0.1.0 github.com/prometheus/exporter-toolkit v0.11.0 diff --git a/go.sum b/go.sum index 0d6f5b95d0..18a4d08d30 100644 --- a/go.sum +++ b/go.sum @@ -608,16 +608,16 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= @@ -625,8 +625,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b 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.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.49.0 h1:ToNTdK4zSnPVJmh698mGFkDor9wBI/iGaJy5dbH1EgI= +github.com/prometheus/common v0.49.0/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= 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/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= diff --git a/model/textparse/promparse_test.go b/model/textparse/promparse_test.go index 204ea7d036..66986291d7 100644 --- a/model/textparse/promparse_test.go +++ b/model/textparse/promparse_test.go @@ -594,7 +594,7 @@ func BenchmarkParse(b *testing.B) { for i := 0; i < b.N; i += promtestdataSampleCount { decSamples := make(model.Vector, 0, 50) sdec := expfmt.SampleDecoder{ - Dec: expfmt.NewDecoder(bytes.NewReader(buf), expfmt.FmtText), + Dec: expfmt.NewDecoder(bytes.NewReader(buf), expfmt.NewFormat(expfmt.TypeTextPlain)), Opts: &expfmt.DecodeOptions{ Timestamp: model.TimeFromUnixNano(0), }, From bbe39af99f0ab5aa54959886f1d5b83bcf588f23 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 12:36:34 +0000 Subject: [PATCH 107/253] tsdb: zero out Labels and memSeries pointers in pool (#13712) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * tsdb: zero out Labels and memSeries pointers in pool So that the garbage-collector doesn't see this memory as still in use. Signed-off-by: Bryan Boreham --------- Signed-off-by: Bryan Boreham Signed-off-by: Björn Rabenstein Co-authored-by: Björn Rabenstein --- tsdb/head_append.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tsdb/head_append.go b/tsdb/head_append.go index a0bf987160..6342a19d46 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -229,6 +229,9 @@ func (h *Head) putExemplarBuffer(b []exemplarWithSeriesRef) { if b == nil { return } + for i := range b { // Zero out to avoid retaining label data. + b[i].exemplar.Labels = labels.EmptyLabels() + } h.exemplarsPool.Put(b[:0]) } @@ -278,6 +281,9 @@ func (h *Head) getSeriesBuffer() []*memSeries { } func (h *Head) putSeriesBuffer(b []*memSeries) { + for i := range b { // Zero out to avoid retaining data. + b[i] = nil + } h.seriesPool.Put(b[:0]) } From 5fc1bf1bf0f40d94ec52b33062aabd893d9e9d64 Mon Sep 17 00:00:00 2001 From: thirdkeyword Date: Wed, 6 Mar 2024 20:55:35 +0800 Subject: [PATCH 108/253] docs: fix some typos Signed-off-by: thirdkeyword --- docs/feature_flags.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/feature_flags.md b/docs/feature_flags.md index 04d9ff3654..a5dc69a718 100644 --- a/docs/feature_flags.md +++ b/docs/feature_flags.md @@ -99,9 +99,9 @@ When enabled, GOMAXPROCS variable is automatically set to match Linux container `--enable-feature=auto-gomemlimit` -When enabled, the GOMEMLIMIT variable is automatically set to match the Linux container memory limit. If there is no container limit, or the process is runing outside of containers, the system memory total is used. +When enabled, the GOMEMLIMIT variable is automatically set to match the Linux container memory limit. If there is no container limit, or the process is running outside of containers, the system memory total is used. -There is also an additional tuning flag, `--auto-gomemlimit.ratio`, which allows controling how much of the memory is used for Prometheus. The remainder is reserved for memory outside the process. For example, kernel page cache. Page cache is important for Prometheus TSDB query performance. The default is `0.9`, which means 90% of the memory limit will be used for Prometheus. +There is also an additional tuning flag, `--auto-gomemlimit.ratio`, which allows controlling how much of the memory is used for Prometheus. The remainder is reserved for memory outside the process. For example, kernel page cache. Page cache is important for Prometheus TSDB query performance. The default is `0.9`, which means 90% of the memory limit will be used for Prometheus. ## No default scrape port From bdfc309c61cf985807e9faefcaa287dd710198a9 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 18:03:49 +0000 Subject: [PATCH 109/253] Update to prometheus/common without Host member Commit 4199f18c3e92. Signed-off-by: Bryan Boreham --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2a9dfffde2..638a327009 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( github.com/prometheus/alertmanager v0.27.0 github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_model v0.6.0 - github.com/prometheus/common v0.49.0 + github.com/prometheus/common v0.49.1-0.20240306132007-4199f18c3e92 github.com/prometheus/common/assets v0.2.0 github.com/prometheus/common/sigv4 v0.1.0 github.com/prometheus/exporter-toolkit v0.11.0 diff --git a/go.sum b/go.sum index 18a4d08d30..2f9d63aabe 100644 --- a/go.sum +++ b/go.sum @@ -625,8 +625,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b 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.49.0 h1:ToNTdK4zSnPVJmh698mGFkDor9wBI/iGaJy5dbH1EgI= -github.com/prometheus/common v0.49.0/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= +github.com/prometheus/common v0.49.1-0.20240306132007-4199f18c3e92 h1:nuwTDY/15McImfuXcUD6AA3alpUNEXfWws8K/8SXr68= +github.com/prometheus/common v0.49.1-0.20240306132007-4199f18c3e92/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= 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/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= From 05fbc239306660eacb271178b8dfe933525b4da1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 18:27:01 +0000 Subject: [PATCH 110/253] CI: stop running codeql for Go It takes around 20 minutes and has never told us anything interesting. Signed-off-by: Bryan Boreham --- .github/workflows/codeql-analysis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9f665779a5..e271405209 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,14 +20,11 @@ jobs: strategy: fail-fast: false matrix: - language: ["go", "javascript"] + language: ["javascript"] steps: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 - with: - go-version: 1.22.x - name: Initialize CodeQL uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 From 864c99493264c600e654ba4b8a9ac3b8bc043008 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 19:05:53 +0000 Subject: [PATCH 111/253] CI: split Go tests into two parts, to run in parallel Signed-off-by: Bryan Boreham --- .github/workflows/ci.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae75a126ff..8251f960e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,10 +18,20 @@ jobs: - uses: ./.github/promci/actions/setup_environment - run: make GOOPTS=--tags=stringlabels GO_ONLY=1 SKIP_GOLANGCI_LINT=1 - run: go test --tags=stringlabels ./tsdb/ -test.tsdb-isolation=false - - run: go test --tags=dedupelabels ./... - - run: GOARCH=386 go test ./cmd/prometheus - run: make -C documentation/examples/remote_storage - run: make -C documentation/examples + + test_go_more: + name: More Go tests + runs-on: ubuntu-latest + container: + image: quay.io/prometheus/golang-builder:1.22-base + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: ./.github/promci/actions/setup_environment + - run: go test --tags=dedupelabels ./... + - run: GOARCH=386 go test ./cmd/prometheus - uses: ./.github/promci/actions/check_proto with: version: "3.15.8" From 7f912db15a77e58969420b76d20cb36607499fa7 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Thu, 7 Mar 2024 00:55:28 +0100 Subject: [PATCH 112/253] promql: Fix limiting of extrapolation to negative values This is a bit tough to explain, but I'll try: `rate` & friends have a sophisticated extrapolation algorithm. Usually, we extrapolate the result to the total interval specified in the range selector. However, if the first sample within the range is too far away from the beginning of the interval, or if the last sample within the range is too far away from the end of the interval, we assume the series has just started half a sampling interval before the first sample or after the last sample, respectively, and shorten the extrapolation interval correspondingly. We calculate the sampling interval by looking at the average time between samples within the range, and we define "too far away" as "more than 110% of that sampling interval". However, if this algorithm leads to an extrapolated starting value that is negative, we limit the start of the extrapolation interval to the point where the extrapolated starting value is zero. At least that was the intention. What we actually implemented is the following: If extrapolating all the way to the beginning of the total interval would lead to an extrapolated negative value, we would only extrapolate to the zero point as above, even if the algorithm above would have selected a starting point that is just half a sampling interval before the first sample and that starting point would not have an extrapolated negative value. In other word: What was meant as a _limitation_ of the extrapolation interval yielded a _longer_ extrapolation interval in this case. There is an exception to the case just described: If the increase of the extrapolation interval is more than 110% of the sampling interval, we suddenly drop back to only extrapolate to half a sampling interval. This behavior can be nicely seen in the testcounter_zero_cutoff test, where the rate goes up all the way to 0.7 and then jumps back to 0.6. This commit changes the behavior to what was (presumably) intended from the beginning: The extension of the extrapolation interval is only limited if actually needed to prevent extrapolation to negative values, but the "limitation" never leads to _more_ extrapolation anymore. The difference is subtle, and probably it never bothered anyone. However, if you calculate a rate of a classic histograms, the old behavior might create non-monotonic histograms as a result (because of the jumps you can see nicely in the old version of the testcounter_zero_cutoff test). With this fix, that doesn't happen anymore. Signed-off-by: beorn7 --- promql/functions.go | 43 +++++++++++++++++----------------- promql/testdata/functions.test | 29 +++++++++++++++++------ 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/promql/functions.go b/promql/functions.go index ae044d5961..da66af2f02 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -128,20 +128,6 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod sampledInterval := float64(lastT-firstT) / 1000 averageDurationBetweenSamples := sampledInterval / float64(numSamplesMinusOne) - // TODO(beorn7): Do this for histograms, too. - if isCounter && resultFloat > 0 && len(samples.Floats) > 0 && samples.Floats[0].F >= 0 { - // Counters cannot be negative. If we have any slope at all - // (i.e. resultFloat went up), we can extrapolate the zero point - // of the counter. If the duration to the zero point is shorter - // than the durationToStart, we take the zero point as the start - // of the series, thereby avoiding extrapolation to negative - // counter values. - durationToZero := sampledInterval * (samples.Floats[0].F / resultFloat) - if durationToZero < durationToStart { - durationToStart = durationToZero - } - } - // If the first/last samples are close to the boundaries of the range, // extrapolate the result. This is as we expect that another sample // will exist given the spacing between samples we've seen thus far, @@ -149,16 +135,29 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod extrapolationThreshold := averageDurationBetweenSamples * 1.1 extrapolateToInterval := sampledInterval - if durationToStart < extrapolationThreshold { - extrapolateToInterval += durationToStart - } else { - extrapolateToInterval += averageDurationBetweenSamples / 2 + if durationToStart >= extrapolationThreshold { + durationToStart = averageDurationBetweenSamples / 2 } - if durationToEnd < extrapolationThreshold { - extrapolateToInterval += durationToEnd - } else { - extrapolateToInterval += averageDurationBetweenSamples / 2 + if isCounter && resultFloat > 0 && len(samples.Floats) > 0 && samples.Floats[0].F >= 0 { + // Counters cannot be negative. If we have any slope at all + // (i.e. resultFloat went up), we can extrapolate the zero point + // of the counter. If the duration to the zero point is shorter + // than the durationToStart, we take the zero point as the start + // of the series, thereby avoiding extrapolation to negative + // counter values. + // TODO(beorn7): Do this for histograms, too. + durationToZero := sampledInterval * (samples.Floats[0].F / resultFloat) + if durationToZero < durationToStart { + durationToStart = durationToZero + } } + extrapolateToInterval += durationToStart + + if durationToEnd >= extrapolationThreshold { + durationToEnd = averageDurationBetweenSamples / 2 + } + extrapolateToInterval += durationToEnd + factor := extrapolateToInterval / sampledInterval if isRate { factor /= ms.Range.Seconds() diff --git a/promql/testdata/functions.test b/promql/testdata/functions.test index 4e104e406e..e01c75a7f6 100644 --- a/promql/testdata/functions.test +++ b/promql/testdata/functions.test @@ -71,15 +71,28 @@ clear load 5m http_requests{path="/foo"} 0+10x10 http_requests{path="/bar"} 0+10x5 0+10x5 + http_requests{path="/dings"} 10+10x10 + http_requests{path="/bumms"} 1+10x10 # Tests for increase(). eval instant at 50m increase(http_requests[50m]) - {path="/foo"} 100 - {path="/bar"} 90 + {path="/foo"} 100 + {path="/bar"} 90 + {path="/dings"} 100 + {path="/bumms"} 100 +# "foo" and "bar" are already at value 0 at t=0, so no extrapolation +# happens. "dings" has value 10 at t=0 and would reach 0 at t=-5m. The +# normal extrapolation by half a sample interval only goes to +# t=-2m30s, so that's not yet reaching a negative value and therefore +# chosen. However, "bumms" has value 1 at t=0 and would reach 0 at +# t=-30s. Here the extrapolation to t=-2m30s would reach a negative +# value, and therefore the extrapolation happens only by 30s. eval instant at 50m increase(http_requests[100m]) - {path="/foo"} 100 - {path="/bar"} 90 + {path="/foo"} 100 + {path="/bar"} 90 + {path="/dings"} 105 + {path="/bumms"} 101 clear @@ -133,13 +146,15 @@ load 4m testcounter_zero_cutoff{start="4m"} 240+240x10 testcounter_zero_cutoff{start="5m"} 300+240x10 -# Zero cutoff for left-side extrapolation. +# Zero cutoff for left-side extrapolation happens until we +# reach half a sampling interval (2m). Beyond that, we only +# extrapolate by half a sampling interval. eval instant at 10m rate(testcounter_zero_cutoff[20m]) {start="0m"} 0.5 {start="1m"} 0.55 {start="2m"} 0.6 - {start="3m"} 0.65 - {start="4m"} 0.7 + {start="3m"} 0.6 + {start="4m"} 0.6 {start="5m"} 0.6 # Normal half-interval cutoff for left-side extrapolation. From 3c2c9ac0675a342af59b28a35d2e28ec0fce99d1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 10:18:38 +0000 Subject: [PATCH 113/253] Update Go dependencies for v2.51 Simply make update-all-go-deps Signed-off-by: Bryan Boreham --- documentation/examples/remote_storage/go.mod | 69 ++--- documentation/examples/remote_storage/go.sum | 266 ++++++++++--------- go.mod | 69 +++-- go.sum | 149 +++++------ 4 files changed, 277 insertions(+), 276 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index 22a6116c8f..38497cbf50 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -8,68 +8,73 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/golang/snappy v0.0.4 github.com/influxdata/influxdb v1.11.5 - github.com/prometheus/client_golang v1.18.0 - github.com/prometheus/common v0.46.0 - github.com/prometheus/prometheus v0.48.1 + github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/common v0.49.0 + github.com/prometheus/prometheus v0.50.1 github.com/stretchr/testify v1.9.0 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect - github.com/aws/aws-sdk-go v1.45.25 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect + github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect + github.com/aws/aws-sdk-go v1.50.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dennwc/varint v1.0.0 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.5.0 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect + github.com/hashicorp/go-version v1.6.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.1 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect - go.opentelemetry.io/collector/semconv v0.87.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/collector/featuregate v1.0.1 // indirect + go.opentelemetry.io/collector/pdata v1.0.1 // indirect + go.opentelemetry.io/collector/semconv v0.93.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect - google.golang.org/grpc v1.58.3 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/grpc v1.61.0 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apimachinery v0.28.6 // indirect + k8s.io/client-go v0.28.6 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect ) exclude ( diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index fff62a45be..6ffa445b29 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -1,16 +1,17 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g= +github.com/Code-Hex/go-generics-cache v1.3.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= @@ -20,13 +21,15 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy 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-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= +github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= -github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI= +github.com/aws/aws-sdk-go v1.50.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= +github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -34,8 +37,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -43,32 +46,34 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= -github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= -github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= +github.com/digitalocean/godo v1.108.0 h1:fWyMENvtxpCpva1UbKzOFnyAS04N1FNuBWWfPeTGquQ= +github.com/digitalocean/godo v1.108.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= +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/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= +github.com/docker/docker v25.0.0+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= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -80,8 +85,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= @@ -90,16 +95,16 @@ github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2Kv github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= +github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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= @@ -111,6 +116,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -129,16 +135,16 @@ 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/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= -github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= +github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= -github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= +github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= +github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -155,20 +161,22 @@ github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZn github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= 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.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok= -github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= +github.com/hetznercloud/hcloud-go/v2 v2.6.0 h1:RJOA2hHZ7rD1pScA4O1NF6qhkHyUdbbxjHgFNot8928= +github.com/hetznercloud/hcloud-go/v2 v2.6.0/go.mod h1:4J1cSE57+g0WS93IiHLV7ubTHItcp+awzeBp5bM9mfA= 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/influxdata/influxdb v1.11.5 h1:+em5VOl6lhAZubXj5o6SobCwvrRs3XDlBx/MUI4schI= github.com/influxdata/influxdb v1.11.5/go.mod h1:k8sWREQl1/9t46VrkrH5adUM4UNGIt206ipO3plbkw8= -github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= -github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= +github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= +github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -186,8 +194,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= -github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -202,8 +210,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= -github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= +github.com/linode/linodego v1.27.1 h1:KoQm5g2fppw8qIClJqUEL0yKH0+f+7te3Mewagb5QKE= +github.com/linode/linodego v1.27.1/go.mod h1:5oAsx+uinHtVo6U77nXXXtox7MWzUW6aEkTOKXxA9uo= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -211,8 +219,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -237,8 +245,8 @@ github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrB github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -250,19 +258,19 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 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.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= -github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/common v0.49.0 h1:ToNTdK4zSnPVJmh698mGFkDor9wBI/iGaJy5dbH1EgI= +github.com/prometheus/common v0.49.0/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= 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= @@ -271,12 +279,12 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= -github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.50.1 h1:N2L+DYrxqPh4WZStU+o1p/gQlBaqFbcLBTjlp3vpdXw= +github.com/prometheus/prometheus v0.50.1/go.mod h1:FvE8dtQ1Ww63IlyKBn1V4s+zMwF9kHkVNkQBR1pM4CU= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2EmKy3yfUKHj3ZdfzYo= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -299,22 +307,24 @@ github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtX github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9Atxpk78bmtVdi15KhE= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= -go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= -go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/collector/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= +go.opentelemetry.io/collector/featuregate v1.0.1/go.mod h1:QQXjP4etmJQhkQ20j4P/rapWuItYxoFozg/iIwuKnYg= +go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftbVCLzeyNvA= +go.opentelemetry.io/collector/pdata v1.0.1/go.mod h1:jutXeu0QOXYY8wcZ/hege+YAnSBP3+jpTqYU1+JTI5Y= +go.opentelemetry.io/collector/semconv v0.93.0 h1:eBlMcVNTwYYsVdAsCVDs4wvVYs75K1xcIDpqj16PG4c= +go.opentelemetry.io/collector/semconv v0.93.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= 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/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -322,10 +332,10 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= -golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +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= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -346,13 +356,12 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 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.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= 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= @@ -360,8 +369,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ 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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.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= @@ -377,50 +386,48 @@ 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.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a h1:myvhA4is3vrit1a6NZCWBIwN0kNEnX21DJOJX/NvIfI= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= +google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= 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= @@ -451,22 +458,21 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.28.6 h1:yy6u9CuIhmg55YvF/BavPBBXB+5QicB64njJXxVnzLo= +k8s.io/api v0.28.6/go.mod h1:AM6Ys6g9MY3dl/XNaNfg/GePI0FT7WBGu8efU/lirAo= +k8s.io/apimachinery v0.28.6 h1:RsTeR4z6S07srPg6XYrwXpTJVMXsjPXn0ODakMytSW0= +k8s.io/apimachinery v0.28.6/go.mod h1:QFNX/kCl/EMT2WTSz8k4WLCv2XnkOLMaL8GAVRMdpsA= +k8s.io/client-go v0.28.6 h1:Gge6ziyIdafRchfoBKcpaARuz7jfrK1R1azuwORIsQI= +k8s.io/client-go v0.28.6/go.mod h1:+nu0Yp21Oeo/cBCsprNVXB2BfJTV51lFfe5tXl2rUL8= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/go.mod b/go.mod index 638a327009..971817eb48 100644 --- a/go.mod +++ b/go.mod @@ -3,19 +3,19 @@ module github.com/prometheus/prometheus go 1.21 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 github.com/Code-Hex/go-generics-cache v1.3.1 github.com/KimMachineGun/automemlimit v0.5.0 github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 - github.com/aws/aws-sdk-go v1.50.25 + github.com/aws/aws-sdk-go v1.50.32 github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 github.com/cespare/xxhash/v2 v2.2.0 github.com/dennwc/varint v1.0.0 - github.com/digitalocean/godo v1.108.0 + github.com/digitalocean/godo v1.109.0 github.com/docker/docker v25.0.3+incompatible github.com/edsrzf/mmap-go v1.1.0 github.com/envoyproxy/go-control-plane v0.12.0 @@ -24,22 +24,22 @@ require ( github.com/fsnotify/fsnotify v1.7.0 github.com/go-kit/log v0.2.1 github.com/go-logfmt/logfmt v0.6.0 - github.com/go-openapi/strfmt v0.22.0 + github.com/go-openapi/strfmt v0.22.2 github.com/go-zookeeper/zk v1.0.3 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-20240117000934-35fc243c5815 + github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 github.com/google/uuid v1.6.0 - github.com/gophercloud/gophercloud v1.8.0 + github.com/gophercloud/gophercloud v1.10.0 github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hashicorp/consul/api v1.27.0 - github.com/hashicorp/nomad/api v0.0.0-20240301140728-96acddbc131f + github.com/hashicorp/consul/api v1.28.2 + github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702 github.com/hetznercloud/hcloud-go/v2 v2.6.0 github.com/ionos-cloud/sdk-go/v6 v6.1.11 github.com/json-iterator/go v1.1.12 - github.com/klauspost/compress v1.17.4 + github.com/klauspost/compress v1.17.7 github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b github.com/linode/linodego v1.29.0 github.com/miekg/dns v1.1.58 @@ -56,13 +56,13 @@ require ( github.com/prometheus/common/assets v0.2.0 github.com/prometheus/common/sigv4 v0.1.0 github.com/prometheus/exporter-toolkit v0.11.0 - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/vultr/govultr/v2 v2.17.2 - go.opentelemetry.io/collector/featuregate v1.2.0 - go.opentelemetry.io/collector/pdata v1.2.0 - go.opentelemetry.io/collector/semconv v0.95.0 + go.opentelemetry.io/collector/featuregate v1.3.0 + go.opentelemetry.io/collector/pdata v1.3.0 + go.opentelemetry.io/collector/semconv v0.96.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 go.opentelemetry.io/otel v1.24.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 @@ -75,16 +75,16 @@ require ( go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/net v0.21.0 - golang.org/x/oauth2 v0.17.0 + golang.org/x/net v0.22.0 + golang.org/x/oauth2 v0.18.0 golang.org/x/sync v0.6.0 - golang.org/x/sys v0.17.0 + golang.org/x/sys v0.18.0 golang.org/x/time v0.5.0 - golang.org/x/tools v0.17.0 - google.golang.org/api v0.167.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 - google.golang.org/grpc v1.61.1 - google.golang.org/protobuf v1.32.0 + golang.org/x/tools v0.19.0 + google.golang.org/api v0.168.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 + google.golang.org/grpc v1.62.1 + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.29.2 @@ -97,7 +97,7 @@ require ( require ( cloud.google.com/go/compute v1.23.4 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect @@ -105,7 +105,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cilium/ebpf v0.11.0 // indirect - github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 // indirect + github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -122,7 +122,7 @@ require ( github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.22.2 // indirect - github.com/go-openapi/errors v0.21.0 // indirect + github.com/go-openapi/errors v0.21.1 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/loads v0.21.5 // indirect @@ -132,7 +132,7 @@ require ( github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/golang-jwt/jwt/v5 v5.2.0 // indirect - github.com/golang/glog v1.1.2 // indirect + github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect @@ -140,7 +140,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.1 // indirect + github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect @@ -179,19 +179,18 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - go.mongodb.org/mongo-driver v1.13.1 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gotest.tools/v3 v3.0.3 // indirect diff --git a/go.sum b/go.sum index 2f9d63aabe..dee9a16e26 100644 --- a/go.sum +++ b/go.sum @@ -34,14 +34,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 h1:MxA59PGoCFb+vCwRQi3PhQEwHj4+r2dhuv9HG+vM7iM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= @@ -90,8 +90,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.50.25 h1:vhiHtLYybv1Nhx3Kv18BBC6L0aPJHaG9aeEsr92W99c= -github.com/aws/aws-sdk-go v1.50.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.50.32 h1:POt81DvegnpQKM4DMDLlHz1CO6OBnEoQ1gRhYFd7QRY= +github.com/aws/aws-sdk-go v1.50.32/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0= @@ -118,8 +118,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= @@ -141,8 +141,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/digitalocean/godo v1.108.0 h1:fWyMENvtxpCpva1UbKzOFnyAS04N1FNuBWWfPeTGquQ= -github.com/digitalocean/godo v1.108.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= +github.com/digitalocean/godo v1.109.0 h1:4W97RJLJSUQ3veRZDNbp1Ol3Rbn6Lmt9bKGvfqYI5SU= +github.com/digitalocean/godo v1.109.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= 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= @@ -214,8 +214,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.22.2 h1:ZBmNoP2h5omLKr/srIC9bfqrUGzT6g6gNv03HE9Vpj0= github.com/go-openapi/analysis v0.22.2/go.mod h1:pDF4UbZsQTo/oNuRfAWWd4dAh4yuYf//LYorPTjrpvo= -github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= -github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho= +github.com/go-openapi/errors v0.21.1 h1:rVisxQPdETctjlYntm0Ek4dKf68nAQocCloCT50vWuI= +github.com/go-openapi/errors v0.21.1/go.mod h1:LyiY9bgc7AVVh6wtVvMYEyoj3KJYNoRw92mmvnMWgj8= 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/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= @@ -224,8 +224,8 @@ github.com/go-openapi/loads v0.21.5 h1:jDzF4dSoHw6ZFADCGltDb2lE4F6De7aWSpe+IcsRz github.com/go-openapi/loads v0.21.5/go.mod h1:PxTsnFBoBe+z89riT+wYt3prmSBP6GDAQh2l9H1Flz8= github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do= github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= -github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= -github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= +github.com/go-openapi/strfmt v0.22.2 h1:DPYOrm6gexCfZZfXUaXFS4+Jw6HAaIIG0SZ5630f8yw= +github.com/go-openapi/strfmt v0.22.2/go.mod h1:HB/b7TCm91rno75Dembc1dFW/0FPLk5CEXsoF9ReNc4= 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/validate v0.23.0 h1:2l7PJLzCis4YUGEoW6eoQw3WhyM65WSIcjX6SQnlfDw= @@ -249,8 +249,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -283,7 +283,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -320,8 +319,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8= -github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -333,10 +332,10 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.1 h1:9F8GV9r9ztXyAi00gsMQHNoF51xPZm8uj1dpYt2ZETM= -github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= -github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= +github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/gophercloud/gophercloud v1.10.0 h1:watRMsaMDlSLuLkpLeLSQ87yvcuwIajNg6A5uLcjoIU= +github.com/gophercloud/gophercloud v1.10.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -354,11 +353,11 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= -github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8= +github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= +github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.15.1 h1:kKIGxc7CZtflcF5DLfHeq7rOQmRq3vk7kwISN9bif8Q= -github.com/hashicorp/consul/sdk v0.15.1/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -409,8 +408,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 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-20240301140728-96acddbc131f h1:cJPJco7rXUfY7QPpXGlklvyCctOTk0f76yRUJPeHEl0= -github.com/hashicorp/nomad/api v0.0.0-20240301140728-96acddbc131f/go.mod h1:z71gkJdrkAt/Rl6C7Q79VE7AwJ5lUF+M+fzFTyIHYB0= +github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702 h1:fI1LXuBaS1d9z1kmb++Og6YD8uMRwadXorCwE+xgOFA= +github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702/go.mod h1:z71gkJdrkAt/Rl6C7Q79VE7AwJ5lUF+M+fzFTyIHYB0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= @@ -454,9 +453,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -526,7 +524,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -650,8 +647,8 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2EmKy3yfUKHj3ZdfzYo= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 h1:/8rfZAdFfafRXOgz+ZpMZZWZ5pYggCY9t7e/BvjaBHM= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shoenig/test v1.7.1 h1:UJcjSAI3aUKx52kfcfhblgyhZceouhvvs3OYdWgn+PY= @@ -683,8 +680,9 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -693,21 +691,17 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -715,8 +709,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= -go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= +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.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -726,12 +720,12 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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/featuregate v1.2.0 h1:nF8OGq5PsSNSLeuNwTWlOqThxbLW6v6DOCvSqQMc108= -go.opentelemetry.io/collector/featuregate v1.2.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A= -go.opentelemetry.io/collector/pdata v1.2.0 h1:N6VdyEFYJyoHIKqHd0F372eNVD5b+AbH0ZQf7Z2jJ9I= -go.opentelemetry.io/collector/pdata v1.2.0/go.mod h1:mKXb6527Syb8PT4P9CZOJNbkuHOHjjGTZNNwSKESJhc= -go.opentelemetry.io/collector/semconv v0.95.0 h1:Oa7NXmoatwKLS+RzuXtdjq9oXAeg8P0g3x238fKF0Do= -go.opentelemetry.io/collector/semconv v0.95.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs= +go.opentelemetry.io/collector/featuregate v1.3.0 h1:nrFSx+zfjdisjE9oCx25Aep3nJ9RaUjeE1qFL6eovoU= +go.opentelemetry.io/collector/featuregate v1.3.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A= +go.opentelemetry.io/collector/pdata v1.3.0 h1:JRYN7tVHYFwmtQhIYbxWeiKSa2L1nCohyAs8sYqKFZo= +go.opentelemetry.io/collector/pdata v1.3.0/go.mod h1:t7W0Undtes53HODPdSujPLTnfSR5fzT+WpL+RTaaayo= +go.opentelemetry.io/collector/semconv v0.96.0 h1:DrZy8BpzJDnN2zFxXRj6BhfGYxNlqpFHBqyuS9fVHRY= +go.opentelemetry.io/collector/semconv v0.96.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= @@ -775,11 +769,10 @@ 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -814,8 +807,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -860,16 +853,16 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= @@ -949,15 +942,15 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1028,8 +1021,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -1049,8 +1042,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.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.167.0 h1:CKHrQD1BLRii6xdkatBDXyKzM0mkawt2QP+H3LtPmSE= -google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= +google.golang.org/api v0.168.0 h1:MBRe+Ki4mMN93jhDDbpuRLjRddooArz4FeSObvUMmjY= +google.golang.org/api v0.168.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= 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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1089,12 +1082,10 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1113,8 +1104,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 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.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= -google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= @@ -1127,8 +1118,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 34a655716e72913efc0dc8c9e6601215d65448ca Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 6 Mar 2024 19:04:30 +0000 Subject: [PATCH 114/253] Back off google.golang.org/protobuf to v1.32.0 Otherwise we get a compilation error. Signed-off-by: Bryan Boreham --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 971817eb48..15e7f2206a 100644 --- a/go.mod +++ b/go.mod @@ -84,7 +84,7 @@ require ( google.golang.org/api v0.168.0 google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.33.0 + google.golang.org/protobuf v1.32.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.29.2 diff --git a/go.sum b/go.sum index dee9a16e26..f220b6d483 100644 --- a/go.sum +++ b/go.sum @@ -1118,8 +1118,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 28f8a346bcddbb284626d5612efca6934a54231b Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 7 Mar 2024 10:13:44 +0000 Subject: [PATCH 115/253] Wind back gophercloud to 1.8.0 It triggers a failure in TestOpenstackSDInstanceRefresh. Signed-off-by: Bryan Boreham --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 15e7f2206a..8039a16af4 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 github.com/google/uuid v1.6.0 - github.com/gophercloud/gophercloud v1.10.0 + github.com/gophercloud/gophercloud v1.8.0 github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/consul/api v1.28.2 diff --git a/go.sum b/go.sum index f220b6d483..599f22a1f7 100644 --- a/go.sum +++ b/go.sum @@ -334,8 +334,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/gophercloud/gophercloud v1.10.0 h1:watRMsaMDlSLuLkpLeLSQ87yvcuwIajNg6A5uLcjoIU= -github.com/gophercloud/gophercloud v1.10.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= +github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= From 57c799132b8d5b3bc1c0d5489653a789ccb617dc Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 09:14:22 +0000 Subject: [PATCH 116/253] Notifier: don't reuse payload after relabeling Also clarify why these variables are being cleared. Signed-off-by: Bryan Boreham --- notifier/notifier.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/notifier/notifier.go b/notifier/notifier.go index a6a99f4135..82c489a2ed 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -481,14 +481,11 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { if len(ams.cfg.AlertRelabelConfigs) > 0 { amAlerts = relabelAlerts(ams.cfg.AlertRelabelConfigs, labels.Labels{}, alerts) - // TODO(nabokihms): figure out the right way to cache marshalled alerts. - // Now it works well only for happy cases. - v1Payload = nil - v2Payload = nil - if len(amAlerts) == 0 { continue } + // We can't use the cached values from previous iteration. + v1Payload, v2Payload = nil, nil } switch ams.cfg.APIVersion { @@ -531,6 +528,11 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { } } + if len(ams.cfg.AlertRelabelConfigs) > 0 { + // We can't use the cached values on the next iteration. + v1Payload, v2Payload = nil, nil + } + for _, am := range ams.ams { wg.Add(1) From 8c4e4b72a8b54ef66d71de76461c719957bf51cc Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 09:20:36 +0000 Subject: [PATCH 117/253] Notifier: pass parameters to goroutine explicitly Avoids possible false sharing between loops. Plausibly there is no problem in the current code, but it's easy enough to write it more safely. Signed-off-by: Bryan Boreham --- notifier/notifier.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notifier/notifier.go b/notifier/notifier.go index 82c489a2ed..d1832402f7 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -539,9 +539,9 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { ctx, cancel := context.WithTimeout(n.ctx, time.Duration(ams.cfg.Timeout)) defer cancel() - go func(client *http.Client, url string) { + go func(ctx context.Context, client *http.Client, url string, payload []byte, count int) { if err := n.sendOne(ctx, client, url, payload); err != nil { - level.Error(n.logger).Log("alertmanager", url, "count", len(amAlerts), "msg", "Error sending alert", "err", err) + level.Error(n.logger).Log("alertmanager", url, "count", count, "msg", "Error sending alert", "err", err) n.metrics.errors.WithLabelValues(url).Inc() } else { numSuccess.Inc() @@ -550,7 +550,7 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { n.metrics.sent.WithLabelValues(url).Add(float64(len(amAlerts))) wg.Done() - }(ams.client, am.url().String()) + }(ctx, ams.client, am.url().String(), payload, len(amAlerts)) } ams.mtx.RUnlock() From 6c41ec984f9bb19bba38e9429de7dff620cdf109 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 10:18:18 +0000 Subject: [PATCH 118/253] [BUGFIX] Scraping: Tolerance should be max 1% of interval Previous code set it at minimum 1%, which was not intended. Signed-off-by: Bryan Boreham --- scrape/scrape.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scrape/scrape.go b/scrape/scrape.go index 11006dc243..f6f3367736 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -1218,10 +1218,8 @@ mainLoop: // and .Add on time.Time behave differently (see time package docs). scrapeTime := time.Now().Round(0) if AlignScrapeTimestamps { - tolerance := ScrapeTimestampTolerance - if maxTolerance := sl.interval / 100; tolerance < maxTolerance { - tolerance = maxTolerance - } + // Tolerance is clamped to maximum 1% of the scrape interval. + tolerance := min(sl.interval/100, ScrapeTimestampTolerance) // For some reason, a tick might have been skipped, in which case we // would call alignedScrapeTime.Add(interval) multiple times. for scrapeTime.Sub(alignedScrapeTime) >= sl.interval { From e54082a62143952f0ab717f5387e9f3ecd15aba2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 10:37:28 +0000 Subject: [PATCH 119/253] CI: don't run race-detector on tests with previous Go version The purpose of running with a previous Go version is to spot usage of new language features; we don't need to intensively look for bugs. Signed-off-by: Bryan Boreham --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8251f960e9..2e4b628699 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,8 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - run: make build - - run: make test GO_ONLY=1 + # Don't run NPM build; don't run race-detector. + - run: make test GO_ONLY=1 test-flags="" test_ui: name: UI tests From eea6ab1cdd24ec69c94ba4b0d165030c89860c8b Mon Sep 17 00:00:00 2001 From: michaelact <86778470+michaelact@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:19:39 +0700 Subject: [PATCH 120/253] [BUGFIX] Azure SD: Fix 'error: parameter virtualMachineScaleSetName cannot be empty' (#13702) Erroneous code was introduced during a merge-back-to-main at #13399. Signed-off-by: michaelact <86778470+michaelact@users.noreply.github.com> --- discovery/azure/azure.go | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index a5d81f4ff6..16628c7bfd 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -413,26 +413,20 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { } else { networkInterface, err = client.getVMScaleSetVMNetworkInterfaceByID(ctx, nicID, vm.ScaleSet, vm.InstanceID) } + if err != nil { if errors.Is(err, errorNotFound) { level.Warn(d.logger).Log("msg", "Network interface does not exist", "name", nicID, "err", err) } else { ch <- target{labelSet: nil, err: err} } - d.addToCache(nicID, networkInterface) - } else { - networkInterface, err = client.getVMScaleSetVMNetworkInterfaceByID(ctx, nicID, vm.ScaleSet, vm.InstanceID) - if err != nil { - if errors.Is(err, errorNotFound) { - level.Warn(d.logger).Log("msg", "Network interface does not exist", "name", nicID, "err", err) - } else { - ch <- target{labelSet: nil, err: err} - } - // Get out of this routine because we cannot continue without a network interface. - return - } - d.addToCache(nicID, networkInterface) + + // Get out of this routine because we cannot continue without a network interface. + return } + + // Continue processing with the network interface + d.addToCache(nicID, networkInterface) } if networkInterface.Properties == nil { From 856f6e49c886f99f7cc0417147fb8d7464d45394 Mon Sep 17 00:00:00 2001 From: carrychair Date: Sat, 9 Mar 2024 17:53:17 +0800 Subject: [PATCH 121/253] fix function and struct name Signed-off-by: carrychair --- promql/engine.go | 2 +- tsdb/index/index.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 68e0502907..5146aae6d6 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1856,7 +1856,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio panic(fmt.Errorf("unhandled expression of type: %T", expr)) } -// reuseOrGetFPointSlices reuses the space from previous slice to create new slice if the former has lots of room. +// reuseOrGetHPointSlices reuses the space from previous slice to create new slice if the former has lots of room. // The previous slices capacity is adjusted so when it is re-used from the pool it doesn't overflow into the new one. func reuseOrGetHPointSlices(prevSS *Series, numSteps int) (r []HPoint) { if prevSS != nil && cap(prevSS.Histograms)-2*len(prevSS.Histograms) > 0 { diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 7aae4c2645..7ab890b99e 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -1829,7 +1829,7 @@ func NewStringListIter(s []string) StringIter { return &stringListIter{l: s} } -// symbolsIter implements StringIter. +// stringListIter implements StringIter. type stringListIter struct { l []string cur string From 8d53e7ba90e0a6707d88a9573ee21e88a7866f1b Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 11 Mar 2024 13:35:44 +0000 Subject: [PATCH 122/253] Cut v2.51.0-rc.0 (#13729) * Cherry-pick [BUGFIX] Azure SD: Fix 'error: parameter virtualMachineScaleSetName cannot be empty' (#13702) Signed-off-by: Bryan Boreham --- CHANGELOG.md | 30 ++++++++++++++++++++ VERSION | 2 +- discovery/azure/azure.go | 20 +++++-------- 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 +- web/ui/react-app/package.json | 4 +-- 8 files changed, 51 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b0350004f..0a99777146 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## 2.51.0-rc.0 / 2024-03-07 + +This version is built with Go 1.22.1. + +There is a new optional build tag "dedupelabels", which should reduce memory consumption (#12304). +It is off by default; there will be an optional alternative image to try it out. + +* [CHANGE] Scraping: Do experimental timestamp alignment even if tolerance is bigger than 1% of scrape interval #13624, #13737 +* [FEATURE] Alerting: Relabel rules for AlertManagerConfig; allows routing alerts to different alertmanagers #12551, #13735 +* [FEATURE] API: add limit param to series, label-names and label-values APIs #13396 +* [FEATURE] UI (experimental native histograms): Add native histogram chart to Table view #13658 +* [FEATURE] Promtool: Add a "tsdb dump-openmetrics" to dump in OpemMetrics format. #13194 +* [FEATURE] PromQL (experimental native histograms): Add histogram_avg function #13467 +* [ENHANCEMENT] Rules: Evaluate independent rules concurrently #12946, #13527 +* [ENHANCEMENT] Scraping (experimental native histograms): Support exemplars #13488 +* [ENHANCEMENT] Remote Write: Disable resharding during active retry backoffs #13562 +* [ENHANCEMENT] Observability: Add native histograms to latency/duration metrics #13681 +* [ENHANCEMENT] Observability: Add 'type' label to prometheus_tsdb_head_out_of_order_samples_appended_total #13607 +* [ENHANCEMENT] API: Faster generation of targets into JSON #13469, #13484 +* [ENHANCEMENT] Scraping, API: Use faster compression library #10782 +* [ENHANCEMENT] OpenTelemetry: Performance improvements in OTLP parsing #13627 +* [ENHANCEMENT] PromQL: Optimisations to reduce CPU and memory #13448, #13536 +* [BUGFIX] PromQL: Constrain extrapolation in rate() to half of sample interval #13725 +* [BUGFIX] Remote Write: Stop slowing down when a new WAL segment is created #13583, #13628 +* [BUGFIX] PromQL: Fix wrongly scoped range vectors with @ modifier #13559 +* [BUGFIX] Kubernetes SD: Pod status changes were not discovered by Endpoints service discovery #13337 +* [BUGFIX] Azure SD: Fix 'error: parameter virtualMachineScaleSetName cannot be empty' (#13702) +* [BUGFIX] Remote Write: Fix signing for AWS sigv4 transport #13497 +* [BUGFIX] Observability: Exemplars emitted by Prometheus use "trace_id" not "traceID" #13589 + ## 2.50.1 / 2024-02-26 * [BUGFIX] API: Fix metadata API using wrong field names. #13633 diff --git a/VERSION b/VERSION index 895eb8a3b2..284f7bfe08 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.50.1 +2.51.0-rc.0 diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index a5d81f4ff6..16628c7bfd 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -413,26 +413,20 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { } else { networkInterface, err = client.getVMScaleSetVMNetworkInterfaceByID(ctx, nicID, vm.ScaleSet, vm.InstanceID) } + if err != nil { if errors.Is(err, errorNotFound) { level.Warn(d.logger).Log("msg", "Network interface does not exist", "name", nicID, "err", err) } else { ch <- target{labelSet: nil, err: err} } - d.addToCache(nicID, networkInterface) - } else { - networkInterface, err = client.getVMScaleSetVMNetworkInterfaceByID(ctx, nicID, vm.ScaleSet, vm.InstanceID) - if err != nil { - if errors.Is(err, errorNotFound) { - level.Warn(d.logger).Log("msg", "Network interface does not exist", "name", nicID, "err", err) - } else { - ch <- target{labelSet: nil, err: err} - } - // Get out of this routine because we cannot continue without a network interface. - return - } - d.addToCache(nicID, networkInterface) + + // Get out of this routine because we cannot continue without a network interface. + return } + + // Continue processing with the network interface + d.addToCache(nicID, networkInterface) } if networkInterface.Properties == nil { diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index 89aa2e9ea2..f352fb75b4 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.50.1", + "version": "0.51.0-rc.0", "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.50.1", + "@prometheus-io/lezer-promql": "0.51.0-rc.0", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index 16f3f42637..d5e53e9d1b 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.50.1", + "version": "0.51.0-rc.0", "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 c241d42e57..53ad8ea5a7 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.50.1", + "version": "0.51.0-rc.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.50.1", + "version": "0.51.0-rc.0", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.50.1", + "version": "0.51.0-rc.0", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.50.1", + "@prometheus-io/lezer-promql": "0.51.0-rc.0", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.50.1", + "version": "0.51.0-rc.0", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.50.1", + "version": "0.51.0-rc.0", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.1", + "@prometheus-io/codemirror-promql": "0.51.0-rc.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index a28cb80657..e541db85f5 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.50.1" + "version": "0.51.0-rc.0" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index 113b2298ce..ebc2f2d18b 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.50.1", + "version": "0.51.0-rc.0", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.50.1", + "@prometheus-io/codemirror-promql": "0.51.0-rc.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 1cccdbaedba18d76dded87a73be1032c4b950c85 Mon Sep 17 00:00:00 2001 From: guoguangwu Date: Tue, 12 Mar 2024 17:19:50 +0800 Subject: [PATCH 123/253] chore: use constant instead of numeric literal Signed-off-by: guoguangwu --- web/federate_test.go | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/web/federate_test.go b/web/federate_test.go index b8749dfa32..16637f60a3 100644 --- a/web/federate_test.go +++ b/web/federate_test.go @@ -48,29 +48,29 @@ var scenarios = map[string]struct { }{ "empty": { params: "", - code: 200, + code: http.StatusOK, body: ``, }, "match nothing": { params: "match[]=does_not_match_anything", - code: 200, + code: http.StatusOK, body: ``, }, "invalid params from the beginning": { params: "match[]=-not-a-valid-metric-name", - code: 400, + code: http.StatusBadRequest, body: `1:1: parse error: unexpected `, }, "invalid params somewhere in the middle": { params: "match[]=not-a-valid-metric-name", - code: 400, + code: http.StatusBadRequest, body: `1:4: parse error: unexpected `, }, "test_metric1": { params: "match[]=test_metric1", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i"} 10000 6000000 test_metric1{foo="boo",instance="i"} 1 6000000 @@ -78,33 +78,33 @@ test_metric1{foo="boo",instance="i"} 1 6000000 }, "test_metric2": { params: "match[]=test_metric2", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric2 untyped test_metric2{foo="boo",instance="i"} 1 6000000 `, }, "test_metric_without_labels": { params: "match[]=test_metric_without_labels", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric_without_labels untyped test_metric_without_labels{instance=""} 1001 6000000 `, }, "test_stale_metric": { params: "match[]=test_metric_stale", - code: 200, + code: http.StatusOK, body: ``, }, "test_old_metric": { params: "match[]=test_metric_old", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric_old untyped test_metric_old{instance=""} 981 5880000 `, }, "{foo='boo'}": { params: "match[]={foo='boo'}", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="boo",instance="i"} 1 6000000 # TYPE test_metric2 untyped @@ -113,7 +113,7 @@ test_metric2{foo="boo",instance="i"} 1 6000000 }, "two matchers": { params: "match[]=test_metric1&match[]=test_metric2", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i"} 10000 6000000 test_metric1{foo="boo",instance="i"} 1 6000000 @@ -123,7 +123,7 @@ test_metric2{foo="boo",instance="i"} 1 6000000 }, "two matchers with overlap": { params: "match[]={__name__=~'test_metric1'}&match[]={foo='bar'}", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i"} 10000 6000000 test_metric1{foo="boo",instance="i"} 1 6000000 @@ -131,7 +131,7 @@ test_metric1{foo="boo",instance="i"} 1 6000000 }, "everything": { params: "match[]={__name__=~'.%2b'}", // '%2b' is an URL-encoded '+'. - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i"} 10000 6000000 test_metric1{foo="boo",instance="i"} 1 6000000 @@ -145,7 +145,7 @@ test_metric_without_labels{instance=""} 1001 6000000 }, "empty label value matches everything that doesn't have that label": { params: "match[]={foo='',__name__=~'.%2b'}", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric_old untyped test_metric_old{instance=""} 981 5880000 # TYPE test_metric_without_labels untyped @@ -154,7 +154,7 @@ test_metric_without_labels{instance=""} 1001 6000000 }, "empty label value for a label that doesn't exist at all, matches everything": { params: "match[]={bar='',__name__=~'.%2b'}", - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i"} 10000 6000000 test_metric1{foo="boo",instance="i"} 1 6000000 @@ -169,7 +169,7 @@ test_metric_without_labels{instance=""} 1001 6000000 "external labels are added if not already present": { params: "match[]={__name__=~'.%2b'}", // '%2b' is an URL-encoded '+'. externalLabels: labels.FromStrings("foo", "baz", "zone", "ie"), - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i",zone="ie"} 10000 6000000 test_metric1{foo="boo",instance="i",zone="ie"} 1 6000000 @@ -186,7 +186,7 @@ test_metric_without_labels{foo="baz",instance="",zone="ie"} 1001 6000000 // know what it does anyway. params: "match[]={__name__=~'.%2b'}", // '%2b' is an URL-encoded '+'. externalLabels: labels.FromStrings("instance", "baz"), - code: 200, + code: http.StatusOK, body: `# TYPE test_metric1 untyped test_metric1{foo="bar",instance="i"} 10000 6000000 test_metric1{foo="boo",instance="i"} 1 6000000 @@ -390,7 +390,6 @@ func TestFederationWithNativeHistograms(t *testing.T) { require.Equal(t, http.StatusOK, res.Code) body, err := io.ReadAll(res.Body) require.NoError(t, err) - p := textparse.NewProtobufParser(body, false, labels.NewSymbolTable()) var actVec promql.Vector metricFamilies := 0 From 26262a1eb7f2d1d9ffae6df946402f5c2c896667 Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Tue, 12 Mar 2024 10:16:39 +1100 Subject: [PATCH 124/253] Remove unnecessary `SetQueryLogger` method on `QueryEngine` interface Signed-off-by: Charles Korn --- promql/engine.go | 1 - web/api/v1/api_test.go | 2 -- 2 files changed, 3 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 0d37f184ee..93fb09254a 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -117,7 +117,6 @@ func (e ErrStorage) Error() string { // QueryEngine defines the interface for the *promql.Engine, so it can be replaced, wrapped or mocked. type QueryEngine interface { - SetQueryLogger(l QueryLogger) NewInstantQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, ts time.Time) (Query, error) NewRangeQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) } diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index eae4b9c64b..aa18d9b1dd 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -3884,8 +3884,6 @@ type fakeEngine struct { query fakeQuery } -func (e *fakeEngine) SetQueryLogger(promql.QueryLogger) {} - func (e *fakeEngine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts promql.QueryOpts, qs string, ts time.Time) (promql.Query, error) { return &e.query, nil } From d08f0549506714d417b667fb5af75b7471bbd4d4 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 12 Mar 2024 11:24:27 +0000 Subject: [PATCH 125/253] [ENHANCEMENT] TSDB: Check CRC without allocating (#13742) Use the existing utility function which does this. Signed-off-by: Bryan Boreham --- tsdb/chunks/head_chunks.go | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/tsdb/chunks/head_chunks.go b/tsdb/chunks/head_chunks.go index 5ba5381320..087f25fbb3 100644 --- a/tsdb/chunks/head_chunks.go +++ b/tsdb/chunks/head_chunks.go @@ -15,7 +15,6 @@ package chunks import ( "bufio" - "bytes" "encoding/binary" "errors" "fmt" @@ -690,7 +689,6 @@ func (cdm *ChunkDiskMapper) Chunk(ref ChunkDiskMapperRef) (chunkenc.Chunk, error sgmIndex, chkStart := ref.Unpack() // We skip the series ref and the mint/maxt beforehand. chkStart += SeriesRefSize + (2 * MintMaxtSize) - chkCRC32 := newCRC32() // If it is the current open file, then the chunks can be in the buffer too. if sgmIndex == cdm.curFileSequence { @@ -755,20 +753,13 @@ func (cdm *ChunkDiskMapper) Chunk(ref ChunkDiskMapperRef) (chunkenc.Chunk, error // Check the CRC. sum := mmapFile.byteSlice.Range(chkDataEnd, chkDataEnd+CRCSize) - if _, err := chkCRC32.Write(mmapFile.byteSlice.Range(chkStart-(SeriesRefSize+2*MintMaxtSize), chkDataEnd)); err != nil { + if err := checkCRC32(mmapFile.byteSlice.Range(chkStart-(SeriesRefSize+2*MintMaxtSize), chkDataEnd), sum); err != nil { return nil, &CorruptionErr{ Dir: cdm.dir.Name(), FileIndex: sgmIndex, Err: err, } } - if act := chkCRC32.Sum(nil); !bytes.Equal(act, sum) { - return nil, &CorruptionErr{ - Dir: cdm.dir.Name(), - FileIndex: sgmIndex, - Err: fmt.Errorf("checksum mismatch expected:%x, actual:%x", sum, act), - } - } // The chunk data itself. chkData := mmapFile.byteSlice.Range(chkDataEnd-int(chkDataLen), chkDataEnd) @@ -802,8 +793,6 @@ func (cdm *ChunkDiskMapper) IterateAllChunks(f func(seriesRef HeadSeriesRef, chu cdm.fileMaxtSet = true }() - chkCRC32 := newCRC32() - // Iterate files in ascending order. segIDs := make([]int, 0, len(cdm.mmappedChunkFiles)) for seg := range cdm.mmappedChunkFiles { @@ -838,7 +827,6 @@ func (cdm *ChunkDiskMapper) IterateAllChunks(f func(seriesRef HeadSeriesRef, chu " - required:%v, available:%v, file:%d", idx+MaxHeadChunkMetaSize, fileEnd, segID), } } - chkCRC32.Reset() chunkRef := newChunkDiskMapperRef(uint64(segID), uint64(idx)) startIdx := idx @@ -877,14 +865,11 @@ func (cdm *ChunkDiskMapper) IterateAllChunks(f func(seriesRef HeadSeriesRef, chu // Check CRC. sum := mmapFile.byteSlice.Range(idx, idx+CRCSize) - if _, err := chkCRC32.Write(mmapFile.byteSlice.Range(startIdx, idx)); err != nil { - return err - } - if act := chkCRC32.Sum(nil); !bytes.Equal(act, sum) { + if err := checkCRC32(mmapFile.byteSlice.Range(startIdx, idx), sum); err != nil { return &CorruptionErr{ Dir: cdm.dir.Name(), FileIndex: segID, - Err: fmt.Errorf("checksum mismatch expected:%x, actual:%x", sum, act), + Err: err, } } idx += CRCSize From 0bb55883865fb87efb37760768d03d7576dc6547 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 12 Mar 2024 11:34:03 +0000 Subject: [PATCH 126/253] labels: optimize String method (#13673) Use a stack buffer to reduce memory allocations. `Write(AppendQuote(AvailableBuffer` does not allocate or copy when the buffer has sufficient space. Also add a benchmark, with some refactoring. Signed-off-by: Bryan Boreham --- model/labels/labels_common.go | 5 ++-- model/labels/labels_test.go | 46 ++++++++++++++++------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/model/labels/labels_common.go b/model/labels/labels_common.go index 4c4a87e872..f46321c97e 100644 --- a/model/labels/labels_common.go +++ b/model/labels/labels_common.go @@ -39,7 +39,8 @@ type Label struct { } func (ls Labels) String() string { - var b bytes.Buffer + var bytea [1024]byte // On stack to avoid memory allocation while building the output. + b := bytes.NewBuffer(bytea[:0]) b.WriteByte('{') i := 0 @@ -50,7 +51,7 @@ func (ls Labels) String() string { } b.WriteString(l.Name) b.WriteByte('=') - b.WriteString(strconv.Quote(l.Value)) + b.Write(strconv.AppendQuote(b.AvailableBuffer(), l.Value)) i++ }) b.WriteByte('}') diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index c2ac6d63a0..49b4b4e67b 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -43,6 +43,13 @@ func TestLabels_String(t *testing.T) { } } +func BenchmarkString(b *testing.B) { + ls := New(benchmarkLabels...) + for i := 0; i < b.N; i++ { + _ = ls.String() + } +} + func TestLabels_MatchLabels(t *testing.T) { labels := FromStrings( "__name__", "ALERTS", @@ -785,24 +792,24 @@ func BenchmarkLabels_Hash(b *testing.B) { } } -func BenchmarkBuilder(b *testing.B) { - m := []Label{ - {"job", "node"}, - {"instance", "123.123.1.211:9090"}, - {"path", "/api/v1/namespaces//deployments/"}, - {"method", "GET"}, - {"namespace", "system"}, - {"status", "500"}, - {"prometheus", "prometheus-core-1"}, - {"datacenter", "eu-west-1"}, - {"pod_name", "abcdef-99999-defee"}, - } +var benchmarkLabels = []Label{ + {"job", "node"}, + {"instance", "123.123.1.211:9090"}, + {"path", "/api/v1/namespaces//deployments/"}, + {"method", "GET"}, + {"namespace", "system"}, + {"status", "500"}, + {"prometheus", "prometheus-core-1"}, + {"datacenter", "eu-west-1"}, + {"pod_name", "abcdef-99999-defee"}, +} +func BenchmarkBuilder(b *testing.B) { var l Labels builder := NewBuilder(EmptyLabels()) for i := 0; i < b.N; i++ { builder.Reset(EmptyLabels()) - for _, l := range m { + for _, l := range benchmarkLabels { builder.Set(l.Name, l.Value) } l = builder.Labels() @@ -811,18 +818,7 @@ func BenchmarkBuilder(b *testing.B) { } func BenchmarkLabels_Copy(b *testing.B) { - m := map[string]string{ - "job": "node", - "instance": "123.123.1.211:9090", - "path": "/api/v1/namespaces//deployments/", - "method": "GET", - "namespace": "system", - "status": "500", - "prometheus": "prometheus-core-1", - "datacenter": "eu-west-1", - "pod_name": "abcdef-99999-defee", - } - l := FromMap(m) + l := New(benchmarkLabels...) for i := 0; i < b.N; i++ { l = l.Copy() From 2061eb0a6aee30f959f87321bf9dfa8c8efe177e Mon Sep 17 00:00:00 2001 From: SuperQ Date: Tue, 12 Mar 2024 14:13:10 +0100 Subject: [PATCH 127/253] Add GitHub action to publish container README Add a GitHub action to publish the README.md to Docker Hub and Quay.io. Fixes: https://github.com/prometheus/prometheus/issues/5348 Signed-off-by: SuperQ --- .github/workflows/container_description.yml | 53 +++++++++++++++++++++ Makefile.common | 4 ++ 2 files changed, 57 insertions(+) create mode 100644 .github/workflows/container_description.yml diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml new file mode 100644 index 0000000000..c48ee28dd8 --- /dev/null +++ b/.github/workflows/container_description.yml @@ -0,0 +1,53 @@ +--- +name: Push README to Docker Hub +on: + push: + paths: + - "README.md" + - ".github/workflows/container_description.yml" + branches: [ main, master ] + +permissions: + contents: read + +jobs: + PushDockerHubReadme: + runs-on: ubuntu-latest + name: Push README to Docker Hub + steps: + - name: git checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Set docker hub repo name. + run: echo "DOCKER_REPO_NAME=$(make common-docker-repo-name)" >> $GITHUB_ENV + - name: push README to Dockerhub + uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 + env: + DOCKER_USER: ${{ secrets.DOCKER_HUB_LOGIN }} + DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASSWORD }} + with: + destination_container_repo: ${{ env.DOCKER_REPO_NAME }} + provider: dockerhub + short_description: ${{ env.DOCKER_REPO_NAME }} + readme_file: 'README.md' + + PushQuayIoReadme: + runs-on: ubuntu-latest + name: Push README to Docker Hub + steps: + - name: git checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Set quay.io org name. + run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV + - name: Set quay.io repo name. + run: echo "DOCKER_REPO_NAME=$(make common-docker-repo-name)" >> $GITHUB_ENV + - name: push README to Dockerhub + uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 + env: + DOCKER_APIKEY: ${{ secrets.QUAY_IO_API_TOKEN }} + with: + destination_container_repo: ${{ env.DOCKER_REPO_NAME }} + provider: quay + readme_file: 'README.md' + + + diff --git a/Makefile.common b/Makefile.common index 92558151e3..49ed5f5478 100644 --- a/Makefile.common +++ b/Makefile.common @@ -208,6 +208,10 @@ common-tarball: promu @echo ">> building release tarball" $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) +.PHONY: common-docker-repo-name +common-docker-repo-name: + @echo "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" + .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: From b8d428b753981db46c7b896709bdc2d09d06dc03 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 14:07:57 +0000 Subject: [PATCH 128/253] Refactor: Azure Discovery: extract function to generate labelSet This should make it easier to test. Signed-off-by: Bryan Boreham --- discovery/azure/azure.go | 181 ++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 90 deletions(-) diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index 16628c7bfd..8936a33adb 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -374,96 +374,8 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { for _, vm := range machines { go func(vm virtualMachine) { defer wg.Done() - r, err := newAzureResourceFromID(vm.ID, d.logger) - if err != nil { - ch <- target{labelSet: nil, err: err} - return - } - - labels := model.LabelSet{ - azureLabelSubscriptionID: model.LabelValue(d.cfg.SubscriptionID), - azureLabelTenantID: model.LabelValue(d.cfg.TenantID), - azureLabelMachineID: model.LabelValue(vm.ID), - azureLabelMachineName: model.LabelValue(vm.Name), - azureLabelMachineComputerName: model.LabelValue(vm.ComputerName), - azureLabelMachineOSType: model.LabelValue(vm.OsType), - azureLabelMachineLocation: model.LabelValue(vm.Location), - azureLabelMachineResourceGroup: model.LabelValue(r.ResourceGroupName), - azureLabelMachineSize: model.LabelValue(vm.Size), - } - - if vm.ScaleSet != "" { - labels[azureLabelMachineScaleSet] = model.LabelValue(vm.ScaleSet) - } - - for k, v := range vm.Tags { - name := strutil.SanitizeLabelName(k) - labels[azureLabelMachineTag+model.LabelName(name)] = model.LabelValue(*v) - } - - // Get the IP address information via separate call to the network provider. - for _, nicID := range vm.NetworkInterfaces { - var networkInterface *armnetwork.Interface - if v, ok := d.getFromCache(nicID); ok { - networkInterface = v - d.metrics.cacheHitCount.Add(1) - } else { - if vm.ScaleSet == "" { - networkInterface, err = client.getVMNetworkInterfaceByID(ctx, nicID) - } else { - networkInterface, err = client.getVMScaleSetVMNetworkInterfaceByID(ctx, nicID, vm.ScaleSet, vm.InstanceID) - } - - if err != nil { - if errors.Is(err, errorNotFound) { - level.Warn(d.logger).Log("msg", "Network interface does not exist", "name", nicID, "err", err) - } else { - ch <- target{labelSet: nil, err: err} - } - - // Get out of this routine because we cannot continue without a network interface. - return - } - - // Continue processing with the network interface - d.addToCache(nicID, networkInterface) - } - - if networkInterface.Properties == nil { - continue - } - - // Unfortunately Azure does not return information on whether a VM is deallocated. - // This information is available via another API call however the Go SDK does not - // yet support this. On deallocated machines, this value happens to be nil so it - // is a cheap and easy way to determine if a machine is allocated or not. - if networkInterface.Properties.Primary == nil { - level.Debug(d.logger).Log("msg", "Skipping deallocated virtual machine", "machine", vm.Name) - return - } - - if *networkInterface.Properties.Primary { - for _, ip := range networkInterface.Properties.IPConfigurations { - // IPAddress is a field defined in PublicIPAddressPropertiesFormat, - // therefore we need to validate that both are not nil. - if ip.Properties != nil && ip.Properties.PublicIPAddress != nil && ip.Properties.PublicIPAddress.Properties != nil && ip.Properties.PublicIPAddress.Properties.IPAddress != nil { - labels[azureLabelMachinePublicIP] = model.LabelValue(*ip.Properties.PublicIPAddress.Properties.IPAddress) - } - if ip.Properties != nil && ip.Properties.PrivateIPAddress != nil { - labels[azureLabelMachinePrivateIP] = model.LabelValue(*ip.Properties.PrivateIPAddress) - address := net.JoinHostPort(*ip.Properties.PrivateIPAddress, fmt.Sprintf("%d", d.port)) - labels[model.AddressLabel] = model.LabelValue(address) - ch <- target{labelSet: labels, err: nil} - return - } - // If we made it here, we don't have a private IP which should be impossible. - // Return an empty target and error to ensure an all or nothing situation. - err = fmt.Errorf("unable to find a private IP for VM %s", vm.Name) - ch <- target{labelSet: nil, err: err} - return - } - } - } + labelSet, err := d.vmToLabelSet(ctx, client, vm) + ch <- target{labelSet: labelSet, err: err} }(vm) } @@ -484,6 +396,95 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { return []*targetgroup.Group{&tg}, nil } +func (d *Discovery) vmToLabelSet(ctx context.Context, client azureClient, vm virtualMachine) (model.LabelSet, error) { + r, err := newAzureResourceFromID(vm.ID, d.logger) + if err != nil { + return nil, err + } + + labels := model.LabelSet{ + azureLabelSubscriptionID: model.LabelValue(d.cfg.SubscriptionID), + azureLabelTenantID: model.LabelValue(d.cfg.TenantID), + azureLabelMachineID: model.LabelValue(vm.ID), + azureLabelMachineName: model.LabelValue(vm.Name), + azureLabelMachineComputerName: model.LabelValue(vm.ComputerName), + azureLabelMachineOSType: model.LabelValue(vm.OsType), + azureLabelMachineLocation: model.LabelValue(vm.Location), + azureLabelMachineResourceGroup: model.LabelValue(r.ResourceGroupName), + azureLabelMachineSize: model.LabelValue(vm.Size), + } + + if vm.ScaleSet != "" { + labels[azureLabelMachineScaleSet] = model.LabelValue(vm.ScaleSet) + } + + for k, v := range vm.Tags { + name := strutil.SanitizeLabelName(k) + labels[azureLabelMachineTag+model.LabelName(name)] = model.LabelValue(*v) + } + + // Get the IP address information via separate call to the network provider. + for _, nicID := range vm.NetworkInterfaces { + var networkInterface *armnetwork.Interface + if v, ok := d.getFromCache(nicID); ok { + networkInterface = v + d.metrics.cacheHitCount.Add(1) + } else { + if vm.ScaleSet == "" { + networkInterface, err = client.getVMNetworkInterfaceByID(ctx, nicID) + } else { + networkInterface, err = client.getVMScaleSetVMNetworkInterfaceByID(ctx, nicID, vm.ScaleSet, vm.InstanceID) + } + if err != nil { + if errors.Is(err, errorNotFound) { + level.Warn(d.logger).Log("msg", "Network interface does not exist", "name", nicID, "err", err) + } else { + return nil, err + } + // Get out of this routine because we cannot continue without a network interface. + return nil, nil + } + + // Continue processing with the network interface + d.addToCache(nicID, networkInterface) + } + + if networkInterface.Properties == nil { + continue + } + + // Unfortunately Azure does not return information on whether a VM is deallocated. + // This information is available via another API call however the Go SDK does not + // yet support this. On deallocated machines, this value happens to be nil so it + // is a cheap and easy way to determine if a machine is allocated or not. + if networkInterface.Properties.Primary == nil { + level.Debug(d.logger).Log("msg", "Skipping deallocated virtual machine", "machine", vm.Name) + return nil, nil + } + + if *networkInterface.Properties.Primary { + for _, ip := range networkInterface.Properties.IPConfigurations { + // IPAddress is a field defined in PublicIPAddressPropertiesFormat, + // therefore we need to validate that both are not nil. + if ip.Properties != nil && ip.Properties.PublicIPAddress != nil && ip.Properties.PublicIPAddress.Properties != nil && ip.Properties.PublicIPAddress.Properties.IPAddress != nil { + labels[azureLabelMachinePublicIP] = model.LabelValue(*ip.Properties.PublicIPAddress.Properties.IPAddress) + } + if ip.Properties != nil && ip.Properties.PrivateIPAddress != nil { + labels[azureLabelMachinePrivateIP] = model.LabelValue(*ip.Properties.PrivateIPAddress) + address := net.JoinHostPort(*ip.Properties.PrivateIPAddress, fmt.Sprintf("%d", d.port)) + labels[model.AddressLabel] = model.LabelValue(address) + return labels, nil + } + // If we made it here, we don't have a private IP which should be impossible. + // Return an empty target and error to ensure an all or nothing situation. + return nil, fmt.Errorf("unable to find a private IP for VM %s", vm.Name) + } + } + } + // TODO: Should we say something at this point? + return nil, nil +} + func (client *azureClient) getVMs(ctx context.Context, resourceGroup string) ([]virtualMachine, error) { var vms []virtualMachine if len(resourceGroup) == 0 { From 4e24e5b1d166842d6f2c604c81defd45223e4e37 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 14:41:26 +0000 Subject: [PATCH 129/253] Refactor: Azure Discovery: introduce an interface for the client So we can mock it. Signed-off-by: Bryan Boreham --- discovery/azure/azure.go | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index 8936a33adb..6bde835e5d 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -212,6 +212,14 @@ func NewDiscovery(cfg *SDConfig, logger log.Logger, metrics discovery.Discoverer return d, nil } +type client interface { + getVMs(ctx context.Context, resourceGroup string) ([]virtualMachine, error) + getScaleSets(ctx context.Context, resourceGroup string) ([]armcompute.VirtualMachineScaleSet, error) + getScaleSetVMs(ctx context.Context, scaleSet armcompute.VirtualMachineScaleSet) ([]virtualMachine, error) + getVMNetworkInterfaceByID(ctx context.Context, networkInterfaceID string) (*armnetwork.Interface, error) + getVMScaleSetVMNetworkInterfaceByID(ctx context.Context, networkInterfaceID, scaleSetName, instanceID string) (*armnetwork.Interface, error) +} + // azureClient represents multiple Azure Resource Manager providers. type azureClient struct { nic *armnetwork.InterfacesClient @@ -221,14 +229,17 @@ type azureClient struct { logger log.Logger } +var _ client = &azureClient{} + // createAzureClient is a helper function for creating an Azure compute client to ARM. -func createAzureClient(cfg SDConfig) (azureClient, error) { +func createAzureClient(cfg SDConfig, logger log.Logger) (client, error) { cloudConfiguration, err := CloudConfigurationFromName(cfg.Environment) if err != nil { - return azureClient{}, err + return &azureClient{}, err } var c azureClient + c.logger = logger telemetry := policy.TelemetryOptions{ ApplicationID: userAgent, @@ -239,12 +250,12 @@ func createAzureClient(cfg SDConfig) (azureClient, error) { Telemetry: telemetry, }) if err != nil { - return azureClient{}, err + return &azureClient{}, err } client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, "azure_sd") if err != nil { - return azureClient{}, err + return &azureClient{}, err } options := &arm.ClientOptions{ ClientOptions: policy.ClientOptions{ @@ -256,25 +267,25 @@ func createAzureClient(cfg SDConfig) (azureClient, error) { c.vm, err = armcompute.NewVirtualMachinesClient(cfg.SubscriptionID, credential, options) if err != nil { - return azureClient{}, err + return &azureClient{}, err } c.nic, err = armnetwork.NewInterfacesClient(cfg.SubscriptionID, credential, options) if err != nil { - return azureClient{}, err + return &azureClient{}, err } c.vmss, err = armcompute.NewVirtualMachineScaleSetsClient(cfg.SubscriptionID, credential, options) if err != nil { - return azureClient{}, err + return &azureClient{}, err } c.vmssvm, err = armcompute.NewVirtualMachineScaleSetVMsClient(cfg.SubscriptionID, credential, options) if err != nil { - return azureClient{}, err + return &azureClient{}, err } - return c, nil + return &c, nil } func newCredential(cfg SDConfig, policyClientOptions policy.ClientOptions) (azcore.TokenCredential, error) { @@ -330,12 +341,11 @@ func newAzureResourceFromID(id string, logger log.Logger) (*arm.ResourceID, erro func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { defer level.Debug(d.logger).Log("msg", "Azure discovery completed") - client, err := createAzureClient(*d.cfg) + client, err := createAzureClient(*d.cfg, d.logger) if err != nil { d.metrics.failuresCount.Inc() return nil, fmt.Errorf("could not create Azure client: %w", err) } - client.logger = d.logger machines, err := client.getVMs(ctx, d.cfg.ResourceGroup) if err != nil { @@ -396,7 +406,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { return []*targetgroup.Group{&tg}, nil } -func (d *Discovery) vmToLabelSet(ctx context.Context, client azureClient, vm virtualMachine) (model.LabelSet, error) { +func (d *Discovery) vmToLabelSet(ctx context.Context, client client, vm virtualMachine) (model.LabelSet, error) { r, err := newAzureResourceFromID(vm.ID, d.logger) if err != nil { return nil, err From 5f2c0c5283c745652e109c6174b5d539eaf9430a Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 14:59:31 +0000 Subject: [PATCH 130/253] Azure Discovery tests: mock the azure client interface Signed-off-by: Bryan Boreham --- discovery/azure/azure_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/discovery/azure/azure_test.go b/discovery/azure/azure_test.go index 1e437c75f2..0daaab86be 100644 --- a/discovery/azure/azure_test.go +++ b/discovery/azure/azure_test.go @@ -14,10 +14,13 @@ package azure import ( + "context" + "fmt" "testing" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/stretchr/testify/require" "go.uber.org/goleak" ) @@ -381,3 +384,35 @@ func TestNewAzureResourceFromID(t *testing.T) { require.Equal(t, tc.expected.ResourceGroupName, actual.ResourceGroupName) } } + +type mockAzureClient struct { + networkInterface *armnetwork.Interface +} + +var _ client = &mockAzureClient{} + +func (*mockAzureClient) getVMs(ctx context.Context, resourceGroup string) ([]virtualMachine, error) { + return nil, nil +} + +func (*mockAzureClient) getScaleSets(ctx context.Context, resourceGroup string) ([]armcompute.VirtualMachineScaleSet, error) { + return nil, nil +} + +func (*mockAzureClient) getScaleSetVMs(ctx context.Context, scaleSet armcompute.VirtualMachineScaleSet) ([]virtualMachine, error) { + return nil, nil +} + +func (m *mockAzureClient) getVMNetworkInterfaceByID(ctx context.Context, networkInterfaceID string) (*armnetwork.Interface, error) { + if networkInterfaceID == "" { + return nil, fmt.Errorf("parameter networkInterfaceID cannot be empty") + } + return m.networkInterface, nil +} + +func (m *mockAzureClient) getVMScaleSetVMNetworkInterfaceByID(ctx context.Context, networkInterfaceID, scaleSetName, instanceID string) (*armnetwork.Interface, error) { + if scaleSetName == "" { + return nil, fmt.Errorf("parameter virtualMachineScaleSetName cannot be empty") + } + return m.networkInterface, nil +} From ab9c544ec7371c0f0b146e082781f539d3f52ab4 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 15:12:41 +0000 Subject: [PATCH 131/253] Azure Discovery tests: Add test for VMToLabelSet Test fails due to bug in code on main. Signed-off-by: Bryan Boreham --- discovery/azure/azure_test.go | 92 ++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/discovery/azure/azure_test.go b/discovery/azure/azure_test.go index 0daaab86be..32dab66c8c 100644 --- a/discovery/azure/azure_test.go +++ b/discovery/azure/azure_test.go @@ -21,12 +21,17 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" + cache "github.com/Code-Hex/go-generics-cache" + "github.com/Code-Hex/go-generics-cache/policy/lru" + "github.com/go-kit/log" "github.com/stretchr/testify/require" "go.uber.org/goleak" ) func TestMain(m *testing.M) { - goleak.VerifyTestMain(m) + goleak.VerifyTestMain(m, + goleak.IgnoreTopFunction("github.com/Code-Hex/go-generics-cache.(*janitor).run.func1"), + ) } func TestMapFromVMWithEmptyTags(t *testing.T) { @@ -82,6 +87,91 @@ func TestMapFromVMWithEmptyTags(t *testing.T) { require.Equal(t, expectedVM, actualVM) } +func TestVMToLabelSet(t *testing.T) { + id := "/subscriptions/00000000-0000-0000-0000-000000000000/test" + name := "name" + size := "size" + vmSize := armcompute.VirtualMachineSizeTypes(size) + osType := armcompute.OperatingSystemTypesLinux + vmType := "type" + location := "westeurope" + computerName := "computer_name" + networkID := "/subscriptions/00000000-0000-0000-0000-000000000000/network1" + ipAddress := "10.20.30.40" + primary := true + networkProfile := armcompute.NetworkProfile{ + NetworkInterfaces: []*armcompute.NetworkInterfaceReference{ + { + ID: &networkID, + Properties: &armcompute.NetworkInterfaceReferenceProperties{Primary: &primary}, + }, + }, + } + properties := &armcompute.VirtualMachineProperties{ + OSProfile: &armcompute.OSProfile{ + ComputerName: &computerName, + }, + StorageProfile: &armcompute.StorageProfile{ + OSDisk: &armcompute.OSDisk{ + OSType: &osType, + }, + }, + NetworkProfile: &networkProfile, + HardwareProfile: &armcompute.HardwareProfile{ + VMSize: &vmSize, + }, + } + + testVM := armcompute.VirtualMachine{ + ID: &id, + Name: &name, + Type: &vmType, + Location: &location, + Tags: nil, + Properties: properties, + } + + expectedVM := virtualMachine{ + ID: id, + Name: name, + ComputerName: computerName, + Type: vmType, + Location: location, + OsType: "Linux", + Tags: map[string]*string{}, + NetworkInterfaces: []string{networkID}, + Size: size, + } + + actualVM := mapFromVM(testVM) + + require.Equal(t, expectedVM, actualVM) + + cfg := DefaultSDConfig + d := &Discovery{ + cfg: &cfg, + logger: log.NewNopLogger(), + cache: cache.New(cache.AsLRU[string, *armnetwork.Interface](lru.WithCapacity(5))), + } + network := armnetwork.Interface{ + Name: &networkID, + Properties: &armnetwork.InterfacePropertiesFormat{ + Primary: &primary, + IPConfigurations: []*armnetwork.InterfaceIPConfiguration{ + {Properties: &armnetwork.InterfaceIPConfigurationPropertiesFormat{ + PrivateIPAddress: &ipAddress, + }}, + }, + }, + } + client := &mockAzureClient{ + networkInterface: &network, + } + labelSet, err := d.vmToLabelSet(context.Background(), client, actualVM) + require.NoError(t, err) + require.Len(t, labelSet, 11) +} + func TestMapFromVMWithEmptyOSType(t *testing.T) { id := "test" name := "name" From cd3e0078f063e99c5ec723fdc487675dec775060 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 20:07:03 +0100 Subject: [PATCH 132/253] build(deps): bump github.com/prometheus/common (#13728) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.49.0 to 0.50.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.49.0...v0.50.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- documentation/examples/remote_storage/go.mod | 12 ++++----- documentation/examples/remote_storage/go.sum | 28 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index 38497cbf50..917563f00c 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -9,7 +9,7 @@ require ( github.com/golang/snappy v0.0.4 github.com/influxdata/influxdb v1.11.5 github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/common v0.49.0 + github.com/prometheus/common v0.50.0 github.com/prometheus/prometheus v0.50.1 github.com/stretchr/testify v1.9.0 ) @@ -58,17 +58,17 @@ require ( go.opentelemetry.io/otel/trace v1.22.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/grpc v1.61.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apimachinery v0.28.6 // indirect diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index 6ffa445b29..50db8d7934 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -269,8 +269,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.49.0 h1:ToNTdK4zSnPVJmh698mGFkDor9wBI/iGaJy5dbH1EgI= -github.com/prometheus/common v0.49.0/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= +github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ= +github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ= 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= @@ -332,8 +332,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 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= @@ -356,12 +356,12 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= 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= @@ -389,12 +389,12 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= 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= @@ -436,8 +436,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= From 3bff79451d0389c8108592eefdb51ef1b4561cd6 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Wed, 13 Mar 2024 14:28:05 +0100 Subject: [PATCH 133/253] Fix container_description workflow Fix yaml indentation. :facepalm: Signed-off-by: SuperQ --- .github/workflows/container_description.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index c48ee28dd8..c453f7c903 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -5,7 +5,7 @@ on: paths: - "README.md" - ".github/workflows/container_description.yml" - branches: [ main, master ] + branches: [ main, master ] permissions: contents: read From 505fd638beef7b0131678f1c98efcc36ce6f4982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C4=8Cajka?= Date: Tue, 12 Mar 2024 15:05:26 +0100 Subject: [PATCH 134/253] otlptranslator: fix up import paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakub Čajka --- storage/remote/otlptranslator/README.md | 3 +-- storage/remote/otlptranslator/prometheus/normalize_label.go | 2 +- storage/remote/otlptranslator/prometheus/normalize_name.go | 2 +- storage/remote/otlptranslator/prometheus/unit_to_ucum.go | 2 +- storage/remote/otlptranslator/update-copy.sh | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/storage/remote/otlptranslator/README.md b/storage/remote/otlptranslator/README.md index c2b04e5aff..774fac5a7f 100644 --- a/storage/remote/otlptranslator/README.md +++ b/storage/remote/otlptranslator/README.md @@ -3,7 +3,6 @@ This files in the `prometheus/` and `prometheusremotewrite/` are copied from the OpenTelemetry Project[^1]. This is done instead of adding a go.mod dependency because OpenTelemetry depends on `prometheus/prometheus` and a cyclic dependency will be created. This is just a temporary solution and the long-term solution is to move the required packages from OpenTelemetry into `prometheus/prometheus`. -We don't copy in `./prometheus` through this script because that package imports a collector specific featuregate package we don't want to import. The featuregate package is being removed now, and in the future we will copy this folder too. To update the dependency is a multi-step process: 1. Vendor the latest `prometheus/prometheus`@`main` into [`opentelemetry/opentelemetry-collector-contrib`](https://github.com/open-telemetry/opentelemetry-collector-contrib) @@ -20,4 +19,4 @@ This means if we depend on the upstream packages directly, we will never able to When we do want to make changes to the types in `prompb`, we might need to edit the files directly. That is OK, please let @gouthamve or @jesusvazquez know so they can take care of updating the upstream code (by vendoring in `prometheus/prometheus` upstream and resolving conflicts) and then will run the copy script again to keep things updated. -[^1]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/translator/prometheus and https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/translator/prometheusremotewrite \ No newline at end of file +[^1]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/translator/prometheus and https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/translator/prometheusremotewrite diff --git a/storage/remote/otlptranslator/prometheus/normalize_label.go b/storage/remote/otlptranslator/prometheus/normalize_label.go index c02800c8bc..a6b41d1c37 100644 --- a/storage/remote/otlptranslator/prometheus/normalize_label.go +++ b/storage/remote/otlptranslator/prometheus/normalize_label.go @@ -3,7 +3,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package prometheus // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" +package prometheus // import "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus" import ( "strings" diff --git a/storage/remote/otlptranslator/prometheus/normalize_name.go b/storage/remote/otlptranslator/prometheus/normalize_name.go index 7ae233a187..a976dfb485 100644 --- a/storage/remote/otlptranslator/prometheus/normalize_name.go +++ b/storage/remote/otlptranslator/prometheus/normalize_name.go @@ -3,7 +3,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package prometheus // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" +package prometheus // import "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus" import ( "strings" diff --git a/storage/remote/otlptranslator/prometheus/unit_to_ucum.go b/storage/remote/otlptranslator/prometheus/unit_to_ucum.go index 4a72e683bb..718a520675 100644 --- a/storage/remote/otlptranslator/prometheus/unit_to_ucum.go +++ b/storage/remote/otlptranslator/prometheus/unit_to_ucum.go @@ -3,7 +3,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package prometheus // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus" +package prometheus // import "github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus" import "strings" diff --git a/storage/remote/otlptranslator/update-copy.sh b/storage/remote/otlptranslator/update-copy.sh index f90be5eedc..8aa645e0bd 100755 --- a/storage/remote/otlptranslator/update-copy.sh +++ b/storage/remote/otlptranslator/update-copy.sh @@ -23,5 +23,5 @@ case $(sed --help 2>&1) in *) set sed -i '';; esac -"$@" -e 's#github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus#github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus#g' ./prometheusremotewrite/*.go +"$@" -e 's#github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus#github.com/prometheus/prometheus/storage/remote/otlptranslator/prometheus#g' ./prometheusremotewrite/*.go ./prometheus/*.go "$@" -e '1s#^#// DO NOT EDIT. COPIED AS-IS. SEE ../README.md\n\n#g' ./prometheusremotewrite/*.go ./prometheus/*.go From 46401b988e9a4d372b9f039d7507dbce2aa684e2 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Wed, 13 Mar 2024 15:56:37 +0100 Subject: [PATCH 135/253] Normalize and fixup step names. Signed-off-by: SuperQ --- .github/workflows/container_description.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index c453f7c903..eb505207cb 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -17,9 +17,9 @@ jobs: steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Set docker hub repo name. + - name: Set docker hub repo name run: echo "DOCKER_REPO_NAME=$(make common-docker-repo-name)" >> $GITHUB_ENV - - name: push README to Dockerhub + - name: Push README to Dockerhub uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 env: DOCKER_USER: ${{ secrets.DOCKER_HUB_LOGIN }} @@ -36,11 +36,11 @@ jobs: steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Set quay.io org name. + - name: Set quay.io org name run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV - - name: Set quay.io repo name. + - name: Set quay.io repo name run: echo "DOCKER_REPO_NAME=$(make common-docker-repo-name)" >> $GITHUB_ENV - - name: push README to Dockerhub + - name: Push README to quay.io uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 env: DOCKER_APIKEY: ${{ secrets.QUAY_IO_API_TOKEN }} From 87edf1f960d2e3b59b0f82026fa3283e4e8f21e4 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 13 Mar 2024 15:57:23 +0000 Subject: [PATCH 136/253] [Cleanup] TSDB: Remove old deprecated WAL implementation Deprecated since 2018. Signed-off-by: Bryan Boreham --- tsdb/db.go | 4 - tsdb/db_test.go | 2 +- tsdb/wal.go | 1303 ---------------------------------------------- tsdb/wal_test.go | 553 -------------------- 4 files changed, 1 insertion(+), 1861 deletions(-) delete mode 100644 tsdb/wal.go delete mode 100644 tsdb/wal_test.go diff --git a/tsdb/db.go b/tsdb/db.go index 4998da6aa7..7aa68da500 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -779,10 +779,6 @@ func open(dir string, l log.Logger, r prometheus.Registerer, opts *Options, rngs walDir := filepath.Join(dir, "wal") wblDir := filepath.Join(dir, wlog.WblDirName) - // Migrate old WAL if one exists. - if err := MigrateWAL(l, walDir); err != nil { - return nil, fmt.Errorf("migrate WAL: %w", err) - } for _, tmpDir := range []string{walDir, dir} { // Remove tmp dirs. if err := removeBestEffortTmpDirs(l, tmpDir); err != nil { diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 45a16b8ba3..b1171b349a 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -3598,7 +3598,7 @@ func testChunkQuerierShouldNotPanicIfHeadChunkIsTruncatedWhileReadingQueriedChun // just to iterate through the bytes slice. We don't really care the reason why // we read this data, we just need to read it to make sure the memory address // of the []byte is still valid. - chkCRC32 := newCRC32() + chkCRC32 := crc32.New(crc32.MakeTable(crc32.Castagnoli)) for _, chunk := range chunks { chkCRC32.Reset() _, err := chkCRC32.Write(chunk.Bytes()) diff --git a/tsdb/wal.go b/tsdb/wal.go deleted file mode 100644 index e06a8aea53..0000000000 --- a/tsdb/wal.go +++ /dev/null @@ -1,1303 +0,0 @@ -// Copyright 2017 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package tsdb - -import ( - "bufio" - "encoding/binary" - "errors" - "fmt" - "hash" - "hash/crc32" - "io" - "math" - "os" - "path/filepath" - "sync" - "time" - - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/prometheus/client_golang/prometheus" - - "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/storage" - "github.com/prometheus/prometheus/tsdb/chunks" - "github.com/prometheus/prometheus/tsdb/encoding" - "github.com/prometheus/prometheus/tsdb/fileutil" - "github.com/prometheus/prometheus/tsdb/record" - "github.com/prometheus/prometheus/tsdb/tombstones" - "github.com/prometheus/prometheus/tsdb/wlog" - "github.com/prometheus/prometheus/util/zeropool" -) - -// WALEntryType indicates what data a WAL entry contains. -type WALEntryType uint8 - -const ( - // WALMagic is a 4 byte number every WAL segment file starts with. - WALMagic = uint32(0x43AF00EF) - - // WALFormatDefault is the version flag for the default outer segment file format. - WALFormatDefault = byte(1) -) - -// Entry types in a segment file. -const ( - WALEntrySymbols WALEntryType = 1 - WALEntrySeries WALEntryType = 2 - WALEntrySamples WALEntryType = 3 - WALEntryDeletes WALEntryType = 4 -) - -type walMetrics struct { - fsyncDuration prometheus.Summary - corruptions prometheus.Counter -} - -func newWalMetrics(r prometheus.Registerer) *walMetrics { - m := &walMetrics{} - - m.fsyncDuration = prometheus.NewSummary(prometheus.SummaryOpts{ - Name: "prometheus_tsdb_wal_fsync_duration_seconds", - Help: "Duration of WAL fsync.", - Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, - }) - m.corruptions = prometheus.NewCounter(prometheus.CounterOpts{ - Name: "prometheus_tsdb_wal_corruptions_total", - Help: "Total number of WAL corruptions.", - }) - - if r != nil { - r.MustRegister( - m.fsyncDuration, - m.corruptions, - ) - } - return m -} - -// WAL is a write ahead log that can log new series labels and samples. -// It must be completely read before new entries are logged. -// -// Deprecated: use wlog pkg combined with the record codex instead. -type WAL interface { - Reader() WALReader - LogSeries([]record.RefSeries) error - LogSamples([]record.RefSample) error - LogDeletes([]tombstones.Stone) error - Truncate(mint int64, keep func(uint64) bool) error - Close() error -} - -// WALReader reads entries from a WAL. -type WALReader interface { - Read( - seriesf func([]record.RefSeries), - samplesf func([]record.RefSample), - deletesf func([]tombstones.Stone), - ) error -} - -// segmentFile wraps a file object of a segment and tracks the highest timestamp -// it contains. During WAL truncating, all segments with no higher timestamp than -// the truncation threshold can be compacted. -type segmentFile struct { - *os.File - maxTime int64 // highest tombstone or sample timestamp in segment - minSeries chunks.HeadSeriesRef // lowerst series ID in segment -} - -func newSegmentFile(f *os.File) *segmentFile { - return &segmentFile{ - File: f, - maxTime: math.MinInt64, - minSeries: math.MaxUint64, - } -} - -const ( - walSegmentSizeBytes = 256 * 1024 * 1024 // 256 MB -) - -// The table gets initialized with sync.Once but may still cause a race -// with any other use of the crc32 package anywhere. Thus we initialize it -// before. -var castagnoliTable *crc32.Table - -func init() { - castagnoliTable = crc32.MakeTable(crc32.Castagnoli) -} - -// newCRC32 initializes a CRC32 hash with a preconfigured polynomial, so the -// polynomial may be easily changed in one location at a later time, if necessary. -func newCRC32() hash.Hash32 { - return crc32.New(castagnoliTable) -} - -// SegmentWAL is a write ahead log for series data. -// -// Deprecated: use wlog pkg combined with the record coders instead. -type SegmentWAL struct { - mtx sync.Mutex - metrics *walMetrics - - dirFile *os.File - files []*segmentFile - - logger log.Logger - flushInterval time.Duration - segmentSize int64 - - crc32 hash.Hash32 - cur *bufio.Writer - curN int64 - - stopc chan struct{} - donec chan struct{} - actorc chan func() error // sequentialized background operations - buffers sync.Pool -} - -// OpenSegmentWAL opens or creates a write ahead log in the given directory. -// The WAL must be read completely before new data is written. -func OpenSegmentWAL(dir string, logger log.Logger, flushInterval time.Duration, r prometheus.Registerer) (*SegmentWAL, error) { - if err := os.MkdirAll(dir, 0o777); err != nil { - return nil, err - } - df, err := fileutil.OpenDir(dir) - if err != nil { - return nil, err - } - if logger == nil { - logger = log.NewNopLogger() - } - - w := &SegmentWAL{ - dirFile: df, - logger: logger, - flushInterval: flushInterval, - donec: make(chan struct{}), - stopc: make(chan struct{}), - actorc: make(chan func() error, 2), - segmentSize: walSegmentSizeBytes, - crc32: newCRC32(), - } - w.metrics = newWalMetrics(r) - - fns, err := sequenceFiles(w.dirFile.Name()) - if err != nil { - return nil, err - } - - for i, fn := range fns { - f, err := w.openSegmentFile(fn) - if err == nil { - w.files = append(w.files, newSegmentFile(f)) - continue - } - level.Warn(logger).Log("msg", "Invalid segment file detected, truncating WAL", "err", err, "file", fn) - - for _, fn := range fns[i:] { - if err := os.Remove(fn); err != nil { - return w, fmt.Errorf("removing segment failed: %w", err) - } - } - break - } - - go w.run(flushInterval) - - return w, nil -} - -// repairingWALReader wraps a WAL reader and truncates its underlying SegmentWAL after the last -// valid entry if it encounters corruption. -type repairingWALReader struct { - wal *SegmentWAL - r WALReader -} - -func (r *repairingWALReader) Read( - seriesf func([]record.RefSeries), - samplesf func([]record.RefSample), - deletesf func([]tombstones.Stone), -) error { - err := r.r.Read(seriesf, samplesf, deletesf) - if err == nil { - return nil - } - var cerr *walCorruptionErr - if !errors.As(err, &cerr) { - return err - } - r.wal.metrics.corruptions.Inc() - return r.wal.truncate(cerr.err, cerr.file, cerr.lastOffset) -} - -// truncate the WAL after the last valid entry. -func (w *SegmentWAL) truncate(err error, file int, lastOffset int64) error { - level.Error(w.logger).Log("msg", "WAL corruption detected; truncating", - "err", err, "file", w.files[file].Name(), "pos", lastOffset) - - // Close and delete all files after the current one. - for _, f := range w.files[file+1:] { - if err := f.Close(); err != nil { - return err - } - if err := os.Remove(f.Name()); err != nil { - return err - } - } - w.mtx.Lock() - defer w.mtx.Unlock() - - w.files = w.files[:file+1] - - // Seek the current file to the last valid offset where we continue writing from. - _, err = w.files[file].Seek(lastOffset, io.SeekStart) - return err -} - -// Reader returns a new reader over the write ahead log data. -// It must be completely consumed before writing to the WAL. -func (w *SegmentWAL) Reader() WALReader { - return &repairingWALReader{ - wal: w, - r: newWALReader(w.files, w.logger), - } -} - -func (w *SegmentWAL) getBuffer() *encoding.Encbuf { - b := w.buffers.Get() - if b == nil { - return &encoding.Encbuf{B: make([]byte, 0, 64*1024)} - } - return b.(*encoding.Encbuf) -} - -func (w *SegmentWAL) putBuffer(b *encoding.Encbuf) { - b.Reset() - w.buffers.Put(b) -} - -// Truncate deletes the values prior to mint and the series which the keep function -// does not indicate to preserve. -func (w *SegmentWAL) Truncate(mint int64, keep func(chunks.HeadSeriesRef) bool) error { - // The last segment is always active. - if len(w.files) < 2 { - return nil - } - var candidates []*segmentFile - - // All files have to be traversed as there could be two segments for a block - // with first block having times (10000, 20000) and SECOND one having (0, 10000). - for _, sf := range w.files[:len(w.files)-1] { - if sf.maxTime >= mint { - break - } - // Past WAL files are closed. We have to reopen them for another read. - f, err := w.openSegmentFile(sf.Name()) - if err != nil { - return fmt.Errorf("open old WAL segment for read: %w", err) - } - candidates = append(candidates, &segmentFile{ - File: f, - minSeries: sf.minSeries, - maxTime: sf.maxTime, - }) - } - if len(candidates) == 0 { - return nil - } - - r := newWALReader(candidates, w.logger) - - // Create a new tmp file. - f, err := w.createSegmentFile(filepath.Join(w.dirFile.Name(), "compact.tmp")) - if err != nil { - return fmt.Errorf("create compaction segment: %w", err) - } - defer func() { - if err := os.RemoveAll(f.Name()); err != nil { - level.Error(w.logger).Log("msg", "remove tmp file", "err", err.Error()) - } - }() - - var ( - csf = newSegmentFile(f) - crc32 = newCRC32() - decSeries = []record.RefSeries{} - activeSeries = []record.RefSeries{} - ) - - for r.next() { - rt, flag, byt := r.at() - - if rt != WALEntrySeries { - continue - } - decSeries = decSeries[:0] - activeSeries = activeSeries[:0] - - err := r.decodeSeries(flag, byt, &decSeries) - if err != nil { - return fmt.Errorf("decode samples while truncating: %w", err) - } - for _, s := range decSeries { - if keep(s.Ref) { - activeSeries = append(activeSeries, s) - } - } - - buf := w.getBuffer() - flag = w.encodeSeries(buf, activeSeries) - - _, err = w.writeTo(csf, crc32, WALEntrySeries, flag, buf.Get()) - w.putBuffer(buf) - - if err != nil { - return fmt.Errorf("write to compaction segment: %w", err) - } - } - if err := r.Err(); err != nil { - return fmt.Errorf("read candidate WAL files: %w", err) - } - - off, err := csf.Seek(0, io.SeekCurrent) - if err != nil { - return err - } - if err := csf.Truncate(off); err != nil { - return err - } - if err := csf.Sync(); err != nil { - return nil - } - if err := csf.Close(); err != nil { - return nil - } - - _ = candidates[0].Close() // need close before remove on platform windows - if err := fileutil.Replace(csf.Name(), candidates[0].Name()); err != nil { - return fmt.Errorf("rename compaction segment: %w", err) - } - for _, f := range candidates[1:] { - f.Close() // need close before remove on platform windows - if err := os.RemoveAll(f.Name()); err != nil { - return fmt.Errorf("delete WAL segment file: %w", err) - } - } - if err := w.dirFile.Sync(); err != nil { - return err - } - - // The file object of csf still holds the name before rename. Recreate it so - // subsequent truncations do not look at a non-existent file name. - csf.File, err = w.openSegmentFile(candidates[0].Name()) - if err != nil { - return err - } - // We don't need it to be open. - if err := csf.Close(); err != nil { - return err - } - - w.mtx.Lock() - w.files = append([]*segmentFile{csf}, w.files[len(candidates):]...) - w.mtx.Unlock() - - return nil -} - -// LogSeries writes a batch of new series labels to the log. -// The series have to be ordered. -func (w *SegmentWAL) LogSeries(series []record.RefSeries) error { - buf := w.getBuffer() - - flag := w.encodeSeries(buf, series) - - w.mtx.Lock() - defer w.mtx.Unlock() - - err := w.write(WALEntrySeries, flag, buf.Get()) - - w.putBuffer(buf) - - if err != nil { - return fmt.Errorf("log series: %w", err) - } - - tf := w.head() - - for _, s := range series { - if tf.minSeries > s.Ref { - tf.minSeries = s.Ref - } - } - return nil -} - -// LogSamples writes a batch of new samples to the log. -func (w *SegmentWAL) LogSamples(samples []record.RefSample) error { - buf := w.getBuffer() - - flag := w.encodeSamples(buf, samples) - - w.mtx.Lock() - defer w.mtx.Unlock() - - err := w.write(WALEntrySamples, flag, buf.Get()) - - w.putBuffer(buf) - - if err != nil { - return fmt.Errorf("log series: %w", err) - } - tf := w.head() - - for _, s := range samples { - if tf.maxTime < s.T { - tf.maxTime = s.T - } - } - return nil -} - -// LogDeletes write a batch of new deletes to the log. -func (w *SegmentWAL) LogDeletes(stones []tombstones.Stone) error { - buf := w.getBuffer() - - flag := w.encodeDeletes(buf, stones) - - w.mtx.Lock() - defer w.mtx.Unlock() - - err := w.write(WALEntryDeletes, flag, buf.Get()) - - w.putBuffer(buf) - - if err != nil { - return fmt.Errorf("log series: %w", err) - } - tf := w.head() - - for _, s := range stones { - for _, iv := range s.Intervals { - if tf.maxTime < iv.Maxt { - tf.maxTime = iv.Maxt - } - } - } - return nil -} - -// openSegmentFile opens the given segment file and consumes and validates header. -func (w *SegmentWAL) openSegmentFile(name string) (*os.File, error) { - // We must open all files in read/write mode as we may have to truncate along - // the way and any file may become the head. - f, err := os.OpenFile(name, os.O_RDWR, 0o666) - if err != nil { - return nil, err - } - metab := make([]byte, 8) - - // If there is an error, we need close f for platform windows before gc. - // Otherwise, file op may fail. - hasError := true - defer func() { - if hasError { - f.Close() - } - }() - - switch n, err := f.Read(metab); { - case err != nil: - return nil, fmt.Errorf("validate meta %q: %w", f.Name(), err) - case n != 8: - return nil, fmt.Errorf("invalid header size %d in %q", n, f.Name()) - } - - if m := binary.BigEndian.Uint32(metab[:4]); m != WALMagic { - return nil, fmt.Errorf("invalid magic header %x in %q", m, f.Name()) - } - if metab[4] != WALFormatDefault { - return nil, fmt.Errorf("unknown WAL segment format %d in %q", metab[4], f.Name()) - } - hasError = false - return f, nil -} - -// createSegmentFile creates a new segment file with the given name. It preallocates -// the standard segment size if possible and writes the header. -func (w *SegmentWAL) createSegmentFile(name string) (*os.File, error) { - f, err := os.Create(name) - if err != nil { - return nil, err - } - if err = fileutil.Preallocate(f, w.segmentSize, true); err != nil { - return nil, err - } - // Write header metadata for new file. - metab := make([]byte, 8) - binary.BigEndian.PutUint32(metab[:4], WALMagic) - metab[4] = WALFormatDefault - - if _, err := f.Write(metab); err != nil { - return nil, err - } - return f, err -} - -// cut finishes the currently active segments and opens the next one. -// The encoder is reset to point to the new segment. -func (w *SegmentWAL) cut() error { - // Sync current head to disk and close. - if hf := w.head(); hf != nil { - if err := w.flush(); err != nil { - return err - } - // Finish last segment asynchronously to not block the WAL moving along - // in the new segment. - go func() { - w.actorc <- func() error { - off, err := hf.Seek(0, io.SeekCurrent) - if err != nil { - return fmt.Errorf("finish old segment %s: %w", hf.Name(), err) - } - if err := hf.Truncate(off); err != nil { - return fmt.Errorf("finish old segment %s: %w", hf.Name(), err) - } - if err := hf.Sync(); err != nil { - return fmt.Errorf("finish old segment %s: %w", hf.Name(), err) - } - if err := hf.Close(); err != nil { - return fmt.Errorf("finish old segment %s: %w", hf.Name(), err) - } - return nil - } - }() - } - - p, _, err := nextSequenceFile(w.dirFile.Name()) - if err != nil { - return err - } - f, err := w.createSegmentFile(p) - if err != nil { - return err - } - - go func() { - w.actorc <- func() error { - if err := w.dirFile.Sync(); err != nil { - return fmt.Errorf("sync WAL directory: %w", err) - } - return nil - } - }() - - w.files = append(w.files, newSegmentFile(f)) - - // TODO(gouthamve): make the buffer size a constant. - w.cur = bufio.NewWriterSize(f, 8*1024*1024) - w.curN = 8 - - return nil -} - -func (w *SegmentWAL) head() *segmentFile { - if len(w.files) == 0 { - return nil - } - return w.files[len(w.files)-1] -} - -// Sync flushes the changes to disk. -func (w *SegmentWAL) Sync() error { - var head *segmentFile - var err error - - // Flush the writer and retrieve the reference to the head segment under mutex lock. - func() { - w.mtx.Lock() - defer w.mtx.Unlock() - if err = w.flush(); err != nil { - return - } - head = w.head() - }() - if err != nil { - return fmt.Errorf("flush buffer: %w", err) - } - if head != nil { - // But only fsync the head segment after releasing the mutex as it will block on disk I/O. - start := time.Now() - err := fileutil.Fdatasync(head.File) - w.metrics.fsyncDuration.Observe(time.Since(start).Seconds()) - return err - } - return nil -} - -func (w *SegmentWAL) sync() error { - if err := w.flush(); err != nil { - return err - } - if w.head() == nil { - return nil - } - - start := time.Now() - err := fileutil.Fdatasync(w.head().File) - w.metrics.fsyncDuration.Observe(time.Since(start).Seconds()) - return err -} - -func (w *SegmentWAL) flush() error { - if w.cur == nil { - return nil - } - return w.cur.Flush() -} - -func (w *SegmentWAL) run(interval time.Duration) { - var tick <-chan time.Time - - if interval > 0 { - ticker := time.NewTicker(interval) - defer ticker.Stop() - tick = ticker.C - } - defer close(w.donec) - - for { - // Processing all enqueued operations has precedence over shutdown and - // background syncs. - select { - case f := <-w.actorc: - if err := f(); err != nil { - level.Error(w.logger).Log("msg", "operation failed", "err", err) - } - continue - default: - } - select { - case <-w.stopc: - return - case f := <-w.actorc: - if err := f(); err != nil { - level.Error(w.logger).Log("msg", "operation failed", "err", err) - } - case <-tick: - if err := w.Sync(); err != nil { - level.Error(w.logger).Log("msg", "sync failed", "err", err) - } - } - } -} - -// Close syncs all data and closes the underlying resources. -func (w *SegmentWAL) Close() error { - // Make sure you can call Close() multiple times. - select { - case <-w.stopc: - return nil // Already closed. - default: - } - - close(w.stopc) - <-w.donec - - w.mtx.Lock() - defer w.mtx.Unlock() - - if err := w.sync(); err != nil { - return err - } - // On opening, a WAL must be fully consumed once. Afterwards - // only the current segment will still be open. - if hf := w.head(); hf != nil { - if err := hf.Close(); err != nil { - return fmt.Errorf("closing WAL head %s: %w", hf.Name(), err) - } - } - if err := w.dirFile.Close(); err != nil { - return fmt.Errorf("closing WAL dir %s: %w", w.dirFile.Name(), err) - } - return nil -} - -func (w *SegmentWAL) write(t WALEntryType, flag uint8, buf []byte) error { - // Cut to the next segment if the entry exceeds the file size unless it would also - // exceed the size of a new segment. - // TODO(gouthamve): Add a test for this case where the commit is greater than segmentSize. - var ( - sz = int64(len(buf)) + 6 - newsz = w.curN + sz - ) - // XXX(fabxc): this currently cuts a new file whenever the WAL was newly opened. - // Probably fine in general but may yield a lot of short files in some cases. - if w.cur == nil || w.curN > w.segmentSize || newsz > w.segmentSize && sz <= w.segmentSize { - if err := w.cut(); err != nil { - return err - } - } - n, err := w.writeTo(w.cur, w.crc32, t, flag, buf) - - w.curN += int64(n) - - return err -} - -func (w *SegmentWAL) writeTo(wr io.Writer, crc32 hash.Hash, t WALEntryType, flag uint8, buf []byte) (int, error) { - if len(buf) == 0 { - return 0, nil - } - crc32.Reset() - wr = io.MultiWriter(crc32, wr) - - var b [6]byte - b[0] = byte(t) - b[1] = flag - - binary.BigEndian.PutUint32(b[2:], uint32(len(buf))) - - n1, err := wr.Write(b[:]) - if err != nil { - return n1, err - } - n2, err := wr.Write(buf) - if err != nil { - return n1 + n2, err - } - n3, err := wr.Write(crc32.Sum(b[:0])) - - return n1 + n2 + n3, err -} - -const ( - walSeriesSimple = 1 - walSamplesSimple = 1 - walDeletesSimple = 1 -) - -func (w *SegmentWAL) encodeSeries(buf *encoding.Encbuf, series []record.RefSeries) uint8 { - for _, s := range series { - buf.PutBE64(uint64(s.Ref)) - record.EncodeLabels(buf, s.Labels) - } - return walSeriesSimple -} - -func (w *SegmentWAL) encodeSamples(buf *encoding.Encbuf, samples []record.RefSample) uint8 { - if len(samples) == 0 { - return walSamplesSimple - } - // Store base timestamp and base reference number of first sample. - // All samples encode their timestamp and ref as delta to those. - // - // TODO(fabxc): optimize for all samples having the same timestamp. - first := samples[0] - - buf.PutBE64(uint64(first.Ref)) - buf.PutBE64int64(first.T) - - for _, s := range samples { - buf.PutVarint64(int64(s.Ref) - int64(first.Ref)) - buf.PutVarint64(s.T - first.T) - buf.PutBE64(math.Float64bits(s.V)) - } - return walSamplesSimple -} - -func (w *SegmentWAL) encodeDeletes(buf *encoding.Encbuf, stones []tombstones.Stone) uint8 { - for _, s := range stones { - for _, iv := range s.Intervals { - buf.PutBE64(uint64(s.Ref)) - buf.PutVarint64(iv.Mint) - buf.PutVarint64(iv.Maxt) - } - } - return walDeletesSimple -} - -// walReader decodes and emits write ahead log entries. -type walReader struct { - logger log.Logger - - files []*segmentFile - cur int - buf []byte - crc32 hash.Hash32 - dec record.Decoder - - curType WALEntryType - curFlag byte - curBuf []byte - lastOffset int64 // offset after last successfully read entry - - err error -} - -func newWALReader(files []*segmentFile, l log.Logger) *walReader { - if l == nil { - l = log.NewNopLogger() - } - return &walReader{ - logger: l, - files: files, - buf: make([]byte, 0, 128*4096), - crc32: newCRC32(), - dec: record.NewDecoder(labels.NewSymbolTable()), - } -} - -// Err returns the last error the reader encountered. -func (r *walReader) Err() error { - return r.err -} - -func (r *walReader) Read( - seriesf func([]record.RefSeries), - samplesf func([]record.RefSample), - deletesf func([]tombstones.Stone), -) error { - // Concurrency for replaying the WAL is very limited. We at least split out decoding and - // processing into separate threads. - // Historically, the processing is the bottleneck with reading and decoding using only - // 15% of the CPU. - var ( - seriesPool zeropool.Pool[[]record.RefSeries] - samplePool zeropool.Pool[[]record.RefSample] - deletePool zeropool.Pool[[]tombstones.Stone] - ) - donec := make(chan struct{}) - datac := make(chan interface{}, 100) - - go func() { - defer close(donec) - - for x := range datac { - switch v := x.(type) { - case []record.RefSeries: - if seriesf != nil { - seriesf(v) - } - seriesPool.Put(v[:0]) - case []record.RefSample: - if samplesf != nil { - samplesf(v) - } - samplePool.Put(v[:0]) - case []tombstones.Stone: - if deletesf != nil { - deletesf(v) - } - deletePool.Put(v[:0]) - default: - level.Error(r.logger).Log("msg", "unexpected data type") - } - } - }() - - var err error - - for r.next() { - et, flag, b := r.at() - - // In decoding below we never return a walCorruptionErr for now. - // Those should generally be caught by entry decoding before. - switch et { - case WALEntrySeries: - series := seriesPool.Get() - if series == nil { - series = make([]record.RefSeries, 0, 512) - } - - err = r.decodeSeries(flag, b, &series) - if err != nil { - err = fmt.Errorf("decode series entry: %w", err) - break - } - datac <- series - - cf := r.current() - for _, s := range series { - if cf.minSeries > s.Ref { - cf.minSeries = s.Ref - } - } - case WALEntrySamples: - samples := samplePool.Get() - if samples == nil { - samples = make([]record.RefSample, 0, 512) - } - - err = r.decodeSamples(flag, b, &samples) - if err != nil { - err = fmt.Errorf("decode samples entry: %w", err) - break - } - datac <- samples - - // Update the times for the WAL segment file. - cf := r.current() - for _, s := range samples { - if cf.maxTime < s.T { - cf.maxTime = s.T - } - } - case WALEntryDeletes: - deletes := deletePool.Get() - if deletes == nil { - deletes = make([]tombstones.Stone, 0, 512) - } - - err = r.decodeDeletes(flag, b, &deletes) - if err != nil { - err = fmt.Errorf("decode delete entry: %w", err) - break - } - datac <- deletes - - // Update the times for the WAL segment file. - cf := r.current() - for _, s := range deletes { - for _, iv := range s.Intervals { - if cf.maxTime < iv.Maxt { - cf.maxTime = iv.Maxt - } - } - } - } - } - close(datac) - <-donec - - if err != nil { - return err - } - if err := r.Err(); err != nil { - return fmt.Errorf("read entry: %w", err) - } - return nil -} - -func (r *walReader) at() (WALEntryType, byte, []byte) { - return r.curType, r.curFlag, r.curBuf -} - -// next returns decodes the next entry pair and returns true -// if it was successful. -func (r *walReader) next() bool { - if r.cur >= len(r.files) { - return false - } - cf := r.files[r.cur] - - // Remember the offset after the last correctly read entry. If the next one - // is corrupted, this is where we can safely truncate. - r.lastOffset, r.err = cf.Seek(0, io.SeekCurrent) - if r.err != nil { - return false - } - - et, flag, b, err := r.entry(cf) - // If we reached the end of the reader, advance to the next one - // and close. - // Do not close on the last one as it will still be appended to. - if errors.Is(err, io.EOF) { - if r.cur == len(r.files)-1 { - return false - } - // Current reader completed, close and move to the next one. - if err := cf.Close(); err != nil { - r.err = err - return false - } - r.cur++ - return r.next() - } - if err != nil { - r.err = err - return false - } - - r.curType = et - r.curFlag = flag - r.curBuf = b - return r.err == nil -} - -func (r *walReader) current() *segmentFile { - return r.files[r.cur] -} - -// walCorruptionErr is a type wrapper for errors that indicate WAL corruption -// and trigger a truncation. -type walCorruptionErr struct { - err error - file int - lastOffset int64 -} - -func (e *walCorruptionErr) Error() string { - return fmt.Sprintf("%s ", e.err, e.file, e.lastOffset) -} - -func (e *walCorruptionErr) Unwrap() error { - return e.err -} - -func (r *walReader) corruptionErr(s string, args ...interface{}) error { - return &walCorruptionErr{ - err: fmt.Errorf(s, args...), - file: r.cur, - lastOffset: r.lastOffset, - } -} - -func (r *walReader) entry(cr io.Reader) (WALEntryType, byte, []byte, error) { - r.crc32.Reset() - tr := io.TeeReader(cr, r.crc32) - - b := make([]byte, 6) - switch n, err := tr.Read(b); { - case err != nil: - return 0, 0, nil, err - case n != 6: - return 0, 0, nil, r.corruptionErr("invalid entry header size %d", n) - } - - var ( - etype = WALEntryType(b[0]) - flag = b[1] - length = int(binary.BigEndian.Uint32(b[2:])) - ) - // Exit if we reached pre-allocated space. - if etype == 0 { - return 0, 0, nil, io.EOF - } - if etype != WALEntrySeries && etype != WALEntrySamples && etype != WALEntryDeletes { - return 0, 0, nil, r.corruptionErr("invalid entry type %d", etype) - } - - if length > len(r.buf) { - r.buf = make([]byte, length) - } - buf := r.buf[:length] - - switch n, err := tr.Read(buf); { - case err != nil: - return 0, 0, nil, err - case n != length: - return 0, 0, nil, r.corruptionErr("invalid entry body size %d", n) - } - - switch n, err := cr.Read(b[:4]); { - case err != nil: - return 0, 0, nil, err - case n != 4: - return 0, 0, nil, r.corruptionErr("invalid checksum length %d", n) - } - if exp, has := binary.BigEndian.Uint32(b[:4]), r.crc32.Sum32(); has != exp { - return 0, 0, nil, r.corruptionErr("unexpected CRC32 checksum %x, want %x", has, exp) - } - - return etype, flag, buf, nil -} - -func (r *walReader) decodeSeries(flag byte, b []byte, res *[]record.RefSeries) error { - dec := encoding.Decbuf{B: b} - - for len(dec.B) > 0 && dec.Err() == nil { - ref := chunks.HeadSeriesRef(dec.Be64()) - lset := r.dec.DecodeLabels(&dec) - - *res = append(*res, record.RefSeries{ - Ref: ref, - Labels: lset, - }) - } - if dec.Err() != nil { - return dec.Err() - } - if len(dec.B) > 0 { - return fmt.Errorf("unexpected %d bytes left in entry", len(dec.B)) - } - return nil -} - -func (r *walReader) decodeSamples(flag byte, b []byte, res *[]record.RefSample) error { - if len(b) == 0 { - return nil - } - dec := encoding.Decbuf{B: b} - - var ( - baseRef = dec.Be64() - baseTime = dec.Be64int64() - ) - - for len(dec.B) > 0 && dec.Err() == nil { - dref := dec.Varint64() - dtime := dec.Varint64() - val := dec.Be64() - - *res = append(*res, record.RefSample{ - Ref: chunks.HeadSeriesRef(int64(baseRef) + dref), - T: baseTime + dtime, - V: math.Float64frombits(val), - }) - } - - if err := dec.Err(); err != nil { - return fmt.Errorf("decode error after %d samples: %w", len(*res), err) - } - if len(dec.B) > 0 { - return fmt.Errorf("unexpected %d bytes left in entry", len(dec.B)) - } - return nil -} - -func (r *walReader) decodeDeletes(flag byte, b []byte, res *[]tombstones.Stone) error { - dec := &encoding.Decbuf{B: b} - - for dec.Len() > 0 && dec.Err() == nil { - *res = append(*res, tombstones.Stone{ - Ref: storage.SeriesRef(dec.Be64()), - Intervals: tombstones.Intervals{ - {Mint: dec.Varint64(), Maxt: dec.Varint64()}, - }, - }) - } - if dec.Err() != nil { - return dec.Err() - } - if len(dec.B) > 0 { - return fmt.Errorf("unexpected %d bytes left in entry", len(dec.B)) - } - return nil -} - -func deprecatedWALExists(logger log.Logger, dir string) (bool, error) { - // Detect whether we still have the old WAL. - fns, err := sequenceFiles(dir) - if err != nil && !os.IsNotExist(err) { - return false, fmt.Errorf("list sequence files: %w", err) - } - if len(fns) == 0 { - return false, nil // No WAL at all yet. - } - // Check header of first segment to see whether we are still dealing with an - // old WAL. - f, err := os.Open(fns[0]) - if err != nil { - return false, fmt.Errorf("check first existing segment: %w", err) - } - defer f.Close() - - var hdr [4]byte - if _, err := f.Read(hdr[:]); err != nil && !errors.Is(err, io.EOF) { - return false, fmt.Errorf("read header from first segment: %w", err) - } - // If we cannot read the magic header for segments of the old WAL, abort. - // Either it's migrated already or there's a corruption issue with which - // we cannot deal here anyway. Subsequent attempts to open the WAL will error in that case. - if binary.BigEndian.Uint32(hdr[:]) != WALMagic { - return false, nil - } - return true, nil -} - -// MigrateWAL rewrites the deprecated write ahead log into the new format. -func MigrateWAL(logger log.Logger, dir string) (err error) { - if logger == nil { - logger = log.NewNopLogger() - } - if exists, err := deprecatedWALExists(logger, dir); err != nil || !exists { - return err - } - level.Info(logger).Log("msg", "Migrating WAL format") - - tmpdir := dir + ".tmp" - if err := os.RemoveAll(tmpdir); err != nil { - return fmt.Errorf("cleanup replacement dir: %w", err) - } - repl, err := wlog.New(logger, nil, tmpdir, wlog.CompressionNone) - if err != nil { - return fmt.Errorf("open new WAL: %w", err) - } - - // It should've already been closed as part of the previous finalization. - // Do it once again in case of prior errors. - defer func() { - if err != nil { - repl.Close() - } - }() - - w, err := OpenSegmentWAL(dir, logger, time.Minute, nil) - if err != nil { - return fmt.Errorf("open old WAL: %w", err) - } - defer w.Close() - - rdr := w.Reader() - - var ( - enc record.Encoder - b []byte - ) - decErr := rdr.Read( - func(s []record.RefSeries) { - if err != nil { - return - } - err = repl.Log(enc.Series(s, b[:0])) - }, - func(s []record.RefSample) { - if err != nil { - return - } - err = repl.Log(enc.Samples(s, b[:0])) - }, - func(s []tombstones.Stone) { - if err != nil { - return - } - err = repl.Log(enc.Tombstones(s, b[:0])) - }, - ) - if decErr != nil { - return fmt.Errorf("decode old entries: %w", err) - } - if err != nil { - return fmt.Errorf("write new entries: %w", err) - } - // We explicitly close even when there is a defer for Windows to be - // able to delete it. The defer is in place to close it in-case there - // are errors above. - if err := w.Close(); err != nil { - return fmt.Errorf("close old WAL: %w", err) - } - if err := repl.Close(); err != nil { - return fmt.Errorf("close new WAL: %w", err) - } - if err := fileutil.Replace(tmpdir, dir); err != nil { - return fmt.Errorf("replace old WAL: %w", err) - } - return nil -} diff --git a/tsdb/wal_test.go b/tsdb/wal_test.go deleted file mode 100644 index 7794a54547..0000000000 --- a/tsdb/wal_test.go +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright 2017 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !windows - -package tsdb - -import ( - "encoding/binary" - "io" - "math/rand" - "os" - "path" - "path/filepath" - "testing" - "time" - - "github.com/go-kit/log" - "github.com/stretchr/testify/require" - - "github.com/prometheus/prometheus/model/labels" - "github.com/prometheus/prometheus/storage" - "github.com/prometheus/prometheus/tsdb/chunks" - "github.com/prometheus/prometheus/tsdb/record" - "github.com/prometheus/prometheus/tsdb/tombstones" - "github.com/prometheus/prometheus/tsdb/wlog" - "github.com/prometheus/prometheus/util/testutil" -) - -func TestSegmentWAL_cut(t *testing.T) { - tmpdir := t.TempDir() - - // This calls cut() implicitly the first time without a previous tail. - w, err := OpenSegmentWAL(tmpdir, nil, 0, nil) - require.NoError(t, err) - - require.NoError(t, w.write(WALEntrySeries, 1, []byte("Hello World!!"))) - - require.NoError(t, w.cut()) - - // Cutting creates a new file. - require.Len(t, w.files, 2) - - require.NoError(t, w.write(WALEntrySeries, 1, []byte("Hello World!!"))) - - require.NoError(t, w.Close()) - - for _, of := range w.files { - f, err := os.Open(of.Name()) - require.NoError(t, err) - - // Verify header data. - metab := make([]byte, 8) - _, err = f.Read(metab) - require.NoError(t, err) - require.Equal(t, WALMagic, binary.BigEndian.Uint32(metab[:4])) - require.Equal(t, WALFormatDefault, metab[4]) - - // We cannot actually check for correct pre-allocation as it is - // optional per filesystem and handled transparently. - et, flag, b, err := newWALReader(nil, nil).entry(f) - require.NoError(t, err) - require.Equal(t, WALEntrySeries, et) - require.Equal(t, byte(walSeriesSimple), flag) - require.Equal(t, []byte("Hello World!!"), b) - } -} - -func TestSegmentWAL_Truncate(t *testing.T) { - const ( - numMetrics = 20000 - batch = 100 - ) - series, err := labels.ReadLabels(filepath.Join("testdata", "20kseries.json"), numMetrics) - require.NoError(t, err) - - dir := t.TempDir() - - w, err := OpenSegmentWAL(dir, nil, 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(w) - w.segmentSize = 10000 - - for i := 0; i < numMetrics; i += batch { - var rs []record.RefSeries - - for j, s := range series[i : i+batch] { - rs = append(rs, record.RefSeries{Labels: s, Ref: chunks.HeadSeriesRef(i+j) + 1}) - } - err := w.LogSeries(rs) - require.NoError(t, err) - } - - // We mark the 2nd half of the files with a min timestamp that should discard - // them from the selection of compactable files. - for i, f := range w.files[len(w.files)/2:] { - f.maxTime = int64(1000 + i) - } - // All series in those files must be preserved regarding of the provided postings list. - boundarySeries := w.files[len(w.files)/2].minSeries - - // We truncate while keeping every 2nd series. - keep := map[chunks.HeadSeriesRef]struct{}{} - for i := 1; i <= numMetrics; i += 2 { - keep[chunks.HeadSeriesRef(i)] = struct{}{} - } - keepf := func(id chunks.HeadSeriesRef) bool { - _, ok := keep[id] - return ok - } - - err = w.Truncate(1000, keepf) - require.NoError(t, err) - - var expected []record.RefSeries - - for i := 1; i <= numMetrics; i++ { - if i%2 == 1 || chunks.HeadSeriesRef(i) >= boundarySeries { - expected = append(expected, record.RefSeries{Ref: chunks.HeadSeriesRef(i), Labels: series[i-1]}) - } - } - - // Call Truncate once again to see whether we can read the written file without - // creating a new WAL. - err = w.Truncate(1000, keepf) - require.NoError(t, err) - require.NoError(t, w.Close()) - - // The same again with a new WAL. - w, err = OpenSegmentWAL(dir, nil, 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(w) - - var readSeries []record.RefSeries - r := w.Reader() - - require.NoError(t, r.Read(func(s []record.RefSeries) { - readSeries = append(readSeries, s...) - }, nil, nil)) - - testutil.RequireEqual(t, expected, readSeries) -} - -// Symmetrical test of reading and writing to the WAL via its main interface. -func TestSegmentWAL_Log_Restore(t *testing.T) { - const ( - numMetrics = 50 - iterations = 5 - stepSize = 5 - ) - // Generate testing data. It does not make semantic sense but - // for the purpose of this test. - series, err := labels.ReadLabels(filepath.Join("testdata", "20kseries.json"), numMetrics) - require.NoError(t, err) - - dir := t.TempDir() - - var ( - recordedSeries [][]record.RefSeries - recordedSamples [][]record.RefSample - recordedDeletes [][]tombstones.Stone - ) - var totalSamples int - - // Open WAL a bunch of times, validate all previous data can be read, - // write more data to it, close it. - for k := 0; k < numMetrics; k += numMetrics / iterations { - w, err := OpenSegmentWAL(dir, nil, 0, nil) - require.NoError(t, err) - - // Set smaller segment size so we can actually write several files. - w.segmentSize = 1000 * 1000 - - r := w.Reader() - - var ( - resultSeries [][]record.RefSeries - resultSamples [][]record.RefSample - resultDeletes [][]tombstones.Stone - ) - - serf := func(series []record.RefSeries) { - if len(series) > 0 { - clsets := make([]record.RefSeries, len(series)) - copy(clsets, series) - resultSeries = append(resultSeries, clsets) - } - } - smplf := func(smpls []record.RefSample) { - if len(smpls) > 0 { - csmpls := make([]record.RefSample, len(smpls)) - copy(csmpls, smpls) - resultSamples = append(resultSamples, csmpls) - } - } - - delf := func(stones []tombstones.Stone) { - if len(stones) > 0 { - cst := make([]tombstones.Stone, len(stones)) - copy(cst, stones) - resultDeletes = append(resultDeletes, cst) - } - } - - require.NoError(t, r.Read(serf, smplf, delf)) - - testutil.RequireEqual(t, recordedSamples, resultSamples) - testutil.RequireEqual(t, recordedSeries, resultSeries) - testutil.RequireEqual(t, recordedDeletes, resultDeletes) - - series := series[k : k+(numMetrics/iterations)] - - // Insert in batches and generate different amounts of samples for each. - for i := 0; i < len(series); i += stepSize { - var samples []record.RefSample - var stones []tombstones.Stone - - for j := 0; j < i*10; j++ { - samples = append(samples, record.RefSample{ - Ref: chunks.HeadSeriesRef(j % 10000), - T: int64(j * 2), - V: rand.Float64(), - }) - } - - for j := 0; j < i*20; j++ { - ts := rand.Int63() - stones = append(stones, tombstones.Stone{Ref: storage.SeriesRef(rand.Uint64()), Intervals: tombstones.Intervals{{Mint: ts, Maxt: ts + rand.Int63n(10000)}}}) - } - - lbls := series[i : i+stepSize] - series := make([]record.RefSeries, 0, len(series)) - for j, l := range lbls { - series = append(series, record.RefSeries{ - Ref: chunks.HeadSeriesRef(i + j), - Labels: l, - }) - } - - require.NoError(t, w.LogSeries(series)) - require.NoError(t, w.LogSamples(samples)) - require.NoError(t, w.LogDeletes(stones)) - - if len(lbls) > 0 { - recordedSeries = append(recordedSeries, series) - } - if len(samples) > 0 { - recordedSamples = append(recordedSamples, samples) - totalSamples += len(samples) - } - if len(stones) > 0 { - recordedDeletes = append(recordedDeletes, stones) - } - } - - require.NoError(t, w.Close()) - } -} - -func TestWALRestoreCorrupted_invalidSegment(t *testing.T) { - dir := t.TempDir() - - wal, err := OpenSegmentWAL(dir, nil, 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(wal) - - _, err = wal.createSegmentFile(filepath.Join(dir, "000000")) - require.NoError(t, err) - f, err := wal.createSegmentFile(filepath.Join(dir, "000001")) - require.NoError(t, err) - f2, err := wal.createSegmentFile(filepath.Join(dir, "000002")) - require.NoError(t, err) - require.NoError(t, f2.Close()) - - // Make header of second segment invalid. - _, err = f.WriteAt([]byte{1, 2, 3, 4}, 0) - require.NoError(t, err) - require.NoError(t, f.Close()) - - require.NoError(t, wal.Close()) - - wal, err = OpenSegmentWAL(dir, log.NewLogfmtLogger(os.Stderr), 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(wal) - - files, err := os.ReadDir(dir) - require.NoError(t, err) - fns := []string{} - for _, f := range files { - fns = append(fns, f.Name()) - } - require.Equal(t, []string{"000000"}, fns) -} - -// Test reading from a WAL that has been corrupted through various means. -func TestWALRestoreCorrupted(t *testing.T) { - cases := []struct { - name string - f func(*testing.T, *SegmentWAL) - }{ - { - name: "truncate_checksum", - f: func(t *testing.T, w *SegmentWAL) { - f, err := os.OpenFile(w.files[0].Name(), os.O_WRONLY, 0o666) - require.NoError(t, err) - defer f.Close() - - off, err := f.Seek(0, io.SeekEnd) - require.NoError(t, err) - - require.NoError(t, f.Truncate(off-1)) - }, - }, - { - name: "truncate_body", - f: func(t *testing.T, w *SegmentWAL) { - f, err := os.OpenFile(w.files[0].Name(), os.O_WRONLY, 0o666) - require.NoError(t, err) - defer f.Close() - - off, err := f.Seek(0, io.SeekEnd) - require.NoError(t, err) - - require.NoError(t, f.Truncate(off-8)) - }, - }, - { - name: "body_content", - f: func(t *testing.T, w *SegmentWAL) { - f, err := os.OpenFile(w.files[0].Name(), os.O_WRONLY, 0o666) - require.NoError(t, err) - defer f.Close() - - off, err := f.Seek(0, io.SeekEnd) - require.NoError(t, err) - - // Write junk before checksum starts. - _, err = f.WriteAt([]byte{1, 2, 3, 4}, off-8) - require.NoError(t, err) - }, - }, - { - name: "checksum", - f: func(t *testing.T, w *SegmentWAL) { - f, err := os.OpenFile(w.files[0].Name(), os.O_WRONLY, 0o666) - require.NoError(t, err) - defer f.Close() - - off, err := f.Seek(0, io.SeekEnd) - require.NoError(t, err) - - // Write junk into checksum - _, err = f.WriteAt([]byte{1, 2, 3, 4}, off-4) - require.NoError(t, err) - }, - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - // Generate testing data. It does not make semantic sense but - // for the purpose of this test. - dir := t.TempDir() - - w, err := OpenSegmentWAL(dir, nil, 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(w) - - require.NoError(t, w.LogSamples([]record.RefSample{{T: 1, V: 2}})) - require.NoError(t, w.LogSamples([]record.RefSample{{T: 2, V: 3}})) - - require.NoError(t, w.cut()) - - // Sleep 2 seconds to avoid error where cut and test "cases" function may write or - // truncate the file out of orders as "cases" are not synchronized with cut. - // Hopefully cut will complete by 2 seconds. - time.Sleep(2 * time.Second) - - require.NoError(t, w.LogSamples([]record.RefSample{{T: 3, V: 4}})) - require.NoError(t, w.LogSamples([]record.RefSample{{T: 5, V: 6}})) - - require.NoError(t, w.Close()) - - // cut() truncates and fsyncs the first segment async. If it happens after - // the corruption we apply below, the corruption will be overwritten again. - // Fire and forget a sync to avoid flakiness. - w.files[0].Sync() - // Corrupt the second entry in the first file. - // After re-opening we must be able to read the first entry - // and the rest, including the second file, must be truncated for clean further - // writes. - c.f(t, w) - - logger := log.NewLogfmtLogger(os.Stderr) - - w2, err := OpenSegmentWAL(dir, logger, 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(w2) - - r := w2.Reader() - - serf := func(l []record.RefSeries) { - require.Empty(t, l) - } - - // Weird hack to check order of reads. - i := 0 - samplef := func(s []record.RefSample) { - if i == 0 { - require.Equal(t, []record.RefSample{{T: 1, V: 2}}, s) - i++ - } else { - require.Equal(t, []record.RefSample{{T: 99, V: 100}}, s) - } - } - - require.NoError(t, r.Read(serf, samplef, nil)) - - require.NoError(t, w2.LogSamples([]record.RefSample{{T: 99, V: 100}})) - require.NoError(t, w2.Close()) - - // We should see the first valid entry and the new one, everything after - // is truncated. - w3, err := OpenSegmentWAL(dir, logger, 0, nil) - require.NoError(t, err) - defer func(wal *SegmentWAL) { require.NoError(t, wal.Close()) }(w3) - - r = w3.Reader() - - i = 0 - require.NoError(t, r.Read(serf, samplef, nil)) - }) - } -} - -func TestMigrateWAL_Empty(t *testing.T) { - // The migration procedure must properly deal with a zero-length segment, - // which is valid in the new format. - dir := t.TempDir() - - wdir := path.Join(dir, "wal") - - // Initialize empty WAL. - w, err := wlog.New(nil, nil, wdir, wlog.CompressionNone) - require.NoError(t, err) - require.NoError(t, w.Close()) - - require.NoError(t, MigrateWAL(nil, wdir)) -} - -func TestMigrateWAL_Fuzz(t *testing.T) { - dir := t.TempDir() - - wdir := path.Join(dir, "wal") - - // Should pass if no WAL exists yet. - require.NoError(t, MigrateWAL(nil, wdir)) - - oldWAL, err := OpenSegmentWAL(wdir, nil, time.Minute, nil) - require.NoError(t, err) - - // Write some data. - require.NoError(t, oldWAL.LogSeries([]record.RefSeries{ - {Ref: 100, Labels: labels.FromStrings("abc", "def", "123", "456")}, - {Ref: 1, Labels: labels.FromStrings("abc", "def2", "1234", "4567")}, - })) - require.NoError(t, oldWAL.LogSamples([]record.RefSample{ - {Ref: 1, T: 100, V: 200}, - {Ref: 2, T: 300, V: 400}, - })) - require.NoError(t, oldWAL.LogSeries([]record.RefSeries{ - {Ref: 200, Labels: labels.FromStrings("xyz", "def", "foo", "bar")}, - })) - require.NoError(t, oldWAL.LogSamples([]record.RefSample{ - {Ref: 3, T: 100, V: 200}, - {Ref: 4, T: 300, V: 400}, - })) - require.NoError(t, oldWAL.LogDeletes([]tombstones.Stone{ - {Ref: 1, Intervals: []tombstones.Interval{{Mint: 100, Maxt: 200}}}, - })) - - require.NoError(t, oldWAL.Close()) - - // Perform migration. - require.NoError(t, MigrateWAL(nil, wdir)) - - w, err := wlog.New(nil, nil, wdir, wlog.CompressionNone) - require.NoError(t, err) - - // We can properly write some new data after migration. - var enc record.Encoder - require.NoError(t, w.Log(enc.Samples([]record.RefSample{ - {Ref: 500, T: 1, V: 1}, - }, nil))) - - require.NoError(t, w.Close()) - - // Read back all data. - sr, err := wlog.NewSegmentsReader(wdir) - require.NoError(t, err) - - r := wlog.NewReader(sr) - var res []interface{} - dec := record.NewDecoder(labels.NewSymbolTable()) - - for r.Next() { - rec := r.Record() - - switch dec.Type(rec) { - case record.Series: - s, err := dec.Series(rec, nil) - require.NoError(t, err) - res = append(res, s) - case record.Samples: - s, err := dec.Samples(rec, nil) - require.NoError(t, err) - res = append(res, s) - case record.Tombstones: - s, err := dec.Tombstones(rec, nil) - require.NoError(t, err) - res = append(res, s) - default: - require.Fail(t, "unknown record type %d", dec.Type(rec)) - } - } - require.NoError(t, r.Err()) - - testutil.RequireEqual(t, []interface{}{ - []record.RefSeries{ - {Ref: 100, Labels: labels.FromStrings("abc", "def", "123", "456")}, - {Ref: 1, Labels: labels.FromStrings("abc", "def2", "1234", "4567")}, - }, - []record.RefSample{{Ref: 1, T: 100, V: 200}, {Ref: 2, T: 300, V: 400}}, - []record.RefSeries{ - {Ref: 200, Labels: labels.FromStrings("xyz", "def", "foo", "bar")}, - }, - []record.RefSample{{Ref: 3, T: 100, V: 200}, {Ref: 4, T: 300, V: 400}}, - []tombstones.Stone{{Ref: 1, Intervals: []tombstones.Interval{{Mint: 100, Maxt: 200}}}}, - []record.RefSample{{Ref: 500, T: 1, V: 1}}, - }, res) - - // Migrating an already migrated WAL shouldn't do anything. - require.NoError(t, MigrateWAL(nil, wdir)) -} From a0fbc75f341949bc90335799719599efc9660b99 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Thu, 14 Mar 2024 09:20:40 +0100 Subject: [PATCH 137/253] Add container_description.yml to repo sync Add the container_description.yml workflow to the repo file sync script. * Skip sync if there is no Dockerfile. * Fixup minor typo in container_description.yml. Signed-off-by: SuperQ --- .github/workflows/container_description.yml | 2 +- scripts/sync_repo_files.sh | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index eb505207cb..f922e3a07c 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -32,7 +32,7 @@ jobs: PushQuayIoReadme: runs-on: ubuntu-latest - name: Push README to Docker Hub + name: Push README to quay.io steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/scripts/sync_repo_files.sh b/scripts/sync_repo_files.sh index 6965a45452..a46f289c49 100755 --- a/scripts/sync_repo_files.sh +++ b/scripts/sync_repo_files.sh @@ -37,7 +37,7 @@ if [ -z "${GITHUB_TOKEN}" ]; then fi # List of files that should be synced. -SYNC_FILES="CODE_OF_CONDUCT.md LICENSE Makefile.common SECURITY.md .yamllint scripts/golangci-lint.yml .github/workflows/scorecards.yml" +SYNC_FILES="CODE_OF_CONDUCT.md LICENSE Makefile.common SECURITY.md .yamllint scripts/golangci-lint.yml .github/workflows/scorecards.yml .github/workflows/container_description.yml" # Go to the root of the repo cd "$(git rev-parse --show-cdup)" || exit 1 @@ -99,6 +99,15 @@ check_go() { curl -sLf -o /dev/null "https://raw.githubusercontent.com/${org_repo}/${default_branch}/go.mod" } +check_docker() { + local org_repo + local default_branch + org_repo="$1" + default_branch="$2" + + curl -sLf -o /dev/null "https://raw.githubusercontent.com/${org_repo}/${default_branch}/Dockerfile" +} + process_repo() { local org_repo local default_branch @@ -119,6 +128,10 @@ process_repo() { echo "${org_repo} is not Go, skipping golangci-lint.yml." continue fi + if [[ "${source_file}" == '.github/workflows/container_description.yml' ]] && ! check_docker "${org_repo}" "${default_branch}" ; then + echo "${org_repo} has no Dockerfile, skipping container_description.yml." + continue + fi if [[ "${source_file}" == 'LICENSE' ]] && ! check_license "${target_file}" ; then echo "LICENSE in ${org_repo} is not apache, skipping." continue From 1de49d5b6915620da666d0e9872413f9091f1d93 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Thu, 14 Mar 2024 11:15:17 +0100 Subject: [PATCH 138/253] Remove unused function tsdb/chunks.PopulatedChunk (#13763) Signed-off-by: Arve Knudsen --- tsdb/chunks/chunks.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tsdb/chunks/chunks.go b/tsdb/chunks/chunks.go index 543b98c289..0826f69670 100644 --- a/tsdb/chunks/chunks.go +++ b/tsdb/chunks/chunks.go @@ -202,15 +202,6 @@ func ChunkFromSamplesGeneric(s Samples) (Meta, error) { }, nil } -// PopulatedChunk creates a chunk populated with samples every second starting at minTime. -func PopulatedChunk(numSamples int, minTime int64) (Meta, error) { - samples := make([]Sample, numSamples) - for i := 0; i < numSamples; i++ { - samples[i] = sample{t: minTime + int64(i*1000), f: 1.0} - } - return ChunkFromSamples(samples) -} - // ChunkMetasToSamples converts a slice of chunk meta data to a slice of samples. // Used in tests to compare the content of chunks. func ChunkMetasToSamples(chunks []Meta) (result []Sample) { From 3eed6c760a5026cd68938d208d16f9264cf509e6 Mon Sep 17 00:00:00 2001 From: machine424 Date: Thu, 14 Mar 2024 18:35:40 +0100 Subject: [PATCH 139/253] adjust signal termination warning log Signed-off-by: machine424 --- cmd/prometheus/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index 614d884637..f64c00e824 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -960,8 +960,8 @@ func main() { func() error { // Don't forget to release the reloadReady channel so that waiting blocks can exit normally. select { - case <-term: - level.Warn(logger).Log("msg", "Received SIGTERM, exiting gracefully...") + case sig := <-term: + level.Warn(logger).Log("msg", "Received an OS signal, exiting gracefully...", "signal", sig.String()) reloadReady.Close() case <-webHandler.Quit(): level.Warn(logger).Log("msg", "Received termination request via web service, exiting gracefully...") From dca47ce2c98d16a5b5959ca9ea41bc7059a8da3c Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Thu, 14 Mar 2024 13:39:54 +1100 Subject: [PATCH 140/253] Only run on prometheus/prometheus repo Signed-off-by: Charles Korn --- .github/workflows/container_description.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index f922e3a07c..5dfc8efa58 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -14,6 +14,7 @@ jobs: PushDockerHubReadme: runs-on: ubuntu-latest name: Push README to Docker Hub + if: github.repository == 'prometheus/prometheus' steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -33,6 +34,7 @@ jobs: PushQuayIoReadme: runs-on: ubuntu-latest name: Push README to quay.io + if: github.repository == 'prometheus/prometheus' steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 From 3274cac0d383025a45655977704a7aeea60aef19 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 15 Mar 2024 08:51:57 +0000 Subject: [PATCH 141/253] TSDB: remove unused function Was only used in old WAL implementation. Signed-off-by: Bryan Boreham --- tsdb/db.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/tsdb/db.go b/tsdb/db.go index 7aa68da500..33b7e8ab65 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -2225,23 +2225,6 @@ func sequenceFiles(dir string) ([]string, error) { return res, nil } -func nextSequenceFile(dir string) (string, int, error) { - files, err := os.ReadDir(dir) - if err != nil { - return "", 0, err - } - - i := uint64(0) - for _, f := range files { - j, err := strconv.ParseUint(f.Name(), 10, 64) - if err != nil { - continue - } - i = j - } - return filepath.Join(dir, fmt.Sprintf("%0.6d", i+1)), int(i + 1), nil -} - func exponential(d, min, max time.Duration) time.Duration { d *= 2 if d < min { From d45b5deb75d3637a9198153030ad2041b2a7fed9 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 15 Mar 2024 08:54:47 +0000 Subject: [PATCH 142/253] TSDB: move function only used in tests Signed-off-by: Bryan Boreham --- tsdb/block_test.go | 16 ++++++++++++++++ tsdb/db.go | 17 ----------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/tsdb/block_test.go b/tsdb/block_test.go index ad7eb55575..21e20a61c8 100644 --- a/tsdb/block_test.go +++ b/tsdb/block_test.go @@ -209,6 +209,22 @@ func TestCorruptedChunk(t *testing.T) { } } +func sequenceFiles(dir string) ([]string, error) { + files, err := os.ReadDir(dir) + if err != nil { + return nil, err + } + var res []string + + for _, fi := range files { + if _, err := strconv.ParseUint(fi.Name(), 10, 64); err != nil { + continue + } + res = append(res, filepath.Join(dir, fi.Name())) + } + return res, nil +} + func TestLabelValuesWithMatchers(t *testing.T) { tmpdir := t.TempDir() ctx := context.Background() diff --git a/tsdb/db.go b/tsdb/db.go index 33b7e8ab65..dc77978b7f 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -24,7 +24,6 @@ import ( "os" "path/filepath" "slices" - "strconv" "strings" "sync" "time" @@ -2209,22 +2208,6 @@ func blockDirs(dir string) ([]string, error) { return dirs, nil } -func sequenceFiles(dir string) ([]string, error) { - files, err := os.ReadDir(dir) - if err != nil { - return nil, err - } - var res []string - - for _, fi := range files { - if _, err := strconv.ParseUint(fi.Name(), 10, 64); err != nil { - continue - } - res = append(res, filepath.Join(dir, fi.Name())) - } - return res, nil -} - func exponential(d, min, max time.Duration) time.Duration { d *= 2 if d < min { From cef1025ea80a1a901cf0e2bbe7b589563dd16a8e Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Fri, 15 Mar 2024 10:11:04 +0100 Subject: [PATCH 143/253] tsdb/wlog.Checkpoint: Fix counting of histogram samples Signed-off-by: Arve Knudsen --- tsdb/wlog/checkpoint.go | 4 ++-- tsdb/wlog/checkpoint_test.go | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tsdb/wlog/checkpoint.go b/tsdb/wlog/checkpoint.go index 4ad1bb2365..5491d9718e 100644 --- a/tsdb/wlog/checkpoint.go +++ b/tsdb/wlog/checkpoint.go @@ -224,8 +224,8 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head if len(repl) > 0 { buf = enc.HistogramSamples(repl, buf) } - stats.TotalSamples += len(samples) - stats.DroppedSamples += len(samples) - len(repl) + stats.TotalSamples += len(histogramSamples) + stats.DroppedSamples += len(histogramSamples) - len(repl) case record.Tombstones: tstones, err = dec.Tombstones(rec, tstones) diff --git a/tsdb/wlog/checkpoint_test.go b/tsdb/wlog/checkpoint_test.go index 142a5a9d49..0d22171768 100644 --- a/tsdb/wlog/checkpoint_test.go +++ b/tsdb/wlog/checkpoint_test.go @@ -220,12 +220,14 @@ func TestCheckpoint(t *testing.T) { } require.NoError(t, w.Close()) - _, err = Checkpoint(log.NewNopLogger(), w, 100, 106, func(x chunks.HeadSeriesRef) bool { + stats, err := Checkpoint(log.NewNopLogger(), w, 100, 106, func(x chunks.HeadSeriesRef) bool { return x%2 == 0 }, last/2) require.NoError(t, err) require.NoError(t, w.Truncate(107)) require.NoError(t, DeleteCheckpoints(w.Dir(), 106)) + require.Equal(t, histogramsInWAL+samplesInWAL, stats.TotalSamples) + require.Greater(t, stats.DroppedSamples, 0) // Only the new checkpoint should be left. files, err := os.ReadDir(dir) From 53091126c28f518c154c365a47d617c9ee7634de Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Wed, 13 Mar 2024 15:36:53 +0100 Subject: [PATCH 144/253] Chunked remote read: close the querier earlier I have seen prometheis instances misebehaving because of broken chinked remote read requests. In order to avoid OOM's when this happens, I propose to close the queries used by the streamed remote read requests earlier. Signed-off-by: Julien Pivotto --- storage/remote/read_handler.go | 53 ++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/storage/remote/read_handler.go b/storage/remote/read_handler.go index ffc64c9c3f..2a00ce897f 100644 --- a/storage/remote/read_handler.go +++ b/storage/remote/read_handler.go @@ -202,34 +202,16 @@ func (h *readHandler) remoteReadStreamedXORChunks(ctx context.Context, w http.Re return err } - querier, err := h.queryable.ChunkQuerier(query.StartTimestampMs, query.EndTimestampMs) - if err != nil { + chunks := h.getChunkSeriesSet(ctx, query, filteredMatchers) + if err := chunks.Err(); err != nil { return err } - defer func() { - if err := querier.Close(); err != nil { - level.Warn(h.logger).Log("msg", "Error on chunk querier close", "err", err.Error()) - } - }() - - var hints *storage.SelectHints - if query.Hints != nil { - hints = &storage.SelectHints{ - Start: query.Hints.StartMs, - End: query.Hints.EndMs, - Step: query.Hints.StepMs, - Func: query.Hints.Func, - Grouping: query.Hints.Grouping, - Range: query.Hints.RangeMs, - By: query.Hints.By, - } - } ws, err := StreamChunkedReadResponses( NewChunkedWriter(w, f), int64(i), // The streaming API has to provide the series sorted. - querier.Select(ctx, true, hints, filteredMatchers...), + chunks, sortedExternalLabels, h.remoteReadMaxBytesInFrame, h.marshalPool, @@ -254,6 +236,35 @@ func (h *readHandler) remoteReadStreamedXORChunks(ctx context.Context, w http.Re } } +// getChunkSeriesSet executes a query to retrieve a ChunkSeriesSet, +// encapsulating the operation in its own function to ensure timely release of +// the querier resources. +func (h *readHandler) getChunkSeriesSet(ctx context.Context, query *prompb.Query, filteredMatchers []*labels.Matcher) storage.ChunkSeriesSet { + querier, err := h.queryable.ChunkQuerier(query.StartTimestampMs, query.EndTimestampMs) + if err != nil { + return storage.ErrChunkSeriesSet(err) + } + defer func() { + if err := querier.Close(); err != nil { + level.Warn(h.logger).Log("msg", "Error on chunk querier close", "err", err.Error()) + } + }() + + var hints *storage.SelectHints + if query.Hints != nil { + hints = &storage.SelectHints{ + Start: query.Hints.StartMs, + End: query.Hints.EndMs, + Step: query.Hints.StepMs, + Func: query.Hints.Func, + Grouping: query.Hints.Grouping, + Range: query.Hints.RangeMs, + By: query.Hints.By, + } + } + return querier.Select(ctx, true, hints, filteredMatchers...) +} + // filterExtLabelsFromMatchers change equality matchers which match external labels // to a matcher that looks for an empty label, // as that label should not be present in the storage. From c8c1ab36dc0ce6fda90e0f0a266e6f3772384ca3 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 15 Mar 2024 16:47:14 +0000 Subject: [PATCH 145/253] MAINTAINERS: Add Bryan Boreham, Ayoub Mrini (#13771) Also simplify structure. Ordering of 'general' maintainers is alphabetical by 2nd name. Signed-off-by: Bryan Boreham --- MAINTAINERS.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a776eb3594..8113ac5296 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,6 +1,10 @@ # Maintainers -Julien Pivotto ( / @roidelapluie) and Levi Harrison ( / @LeviHarrison) are the main/default maintainers, some parts of the codebase have other maintainers: +General maintainers: +* Bryan Boreham (bjboreham@gmail.com / @bboreham) +* Levi Harrison (levi@leviharrison.dev / @LeviHarrison) +* Ayoub Mrini (ayoubmrini424@gmail.com / @machine424) +* Julien Pivotto (roidelapluie@prometheus.io / @roidelapluie) * `cmd` * `promtool`: David Leadbeater ( / @dgl) @@ -19,7 +23,6 @@ George Krajcsovits ( / @krajorama) * `module`: Augustin Husson ( @nexucis) * `Makefile` and related build configuration: Simon Pasquier ( / @simonpasquier), Ben Kochie ( / @SuperQ) - For the sake of brevity, not all subtrees are explicitly listed. Due to the size of this repository, the natural changes in focus of maintainers over time, and nuances of where particular features live, this list will always be From b7047f7fcb3fb35c6ebf349ac5b7a65973befcde Mon Sep 17 00:00:00 2001 From: Darshan Chaudhary Date: Sat, 16 Mar 2024 00:05:16 +0530 Subject: [PATCH 146/253] Fix retention boundary so 2h retention deletes blocks right at the 2h boundary (#9633) Signed-off-by: darshanime --- CHANGELOG.md | 4 ++++ tsdb/db.go | 2 +- tsdb/db_test.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b0350004f..da1979defd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## unreleased + +* [CHANGE] TSDB: Fix the predicate checking for blocks which are beyond the retention period to include the ones right at the retention boundary. #9633 + ## 2.50.1 / 2024-02-26 * [BUGFIX] API: Fix metadata API using wrong field names. #13633 diff --git a/tsdb/db.go b/tsdb/db.go index 4998da6aa7..eaba508558 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -1615,7 +1615,7 @@ func BeyondTimeRetention(db *DB, blocks []*Block) (deletable map[ulid.ULID]struc for i, block := range blocks { // The difference between the first block and this block is larger than // the retention period so any blocks after that are added as deletable. - if i > 0 && blocks[0].Meta().MaxTime-block.Meta().MaxTime > db.opts.RetentionDuration { + if i > 0 && blocks[0].Meta().MaxTime-block.Meta().MaxTime >= db.opts.RetentionDuration { for _, b := range blocks[i:] { deletable[b.meta.ULID] = struct{}{} } diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 45a16b8ba3..9e88877890 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -681,6 +681,34 @@ func TestDB_Snapshot(t *testing.T) { require.Equal(t, 1000.0, sum) } +func TestDB_BeyondTimeRetention(t *testing.T) { + opts := DefaultOptions() + opts.RetentionDuration = 100 + db := openTestDB(t, opts, nil) + defer func() { + require.NoError(t, db.Close()) + }() + + // We have 4 blocks, 3 of which are beyond the retention duration. + metas := []BlockMeta{ + {MinTime: 300, MaxTime: 500}, + {MinTime: 200, MaxTime: 300}, + {MinTime: 100, MaxTime: 200}, + {MinTime: 0, MaxTime: 100}, + } + + for _, m := range metas { + createBlock(t, db.Dir(), genSeries(1, 1, m.MinTime, m.MaxTime)) + } + + // Reloading should truncate the 3 blocks which are >= the retention period. + require.NoError(t, db.reloadBlocks()) + blocks := db.Blocks() + require.Len(t, blocks, 1) + require.Equal(t, metas[0].MinTime, blocks[0].Meta().MinTime) + require.Equal(t, metas[0].MaxTime, blocks[0].Meta().MaxTime) +} + // TestDB_Snapshot_ChunksOutsideOfCompactedRange ensures that a snapshot removes chunks samples // that are outside the set block time range. // See https://github.com/prometheus/prometheus/issues/5105 From 302e151de8937c4c2c77567e33e7c9ae208a2e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 16 Mar 2024 12:06:57 +0100 Subject: [PATCH 147/253] {discovery,remote_write}/azure: Support default SDK authentication (#13099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * discovery/azure: Offer default SDK authentication Signed-off-by: Jan-Otto Kröpke --- config/config_test.go | 2 +- discovery/azure/azure.go | 15 +++++- docs/configuration/configuration.md | 9 +++- storage/remote/azuread/azuread.go | 48 ++++++++++++++++++- storage/remote/azuread/azuread_test.go | 38 +++++++++++++-- .../testdata/azuread_bad_oauthsdkconfig.yaml | 7 +++ .../azuread/testdata/azuread_good_sdk.yaml | 3 ++ 7 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 storage/remote/azuread/testdata/azuread_bad_oauthsdkconfig.yaml create mode 100644 storage/remote/azuread/testdata/azuread_good_sdk.yaml diff --git a/config/config_test.go b/config/config_test.go index 36b125f794..14981d25f0 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1840,7 +1840,7 @@ var expectedErrors = []struct { }, { filename: "azure_authentication_method.bad.yml", - errMsg: "unknown authentication_type \"invalid\". Supported types are \"OAuth\" or \"ManagedIdentity\"", + errMsg: "unknown authentication_type \"invalid\". Supported types are \"OAuth\", \"ManagedIdentity\" or \"SDK\"", }, { filename: "azure_bearertoken_basicauth.bad.yml", diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index 16628c7bfd..746496a699 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -65,6 +65,7 @@ const ( azureLabelMachineSize = azureLabel + "machine_size" authMethodOAuth = "OAuth" + authMethodSDK = "SDK" authMethodManagedIdentity = "ManagedIdentity" ) @@ -164,8 +165,8 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { } } - if c.AuthenticationMethod != authMethodOAuth && c.AuthenticationMethod != authMethodManagedIdentity { - return fmt.Errorf("unknown authentication_type %q. Supported types are %q or %q", c.AuthenticationMethod, authMethodOAuth, authMethodManagedIdentity) + if c.AuthenticationMethod != authMethodOAuth && c.AuthenticationMethod != authMethodManagedIdentity && c.AuthenticationMethod != authMethodSDK { + return fmt.Errorf("unknown authentication_type %q. Supported types are %q, %q or %q", c.AuthenticationMethod, authMethodOAuth, authMethodManagedIdentity, authMethodSDK) } return c.HTTPClientConfig.Validate() @@ -294,6 +295,16 @@ func newCredential(cfg SDConfig, policyClientOptions policy.ClientOptions) (azco return nil, err } credential = azcore.TokenCredential(secretCredential) + case authMethodSDK: + options := &azidentity.DefaultAzureCredentialOptions{ClientOptions: policyClientOptions} + if len(cfg.TenantID) != 0 { + options.TenantID = cfg.TenantID + } + sdkCredential, err := azidentity.NewDefaultAzureCredential(options) + if err != nil { + return nil, err + } + credential = azcore.TokenCredential(sdkCredential) } return credential, nil } diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index e134ae02b7..d751a4084e 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -600,8 +600,10 @@ See below for the configuration options for Azure discovery: # The Azure environment. [ environment: | default = AzurePublicCloud ] -# The authentication method, either OAuth or ManagedIdentity. +# The authentication method, either OAuth, ManagedIdentity or SDK. # See https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview +# SDK authentication method uses environment variables by default. +# See https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication [ authentication_method: | default = OAuth] # The subscription ID. Always required. subscription_id: @@ -3619,6 +3621,11 @@ azuread: [ client_secret: ] [ tenant_id: ] ] + # Azure SDK auth. + # See https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication + [ sdk: + [ tenant_id: ] ] + # Configures the remote write request's TLS settings. tls_config: [ ] diff --git a/storage/remote/azuread/azuread.go b/storage/remote/azuread/azuread.go index 20d48d0087..e2058fb54d 100644 --- a/storage/remote/azuread/azuread.go +++ b/storage/remote/azuread/azuread.go @@ -61,6 +61,12 @@ type OAuthConfig struct { TenantID string `yaml:"tenant_id,omitempty"` } +// SDKConfig is used to store azure SDK config values. +type SDKConfig struct { + // TenantID is the tenantId of the azure active directory application that is being used to authenticate. + TenantID string `yaml:"tenant_id,omitempty"` +} + // AzureADConfig is used to store the config values. type AzureADConfig struct { //nolint:revive // exported. // ManagedIdentity is the managed identity that is being used to authenticate. @@ -69,6 +75,9 @@ type AzureADConfig struct { //nolint:revive // exported. // OAuth is the oauth config that is being used to authenticate. OAuth *OAuthConfig `yaml:"oauth,omitempty"` + // OAuth is the oauth config that is being used to authenticate. + SDK *SDKConfig `yaml:"sdk,omitempty"` + // Cloud is the Azure cloud in which the service is running. Example: AzurePublic/AzureGovernment/AzureChina. Cloud string `yaml:"cloud,omitempty"` } @@ -102,14 +111,22 @@ func (c *AzureADConfig) Validate() error { return fmt.Errorf("must provide a cloud in the Azure AD config") } - if c.ManagedIdentity == nil && c.OAuth == nil { - return fmt.Errorf("must provide an Azure Managed Identity or Azure OAuth in the Azure AD config") + if c.ManagedIdentity == nil && c.OAuth == nil && c.SDK == nil { + return fmt.Errorf("must provide an Azure Managed Identity, Azure OAuth or Azure SDK in the Azure AD config") } if c.ManagedIdentity != nil && c.OAuth != nil { return fmt.Errorf("cannot provide both Azure Managed Identity and Azure OAuth in the Azure AD config") } + if c.ManagedIdentity != nil && c.SDK != nil { + return fmt.Errorf("cannot provide both Azure Managed Identity and Azure SDK in the Azure AD config") + } + + if c.OAuth != nil && c.SDK != nil { + return fmt.Errorf("cannot provide both Azure OAuth and Azure SDK in the Azure AD config") + } + if c.ManagedIdentity != nil { if c.ManagedIdentity.ClientID == "" { return fmt.Errorf("must provide an Azure Managed Identity client_id in the Azure AD config") @@ -143,6 +160,17 @@ func (c *AzureADConfig) Validate() error { } } + if c.SDK != nil { + var err error + + if c.SDK.TenantID != "" { + _, err = regexp.MatchString("^[0-9a-zA-Z-.]+$", c.SDK.TenantID) + if err != nil { + return fmt.Errorf("the provided Azure OAuth tenant_id is invalid") + } + } + } + return nil } @@ -225,6 +253,16 @@ func newTokenCredential(cfg *AzureADConfig) (azcore.TokenCredential, error) { } } + if cfg.SDK != nil { + sdkConfig := &SDKConfig{ + TenantID: cfg.SDK.TenantID, + } + cred, err = newSDKTokenCredential(clientOpts, sdkConfig) + if err != nil { + return nil, err + } + } + return cred, nil } @@ -241,6 +279,12 @@ func newOAuthTokenCredential(clientOpts *azcore.ClientOptions, oAuthConfig *OAut return azidentity.NewClientSecretCredential(oAuthConfig.TenantID, oAuthConfig.ClientID, oAuthConfig.ClientSecret, opts) } +// newSDKTokenCredential returns new SDK token credential. +func newSDKTokenCredential(clientOpts *azcore.ClientOptions, sdkConfig *SDKConfig) (azcore.TokenCredential, error) { + opts := &azidentity.DefaultAzureCredentialOptions{ClientOptions: *clientOpts, TenantID: sdkConfig.TenantID} + return azidentity.NewDefaultAzureCredential(opts) +} + // newTokenProvider helps to fetch accessToken for different types of credential. This also takes care of // refreshing the accessToken before expiry. This accessToken is attached to the Authorization header while making requests. func newTokenProvider(cfg *AzureADConfig, cred azcore.TokenCredential) (*tokenProvider, error) { diff --git a/storage/remote/azuread/azuread_test.go b/storage/remote/azuread/azuread_test.go index 5eed2c0b19..7c97138120 100644 --- a/storage/remote/azuread/azuread_test.go +++ b/storage/remote/azuread/azuread_test.go @@ -39,7 +39,7 @@ const ( testTokenString = "testTokenString" ) -var testTokenExpiry = time.Now().Add(5 * time.Second) +func testTokenExpiry() time.Time { return time.Now().Add(5 * time.Second) } type AzureAdTestSuite struct { suite.Suite @@ -94,7 +94,7 @@ func (ad *AzureAdTestSuite) TestAzureAdRoundTripper() { testToken := &azcore.AccessToken{ Token: testTokenString, - ExpiresOn: testTokenExpiry, + ExpiresOn: testTokenExpiry(), } ad.mockCredential.On("GetToken", mock.Anything, mock.Anything).Return(*testToken, nil) @@ -145,7 +145,7 @@ func TestAzureAdConfig(t *testing.T) { // Missing managedidentiy or oauth field. { filename: "testdata/azuread_bad_configmissing.yaml", - err: "must provide an Azure Managed Identity or Azure OAuth in the Azure AD config", + err: "must provide an Azure Managed Identity, Azure OAuth or Azure SDK in the Azure AD config", }, // Invalid managedidentity client id. { @@ -162,6 +162,11 @@ func TestAzureAdConfig(t *testing.T) { filename: "testdata/azuread_bad_twoconfig.yaml", err: "cannot provide both Azure Managed Identity and Azure OAuth in the Azure AD config", }, + // Invalid config when both sdk and oauth is provided. + { + filename: "testdata/azuread_bad_oauthsdkconfig.yaml", + err: "cannot provide both Azure OAuth and Azure SDK in the Azure AD config", + }, // Valid config with missing optionally cloud field. { filename: "testdata/azuread_good_cloudmissing.yaml", @@ -174,6 +179,10 @@ func TestAzureAdConfig(t *testing.T) { { filename: "testdata/azuread_good_oauth.yaml", }, + // Valid SDK config. + { + filename: "testdata/azuread_good_sdk.yaml", + }, } for _, c := range cases { _, err := loadAzureAdConfig(c.filename) @@ -232,6 +241,16 @@ func (s *TokenProviderTestSuite) TestNewTokenProvider() { }, err: "Cloud is not specified or is incorrect: ", }, + // Invalid tokenProvider for SDK. + { + cfg: &AzureADConfig{ + Cloud: "PublicAzure", + SDK: &SDKConfig{ + TenantID: dummyTenantID, + }, + }, + err: "Cloud is not specified or is incorrect: ", + }, // Valid tokenProvider for managedidentity. { cfg: &AzureADConfig{ @@ -252,6 +271,15 @@ func (s *TokenProviderTestSuite) TestNewTokenProvider() { }, }, }, + // Valid tokenProvider for SDK. + { + cfg: &AzureADConfig{ + Cloud: "AzurePublic", + SDK: &SDKConfig{ + TenantID: dummyTenantID, + }, + }, + }, } mockGetTokenCallCounter := 1 for _, c := range cases { @@ -264,11 +292,11 @@ func (s *TokenProviderTestSuite) TestNewTokenProvider() { } else { testToken := &azcore.AccessToken{ Token: testTokenString, - ExpiresOn: testTokenExpiry, + ExpiresOn: testTokenExpiry(), } s.mockCredential.On("GetToken", mock.Anything, mock.Anything).Return(*testToken, nil).Once(). - On("GetToken", mock.Anything, mock.Anything).Return(getToken(), nil) + On("GetToken", mock.Anything, mock.Anything).Return(getToken(), nil).Once() actualTokenProvider, actualErr := newTokenProvider(c.cfg, s.mockCredential) diff --git a/storage/remote/azuread/testdata/azuread_bad_oauthsdkconfig.yaml b/storage/remote/azuread/testdata/azuread_bad_oauthsdkconfig.yaml new file mode 100644 index 0000000000..825759d313 --- /dev/null +++ b/storage/remote/azuread/testdata/azuread_bad_oauthsdkconfig.yaml @@ -0,0 +1,7 @@ +cloud: AzurePublic +oauth: + client_id: 00000000-0000-0000-0000-000000000000 + client_secret: Cl1ent$ecret! + tenant_id: 00000000-a12b-3cd4-e56f-000000000000 +sdk: + tenant_id: 00000000-a12b-3cd4-e56f-000000000000 diff --git a/storage/remote/azuread/testdata/azuread_good_sdk.yaml b/storage/remote/azuread/testdata/azuread_good_sdk.yaml new file mode 100644 index 0000000000..53de8897d5 --- /dev/null +++ b/storage/remote/azuread/testdata/azuread_good_sdk.yaml @@ -0,0 +1,3 @@ +cloud: AzurePublic +sdk: + tenant_id: 00000000-a12b-3cd4-e56f-000000000000 From ed9deb1f9080fe4de8d8053ea48ef353a88cc5c5 Mon Sep 17 00:00:00 2001 From: Goutham Date: Sun, 17 Mar 2024 12:23:25 +0100 Subject: [PATCH 148/253] Add Arve as OTLP ingest maintainer Also remove myself :) Arve has been doing a lot of maintainance on the upstream component and also reviewing PRs on Prometheus for this otlp ingest. I continue to have less and less time for this, so I'd like make Arve a maintainer for OTLP Ingestion. Signed-off-by: Goutham --- .github/CODEOWNERS | 2 +- MAINTAINERS.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 41530d4654..7f7cec9cda 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,7 +1,7 @@ /web/ui @juliusv /web/ui/module @juliusv @nexucis /storage/remote @cstyan @bwplotka @tomwilkie -/storage/remote/otlptranslator @gouthamve @jesusvazquez +/storage/remote/otlptranslator @aknuds1 @jesusvazquez /discovery/kubernetes @brancz /tsdb @jesusvazquez /promql @roidelapluie diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 8113ac5296..f23d0eb898 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -16,6 +16,7 @@ General maintainers: George Krajcsovits ( / @krajorama) * `storage` * `remote`: Callum Styan ( / @cstyan), Bartłomiej Płotka ( / @bwplotka), Tom Wilkie ( / @tomwilkie) + * `otlptranslator`: Arve Knudsen ( / @aknuds1), Jesús Vázquez ( / @jesusvazquez) * `tsdb`: Ganesh Vernekar ( / @codesome), Bartłomiej Płotka ( / @bwplotka), Jesús Vázquez ( / @jesusvazquez) * `agent`: Robert Fratto ( / @rfratto) * `web` From 969959895200686eef33874ba2e3b98d698817a1 Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Sun, 17 Mar 2024 16:56:12 +0100 Subject: [PATCH 149/253] Improve Labels.Compare performance w/stringlabels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was bored on a train and I spent some amount of time trying to scratch some nanoseconds off the Labels.Compare when running with stringlabels. I would be ashamed to admit the real amount of time I spent on it. The worst thing is, I can't really explain why this is performing so much better, and someone should re-run the benchmarks on their machine to confirm that it's not something related to general relativity because the train is moving. I also added some extra real-life benchmark cases with longer labelsets (these aren't the longest we have in production, but kubernetes labelsets are fairly common in Prometheus so I thought it would be nice to have them). My benchmarks show this diff: goos: darwin goarch: arm64 pkg: github.com/prometheus/prometheus/model/labels │ old │ new │ │ sec/op │ sec/op vs base │ Labels_Compare/equal 5.898n ± 0% 5.875n ± 1% -0.40% (p=0.037 n=10) Labels_Compare/not_equal 11.78n ± 2% 11.01n ± 1% -6.54% (p=0.000 n=10) Labels_Compare/different_sizes 4.959n ± 1% 4.906n ± 2% -1.05% (p=0.050 n=10) Labels_Compare/lots 21.32n ± 0% 17.54n ± 5% -17.75% (p=0.000 n=10) Labels_Compare/real_long_equal 15.06n ± 1% 14.92n ± 0% -0.93% (p=0.000 n=10) Labels_Compare/real_long_different_end 25.20n ± 0% 24.43n ± 0% -3.04% (p=0.000 n=10) geomean 11.86n 11.25n -5.16% Signed-off-by: Oleg Zaytsev --- model/labels/labels_stringlabels.go | 8 ++------ model/labels/labels_test.go | 10 ++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index 2e718c2b1f..44a2e0fb53 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -363,12 +363,8 @@ func Compare(a, b Labels) int { // Now we know that there is some difference before the end of a and b. // Go back through the fields and find which field that difference is in. - firstCharDifferent := i - for i = 0; ; { - size, nextI := decodeSize(a.data, i) - if nextI+size > firstCharDifferent { - break - } + firstCharDifferent, i := i, 0 + for size, nextI := decodeSize(a.data, i); nextI+size <= firstCharDifferent; size, nextI = decodeSize(a.data, i) { i = nextI + size } // Difference is inside this entry. diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index 49b4b4e67b..cedeb95a6c 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -532,6 +532,16 @@ var comparisonBenchmarkScenarios = []struct { FromStrings("aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrz"), FromStrings("aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrr"), }, + { + "real long equal", + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "d3ec90b2-4975-4607-b45d-b9ad64bb417e"), + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "d3ec90b2-4975-4607-b45d-b9ad64bb417e"), + }, + { + "real long different end", + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "d3ec90b2-4975-4607-b45d-b9ad64bb417e"), + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "deadbeef-0000-1111-2222-b9ad64bb417e"), + }, } func BenchmarkLabels_Equals(b *testing.B) { From b64171536302f41f482967acf331ad3a0df2a93a Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Mon, 18 Mar 2024 10:33:56 +1100 Subject: [PATCH 150/253] Support copying workflow as-is to other Prometheus repositories. Signed-off-by: Charles Korn --- .github/workflows/container_description.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index 5dfc8efa58..0b8a8cc05f 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -14,7 +14,7 @@ jobs: PushDockerHubReadme: runs-on: ubuntu-latest name: Push README to Docker Hub - if: github.repository == 'prometheus/prometheus' + if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -34,7 +34,7 @@ jobs: PushQuayIoReadme: runs-on: ubuntu-latest name: Push README to quay.io - if: github.repository == 'prometheus/prometheus' + if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. steps: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 From 161354e861f32f385d5f2a78c1b532b842eaccf1 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Mon, 18 Mar 2024 08:20:42 +0100 Subject: [PATCH 151/253] Add container_description.yml to force sync list Since we skip repos that don't have a Dockerfile, we can force sync the `.github/workflows/container_description.yml` config. Signed-off-by: SuperQ --- scripts/sync_repo_files.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sync_repo_files.sh b/scripts/sync_repo_files.sh index a46f289c49..6459fb1e7a 100755 --- a/scripts/sync_repo_files.sh +++ b/scripts/sync_repo_files.sh @@ -144,7 +144,7 @@ process_repo() { if [[ -z "${target_file}" ]]; then echo "${target_filename} doesn't exist in ${org_repo}" case "${source_file}" in - CODE_OF_CONDUCT.md | SECURITY.md) + CODE_OF_CONDUCT.md | SECURITY.md | .github/workflows/container_description.yml) echo "${source_file} missing in ${org_repo}, force updating." needs_update+=("${source_file}") ;; From d12e785075ed42f0d0edafe7018e2d512d0f8ce6 Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Mon, 18 Mar 2024 11:16:09 +0100 Subject: [PATCH 152/253] Improve readability As suggested by @bboreham Signed-off-by: Oleg Zaytsev --- model/labels/labels_stringlabels.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index 44a2e0fb53..9ef764daec 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -364,8 +364,10 @@ func Compare(a, b Labels) int { // Now we know that there is some difference before the end of a and b. // Go back through the fields and find which field that difference is in. firstCharDifferent, i := i, 0 - for size, nextI := decodeSize(a.data, i); nextI+size <= firstCharDifferent; size, nextI = decodeSize(a.data, i) { + size, nextI := decodeSize(a.data, i) + for nextI+size <= firstCharDifferent { i = nextI + size + size, nextI = decodeSize(a.data, i) } // Difference is inside this entry. aStr, _ := decodeString(a.data, i) From 9c7a7340630b61d296bb770e6d450b09be759878 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 19 Mar 2024 09:10:21 +0100 Subject: [PATCH 153/253] tsdb.BeyondTimeRetention: Fix comment and test at retention duration Signed-off-by: Arve Knudsen --- tsdb/db.go | 2 +- tsdb/db_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tsdb/db.go b/tsdb/db.go index e49c5811d2..f83c7c4958 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -1608,7 +1608,7 @@ func BeyondTimeRetention(db *DB, blocks []*Block) (deletable map[ulid.ULID]struc deletable = make(map[ulid.ULID]struct{}) for i, block := range blocks { - // The difference between the first block and this block is larger than + // The difference between the first block and this block is greater than or equal to // the retention period so any blocks after that are added as deletable. if i > 0 && blocks[0].Meta().MaxTime-block.Meta().MaxTime >= db.opts.RetentionDuration { for _, b := range blocks[i:] { diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 498e26c588..c7ea564d0e 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -689,10 +689,10 @@ func TestDB_BeyondTimeRetention(t *testing.T) { require.NoError(t, db.Close()) }() - // We have 4 blocks, 3 of which are beyond the retention duration. + // We have 4 blocks, 3 of which are beyond or at the retention duration. metas := []BlockMeta{ {MinTime: 300, MaxTime: 500}, - {MinTime: 200, MaxTime: 300}, + {MinTime: 200, MaxTime: 400}, {MinTime: 100, MaxTime: 200}, {MinTime: 0, MaxTime: 100}, } From 45c2b111871d569273d10484c65bc108d6dfa5ac Mon Sep 17 00:00:00 2001 From: SuperQ Date: Tue, 19 Mar 2024 06:53:10 +0100 Subject: [PATCH 154/253] Fixup make target in container description Use `docker-repo-name` as the make target so that a repo Makfile can override the common target implementation. Signed-off-by: SuperQ --- .github/workflows/container_description.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index 0b8a8cc05f..8a57107dd9 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -19,7 +19,7 @@ jobs: - name: git checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set docker hub repo name - run: echo "DOCKER_REPO_NAME=$(make common-docker-repo-name)" >> $GITHUB_ENV + run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV - name: Push README to Dockerhub uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 env: @@ -41,7 +41,7 @@ jobs: - name: Set quay.io org name run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV - name: Set quay.io repo name - run: echo "DOCKER_REPO_NAME=$(make common-docker-repo-name)" >> $GITHUB_ENV + run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV - name: Push README to quay.io uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 env: @@ -50,6 +50,3 @@ jobs: destination_container_repo: ${{ env.DOCKER_REPO_NAME }} provider: quay readme_file: 'README.md' - - - From c05c15512acb675e3f6cd662a6727854e93fc024 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 19 Mar 2024 11:49:40 +0100 Subject: [PATCH 155/253] Cut v2.51.0 (#13787) Signed-off-by: Bryan Boreham --- CHANGELOG.md | 4 ++-- VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a99777146..8951866819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 2.51.0-rc.0 / 2024-03-07 +## 2.51.0 / 2024-03-18 This version is built with Go 1.22.1. @@ -11,7 +11,7 @@ It is off by default; there will be an optional alternative image to try it out. * [FEATURE] Alerting: Relabel rules for AlertManagerConfig; allows routing alerts to different alertmanagers #12551, #13735 * [FEATURE] API: add limit param to series, label-names and label-values APIs #13396 * [FEATURE] UI (experimental native histograms): Add native histogram chart to Table view #13658 -* [FEATURE] Promtool: Add a "tsdb dump-openmetrics" to dump in OpemMetrics format. #13194 +* [FEATURE] Promtool: Add a "tsdb dump-openmetrics" to dump in OpenMetrics format. #13194 * [FEATURE] PromQL (experimental native histograms): Add histogram_avg function #13467 * [ENHANCEMENT] Rules: Evaluate independent rules concurrently #12946, #13527 * [ENHANCEMENT] Scraping (experimental native histograms): Support exemplars #13488 diff --git a/VERSION b/VERSION index 284f7bfe08..d66b738716 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.51.0-rc.0 +2.51.0 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index f352fb75b4..5139bce620 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.51.0-rc.0", + "version": "0.51.0", "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.51.0-rc.0", + "@prometheus-io/lezer-promql": "0.51.0", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index d5e53e9d1b..2983206f5c 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.51.0-rc.0", + "version": "0.51.0", "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 53ad8ea5a7..d2581baf40 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.51.0-rc.0", + "version": "0.51.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.51.0-rc.0", + "version": "0.51.0", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.51.0-rc.0", + "version": "0.51.0", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.51.0-rc.0", + "@prometheus-io/lezer-promql": "0.51.0", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.51.0-rc.0", + "version": "0.51.0", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.51.0-rc.0", + "version": "0.51.0", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.51.0-rc.0", + "@prometheus-io/codemirror-promql": "0.51.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index e541db85f5..7eedd0b217 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.51.0-rc.0" + "version": "0.51.0" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index ebc2f2d18b..4d2b5be920 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.51.0-rc.0", + "version": "0.51.0", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.51.0-rc.0", + "@prometheus-io/codemirror-promql": "0.51.0", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From e14af52e485e6fd7e9f257ff19a08bc1aabc6dad Mon Sep 17 00:00:00 2001 From: beorn7 Date: Tue, 19 Mar 2024 18:23:55 +0100 Subject: [PATCH 156/253] Tweak MAINTAINERS.md After #13771, the list for specific parts of the codebase looks like it is part of the "general maintainers" list. This commit makes things clearer. Signed-off-by: beorn7 --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 8113ac5296..2cb65c06d9 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,6 +6,7 @@ General maintainers: * Ayoub Mrini (ayoubmrini424@gmail.com / @machine424) * Julien Pivotto (roidelapluie@prometheus.io / @roidelapluie) +Maintainers for specific parts of the codebase: * `cmd` * `promtool`: David Leadbeater ( / @dgl) * `discovery` From 742196b6c4918d9d08b8349182b12471d9b223e1 Mon Sep 17 00:00:00 2001 From: Erlan Zholdubai uulu Date: Tue, 19 Mar 2024 10:37:43 -0700 Subject: [PATCH 157/253] add context cancellation check at get series result iteration (#13766) * add context cancellation check at get series iteration * add warnings and closer on error * add test --------- Signed-off-by: Erlan Zholdubai uulu --- web/api/v1/api.go | 3 +++ web/api/v1/api_test.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index b56026e45e..dc22365073 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -882,6 +882,9 @@ func (api *API) series(r *http.Request) (result apiFuncResult) { warnings := set.Warnings() for set.Next() { + if err := ctx.Err(); err != nil { + return apiFuncResult{nil, returnAPIError(err), warnings, closer} + } metrics = append(metrics, set.At().Labels()) if len(metrics) >= limit { diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 63a0225357..4158e544ef 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -3568,6 +3568,9 @@ func TestReturnAPIError(t *testing.T) { }, { err: errors.New("exec error"), expected: errorExec, + }, { + err: context.Canceled, + expected: errorCanceled, }, } From 11fc7b1d835e04a7f426841fd0cc8ab178d12717 Mon Sep 17 00:00:00 2001 From: dongjiang Date: Wed, 20 Mar 2024 02:24:37 +0800 Subject: [PATCH 158/253] chores: bump to golangci-lint v1.56.2 (#13753) bump to golangci-lint to v1.56.2 --------- Signed-off-by: dongjiang1989 --- .github/workflows/ci.yml | 2 +- Makefile.common | 2 +- scripts/golangci-lint.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e4b628699..8303cad528 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -162,7 +162,7 @@ jobs: with: args: --verbose # Make sure to sync this with Makefile.common and scripts/golangci-lint.yml. - version: v1.55.2 + version: v1.56.2 fuzzing: uses: ./.github/workflows/fuzzing.yml if: github.event_name == 'pull_request' diff --git a/Makefile.common b/Makefile.common index 49ed5f5478..483b3bf9df 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.55.2 +GOLANGCI_LINT_VERSION ?= v1.56.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) diff --git a/scripts/golangci-lint.yml b/scripts/golangci-lint.yml index 4dc7b830f6..5670d6079b 100644 --- a/scripts/golangci-lint.yml +++ b/scripts/golangci-lint.yml @@ -35,4 +35,4 @@ jobs: - name: Lint uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 with: - version: v1.55.2 + version: v1.56.2 From af694dc29549aee7862893b9916df1560b293f66 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 20 Mar 2024 09:07:16 +0100 Subject: [PATCH 159/253] Merge TestDB_BeyondTimeRetention into TestTimeRetention Signed-off-by: Arve Knudsen --- tsdb/db_test.go | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/tsdb/db_test.go b/tsdb/db_test.go index c7ea564d0e..50d5141bd5 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -681,34 +681,6 @@ func TestDB_Snapshot(t *testing.T) { require.Equal(t, 1000.0, sum) } -func TestDB_BeyondTimeRetention(t *testing.T) { - opts := DefaultOptions() - opts.RetentionDuration = 100 - db := openTestDB(t, opts, nil) - defer func() { - require.NoError(t, db.Close()) - }() - - // We have 4 blocks, 3 of which are beyond or at the retention duration. - metas := []BlockMeta{ - {MinTime: 300, MaxTime: 500}, - {MinTime: 200, MaxTime: 400}, - {MinTime: 100, MaxTime: 200}, - {MinTime: 0, MaxTime: 100}, - } - - for _, m := range metas { - createBlock(t, db.Dir(), genSeries(1, 1, m.MinTime, m.MaxTime)) - } - - // Reloading should truncate the 3 blocks which are >= the retention period. - require.NoError(t, db.reloadBlocks()) - blocks := db.Blocks() - require.Len(t, blocks, 1) - require.Equal(t, metas[0].MinTime, blocks[0].Meta().MinTime) - require.Equal(t, metas[0].MaxTime, blocks[0].Meta().MaxTime) -} - // TestDB_Snapshot_ChunksOutsideOfCompactedRange ensures that a snapshot removes chunks samples // that are outside the set block time range. // See https://github.com/prometheus/prometheus/issues/5105 @@ -1497,7 +1469,8 @@ func TestTimeRetention(t *testing.T) { }() blocks := []*BlockMeta{ - {MinTime: 500, MaxTime: 900}, // Oldest block + {MinTime: 500, MaxTime: 900}, // Oldest block + {MinTime: 500, MaxTime: 1000}, // Coinciding exactly with the retention duration. {MinTime: 1000, MaxTime: 1500}, {MinTime: 1500, MaxTime: 2000}, // Newest Block } @@ -1509,14 +1482,17 @@ func TestTimeRetention(t *testing.T) { require.NoError(t, db.reloadBlocks()) // Reload the db to register the new blocks. require.Equal(t, len(blocks), len(db.Blocks())) // Ensure all blocks are registered. - db.opts.RetentionDuration = blocks[2].MaxTime - blocks[1].MinTime + // By setting retention duration as follows, we verify that also blocks[1], + // coinciding exactly with the boundary, is deleted. + db.opts.RetentionDuration = blocks[3].MaxTime - blocks[1].MaxTime + // Reloading should truncate the blocks which are >= the retention duration. require.NoError(t, db.reloadBlocks()) - expBlocks := blocks[1:] + expBlocks := blocks[2:] actBlocks := db.Blocks() require.Equal(t, 1, int(prom_testutil.ToFloat64(db.metrics.timeRetentionCount)), "metric retention count mismatch") - require.Equal(t, len(expBlocks), len(actBlocks)) + require.Len(t, actBlocks, len(expBlocks)) require.Equal(t, expBlocks[0].MaxTime, actBlocks[0].meta.MaxTime) require.Equal(t, expBlocks[len(expBlocks)-1].MaxTime, actBlocks[len(actBlocks)-1].meta.MaxTime) } From 07332f7427ed9a1d6a04c124ae545eb3989134d6 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 20 Mar 2024 14:58:09 +0100 Subject: [PATCH 160/253] TestTimeRetention: Split into two sub-tests Signed-off-by: Arve Knudsen --- tsdb/db_test.go | 86 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 50d5141bd5..ce5efd0e43 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -1463,38 +1463,66 @@ func (*mockCompactorFailing) CompactOOO(string, *OOOCompactionHead) (result []ul } func TestTimeRetention(t *testing.T) { - db := openTestDB(t, nil, []int64{1000}) - defer func() { - require.NoError(t, db.Close()) - }() - - blocks := []*BlockMeta{ - {MinTime: 500, MaxTime: 900}, // Oldest block - {MinTime: 500, MaxTime: 1000}, // Coinciding exactly with the retention duration. - {MinTime: 1000, MaxTime: 1500}, - {MinTime: 1500, MaxTime: 2000}, // Newest Block + testCases := []struct { + name string + blocks []*BlockMeta + expBlocks []*BlockMeta + retentionDuration int64 + }{ + { + name: "Block max time delta greater than retention duration", + blocks: []*BlockMeta{ + {MinTime: 500, MaxTime: 900}, // Oldest block, beyond retention + {MinTime: 1000, MaxTime: 1500}, + {MinTime: 1500, MaxTime: 2000}, // Newest block + }, + expBlocks: []*BlockMeta{ + {MinTime: 1000, MaxTime: 1500}, + {MinTime: 1500, MaxTime: 2000}, + }, + retentionDuration: 1000, + }, + { + name: "Block max time delta equal to retention duration", + blocks: []*BlockMeta{ + {MinTime: 500, MaxTime: 900}, // Oldest block + {MinTime: 1000, MaxTime: 1500}, // Coinciding exactly with the retention duration. + {MinTime: 1500, MaxTime: 2000}, // Newest block + }, + expBlocks: []*BlockMeta{ + {MinTime: 1500, MaxTime: 2000}, + }, + retentionDuration: 500, + }, } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + db := openTestDB(t, nil, []int64{1000}) + defer func() { + require.NoError(t, db.Close()) + }() - for _, m := range blocks { - createBlock(t, db.Dir(), genSeries(10, 10, m.MinTime, m.MaxTime)) + for _, m := range tc.blocks { + createBlock(t, db.Dir(), genSeries(10, 10, m.MinTime, m.MaxTime)) + } + + require.NoError(t, db.reloadBlocks()) // Reload the db to register the new blocks. + require.Len(t, db.Blocks(), len(tc.blocks)) // Ensure all blocks are registered. + + db.opts.RetentionDuration = tc.retentionDuration + // Reloading should truncate the blocks which are >= the retention duration vs the first block. + require.NoError(t, db.reloadBlocks()) + + actBlocks := db.Blocks() + + require.Equal(t, 1, int(prom_testutil.ToFloat64(db.metrics.timeRetentionCount)), "metric retention count mismatch") + require.Len(t, actBlocks, len(tc.expBlocks)) + for i, eb := range tc.expBlocks { + require.Equal(t, eb.MinTime, actBlocks[i].meta.MinTime) + require.Equal(t, eb.MaxTime, actBlocks[i].meta.MaxTime) + } + }) } - - require.NoError(t, db.reloadBlocks()) // Reload the db to register the new blocks. - require.Equal(t, len(blocks), len(db.Blocks())) // Ensure all blocks are registered. - - // By setting retention duration as follows, we verify that also blocks[1], - // coinciding exactly with the boundary, is deleted. - db.opts.RetentionDuration = blocks[3].MaxTime - blocks[1].MaxTime - // Reloading should truncate the blocks which are >= the retention duration. - require.NoError(t, db.reloadBlocks()) - - expBlocks := blocks[2:] - actBlocks := db.Blocks() - - require.Equal(t, 1, int(prom_testutil.ToFloat64(db.metrics.timeRetentionCount)), "metric retention count mismatch") - require.Len(t, actBlocks, len(expBlocks)) - require.Equal(t, expBlocks[0].MaxTime, actBlocks[0].meta.MaxTime) - require.Equal(t, expBlocks[len(expBlocks)-1].MaxTime, actBlocks[len(actBlocks)-1].meta.MaxTime) } func TestRetentionDurationMetric(t *testing.T) { From 2a2e2ed28bc9f1f9205e874ed1be705e765ecb9b Mon Sep 17 00:00:00 2001 From: machine424 Date: Wed, 20 Mar 2024 14:09:21 +0100 Subject: [PATCH 161/253] chore(tsdb): set the wbl to nil as well in DBReadOnly.loadDataAsQueryable Signed-off-by: machine424 --- tsdb/db.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsdb/db.go b/tsdb/db.go index e49c5811d2..28cecde4f4 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -529,9 +529,10 @@ func (db *DBReadOnly) loadDataAsQueryable(maxt int64) (storage.SampleAndChunkQue if err := head.Init(maxBlockTime); err != nil { return nil, fmt.Errorf("read WAL: %w", err) } - // Set the wal to nil to disable all wal operations. + // Set the wal and the wbl to nil to disable related operations. // This is mainly to avoid blocking when closing the head. head.wal = nil + head.wbl = nil } db.closers = append(db.closers, head) From f6834c347ad64d2768b60b60f411597a467b4b64 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 20 Mar 2024 22:01:05 +0300 Subject: [PATCH 162/253] promql: validate `label_join` destination label Signed-off-by: tdakkota --- promql/functions.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/promql/functions.go b/promql/functions.go index da66af2f02..d5840374e7 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1386,6 +1386,9 @@ func (ev *evaluator) evalLabelJoin(args parser.Expressions) (parser.Value, annot } srcLabels[i-3] = src } + if !model.LabelName(dst).IsValid() { + panic(fmt.Errorf("invalid destination label name in label_join(): %s", dst)) + } val, ws := ev.eval(args[0]) matrix := val.(Matrix) From c7ca85388f0adbc166902757aef6184e73355034 Mon Sep 17 00:00:00 2001 From: heyitao Date: Thu, 21 Mar 2024 11:32:02 +0800 Subject: [PATCH 163/253] Fix yaml file format and clear ci errors Signed-off-by: heyitao --- .github/dependabot.yml | 8 ++-- .golangci.yml | 37 +++++++++---------- .yamllint | 2 + .../testdata/no-test-group-interval.yml | 2 +- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9617e04a48..3d56ff2b22 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,11 +6,11 @@ updates: interval: "monthly" groups: k8s.io: - patterns: - - "k8s.io/*" + patterns: + - "k8s.io/*" go.opentelemetry.io: - patterns: - - "go.opentelemetry.io/*" + patterns: + - "go.opentelemetry.io/*" - package-ecosystem: "gomod" directory: "/documentation/examples/remote_storage" schedule: diff --git a/.golangci.yml b/.golangci.yml index 2eeb6c1c8f..42410aebf8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -48,24 +48,24 @@ linters-settings: rules: main: deny: - - pkg: "sync/atomic" - desc: "Use go.uber.org/atomic instead of sync/atomic" - - pkg: "github.com/stretchr/testify/assert" - desc: "Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert" - - pkg: "github.com/go-kit/kit/log" - desc: "Use github.com/go-kit/log instead of github.com/go-kit/kit/log" - - pkg: "io/ioutil" - desc: "Use corresponding 'os' or 'io' functions instead." - - pkg: "regexp" - desc: "Use github.com/grafana/regexp instead of regexp" - - pkg: "github.com/pkg/errors" - desc: "Use 'errors' or 'fmt' instead of github.com/pkg/errors" - - pkg: "gzip" - desc: "Use github.com/klauspost/compress instead of gzip" - - pkg: "zlib" - desc: "Use github.com/klauspost/compress instead of zlib" - - pkg: "golang.org/x/exp/slices" - desc: "Use 'slices' instead." + - pkg: "sync/atomic" + desc: "Use go.uber.org/atomic instead of sync/atomic" + - pkg: "github.com/stretchr/testify/assert" + desc: "Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert" + - pkg: "github.com/go-kit/kit/log" + desc: "Use github.com/go-kit/log instead of github.com/go-kit/kit/log" + - pkg: "io/ioutil" + desc: "Use corresponding 'os' or 'io' functions instead." + - pkg: "regexp" + desc: "Use github.com/grafana/regexp instead of regexp" + - pkg: "github.com/pkg/errors" + desc: "Use 'errors' or 'fmt' instead of github.com/pkg/errors" + - pkg: "gzip" + desc: "Use github.com/klauspost/compress instead of gzip" + - pkg: "zlib" + desc: "Use github.com/klauspost/compress instead of zlib" + - pkg: "golang.org/x/exp/slices" + desc: "Use 'slices' instead." errcheck: exclude-functions: # Don't flag lines such as "io.Copy(io.Discard, resp.Body)". @@ -135,4 +135,3 @@ linters-settings: - require-error - suite-dont-use-pkg - suite-extra-assert-call - diff --git a/.yamllint b/.yamllint index 955a5a6270..1859cb624b 100644 --- a/.yamllint +++ b/.yamllint @@ -1,5 +1,7 @@ --- extends: default +ignore: | + ui/react-app/node_modules rules: braces: diff --git a/cmd/promtool/testdata/no-test-group-interval.yml b/cmd/promtool/testdata/no-test-group-interval.yml index d1f6935cd6..99f2ec6467 100644 --- a/cmd/promtool/testdata/no-test-group-interval.yml +++ b/cmd/promtool/testdata/no-test-group-interval.yml @@ -12,4 +12,4 @@ tests: eval_time: 1m exp_samples: - value: 1 - labels: test \ No newline at end of file + labels: test From d9e43535202ef6a5846d62ac360cc5763559bb8b Mon Sep 17 00:00:00 2001 From: heyitao Date: Thu, 21 Mar 2024 11:32:23 +0800 Subject: [PATCH 164/253] Fix binary detection in Makefile Signed-off-by: heyitao --- Makefile | 2 +- Makefile.common | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ab229f9311..d78813068e 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ assets-tarball: assets .PHONY: parser parser: @echo ">> running goyacc to generate the .go file." -ifeq (, $(shell command -v goyacc > /dev/null)) +ifeq (, $(shell command -v goyacc 2> /dev/null)) @echo "goyacc not installed so skipping" @echo "To install: go install golang.org/x/tools/cmd/goyacc@v0.6.0" else diff --git a/Makefile.common b/Makefile.common index 483b3bf9df..0acfb9d806 100644 --- a/Makefile.common +++ b/Makefile.common @@ -49,7 +49,7 @@ endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) -ifneq ($(shell command -v gotestsum > /dev/null),) +ifneq ($(shell command -v gotestsum 2> /dev/null),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif @@ -182,7 +182,7 @@ endif .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" -ifeq (, $(shell command -v yamllint > /dev/null)) +ifeq (, $(shell command -v yamllint 2> /dev/null)) @echo "yamllint not installed so skipping" else yamllint . From a192d4a04b3e0479cf9d00696300f5a15c083b6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:14:12 +0000 Subject: [PATCH 165/253] build(deps): bump actions/checkout from 4.1.1 to 4.1.2 in /scripts Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/b4ffde65f46336ab88eb53be808477a3936bae11...9bb56186c3b09b4f86b1c65136769dd318469633) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- scripts/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/golangci-lint.yml b/scripts/golangci-lint.yml index 5670d6079b..a7a40c1be5 100644 --- a/scripts/golangci-lint.yml +++ b/scripts/golangci-lint.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: install Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: From b5a2331c69771951aa380cfaade068b6ccd89a04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:14:18 +0000 Subject: [PATCH 166/253] build(deps): bump golangci/golangci-lint-action from 3.7.0 to 4.0.0 Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.7.0 to 4.0.0. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/3a919529898de77ec3da873e3063ca4b10e7f5cc...3cfe3a4abbb849e10058ce4af15d205b6da42804) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8303cad528..498db12b6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,7 +158,7 @@ jobs: run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 with: args: --verbose # Make sure to sync this with Makefile.common and scripts/golangci-lint.yml. From 4eadb42c435fa989171400d59455efbccaef7662 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:14:24 +0000 Subject: [PATCH 167/253] build(deps): bump bufbuild/buf-setup-action from 1.28.1 to 1.30.0 Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.28.1 to 1.30.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/382440cdb8ec7bc25a68d7b4711163d95f7cc3aa...517ee23296d5caf38df31c21945e6a54bbc8a89f) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/buf-lint.yml | 2 +- .github/workflows/buf.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buf-lint.yml b/.github/workflows/buf-lint.yml index 91de37aa6f..942db6e9b2 100644 --- a/.github/workflows/buf-lint.yml +++ b/.github/workflows/buf-lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: bufbuild/buf-setup-action@382440cdb8ec7bc25a68d7b4711163d95f7cc3aa # v1.28.1 + - uses: bufbuild/buf-setup-action@517ee23296d5caf38df31c21945e6a54bbc8a89f # v1.30.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} - uses: bufbuild/buf-lint-action@044d13acb1f155179c606aaa2e53aea304d22058 # v1.1.0 diff --git a/.github/workflows/buf.yml b/.github/workflows/buf.yml index 04d4ed8682..9bbfd236e7 100644 --- a/.github/workflows/buf.yml +++ b/.github/workflows/buf.yml @@ -13,7 +13,7 @@ jobs: if: github.repository_owner == 'prometheus' steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: bufbuild/buf-setup-action@382440cdb8ec7bc25a68d7b4711163d95f7cc3aa # v1.28.1 + - uses: bufbuild/buf-setup-action@517ee23296d5caf38df31c21945e6a54bbc8a89f # v1.30.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} - uses: bufbuild/buf-lint-action@044d13acb1f155179c606aaa2e53aea304d22058 # v1.1.0 From 94d13099b4042ddac3cd138a4b0c63ee8aae142a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:14:36 +0000 Subject: [PATCH 168/253] build(deps): bump actions/cache from 4.0.1 to 4.0.2 Bumps [actions/cache](https://github.com/actions/cache) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/ab5e6d0c87105b4c9c2047343972218f562e4319...0c45773b623bea8c8e75f6c82b208c3cf94ea4f9) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8303cad528..bf2246d0e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -211,7 +211,7 @@ jobs: with: node-version-file: "web/ui/.nvmrc" registry-url: "https://registry.npmjs.org" - - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} From 0c58987bc9f989330a5bf0b1cc95335e62ed0219 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:14:40 +0000 Subject: [PATCH 169/253] build(deps): bump actions/setup-node from 4.0.1 to 4.0.2 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8...60edb5dd545a775178f52524783378180af0d1f8) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8303cad528..1dda9b930d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -207,7 +207,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - name: Install nodejs - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: node-version-file: "web/ui/.nvmrc" registry-url: "https://registry.npmjs.org" From 33138174d454399be72942bb80b93d96d14d63ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:15:04 +0000 Subject: [PATCH 170/253] build(deps): bump the k8s-io group with 3 updates Bumps the k8s-io group with 3 updates: [k8s.io/api](https://github.com/kubernetes/api), [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) and [k8s.io/client-go](https://github.com/kubernetes/client-go). Updates `k8s.io/api` from 0.29.2 to 0.29.3 - [Commits](https://github.com/kubernetes/api/compare/v0.29.2...v0.29.3) Updates `k8s.io/apimachinery` from 0.29.2 to 0.29.3 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.29.2...v0.29.3) Updates `k8s.io/client-go` from 0.29.2 to 0.29.3 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.29.2...v0.29.3) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apimachinery dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/client-go dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io ... Signed-off-by: dependabot[bot] --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 8039a16af4..1e2ea84551 100644 --- a/go.mod +++ b/go.mod @@ -84,12 +84,12 @@ require ( google.golang.org/api v0.168.0 google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.29.2 - k8s.io/apimachinery v0.29.2 - k8s.io/client-go v0.29.2 + k8s.io/api v0.29.3 + k8s.io/apimachinery v0.29.3 + k8s.io/client-go v0.29.3 k8s.io/klog v1.0.0 k8s.io/klog/v2 v2.120.1 ) @@ -134,7 +134,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // 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 github.com/google/gofuzz v1.2.0 // indirect diff --git a/go.sum b/go.sum index 599f22a1f7..3fb337c860 100644 --- a/go.sum +++ b/go.sum @@ -280,8 +280,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -1118,8 +1118,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1161,12 +1161,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= -k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= -k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= -k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= -k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= +k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= +k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= From 9bdb6f6554768683d780ca4fb6c371c6ae0af59c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:15:15 +0000 Subject: [PATCH 171/253] build(deps): bump github.com/linode/linodego from 1.29.0 to 1.30.0 Bumps [github.com/linode/linodego](https://github.com/linode/linodego) from 1.29.0 to 1.30.0. - [Release notes](https://github.com/linode/linodego/releases) - [Commits](https://github.com/linode/linodego/compare/v1.29.0...v1.30.0) --- updated-dependencies: - dependency-name: github.com/linode/linodego dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 8039a16af4..dfa7098801 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/json-iterator/go v1.1.12 github.com/klauspost/compress v1.17.7 github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b - github.com/linode/linodego v1.29.0 + github.com/linode/linodego v1.30.0 github.com/miekg/dns v1.1.58 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f diff --git a/go.sum b/go.sum index 599f22a1f7..9de7ed96a1 100644 --- a/go.sum +++ b/go.sum @@ -424,8 +424,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= -github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= -github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= +github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= +github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -471,8 +471,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linode/linodego v1.29.0 h1:gDSQWAbKMAQX8db9FDCXHhodQPrJmLcmthjx6m+PyV4= -github.com/linode/linodego v1.29.0/go.mod h1:3k6WvCM10gillgYcnoLqIL23ST27BD9HhMsCJWb3Bpk= +github.com/linode/linodego v1.30.0 h1:6HJli+LX7NGu+Sne2G+ux790EkVOWOV/SR4mK3jcs6k= +github.com/linode/linodego v1.30.0/go.mod h1:/46h/XpmWi//oSA92GX2p3FIxb8HbX7grslPPQalR2o= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= From 191c467f1620ef8b6f849d0261eb54f69d1e9238 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:15:52 +0000 Subject: [PATCH 172/253] build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 Bumps [github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5](https://github.com/Azure/azure-sdk-for-go) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/Azure/azure-sdk-for-go/releases) - [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md) - [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/resourcemanager/compute/armcompute/v5.5.0...sdk/resourcemanager/compute/armcompute/v5.6.0) --- updated-dependencies: - dependency-name: github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8039a16af4..dd5f9d7968 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 github.com/Code-Hex/go-generics-cache v1.3.1 github.com/KimMachineGun/automemlimit v0.5.0 diff --git a/go.sum b/go.sum index 599f22a1f7..4eaa14b96a 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 h1:MxA59PGoCFb+vCwRQi3PhQEwHj4+r2dhuv9HG+vM7iM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0 h1:ui3YNbxfW7J3tTFIZMH6LIGRjCngp+J+nIFlnizfNTE= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0/go.mod h1:gZmgV+qBqygoznvqo2J9oKZAFziqhLZ2xE/WVUmzkHA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= From 7ec4a11472648e994b1ebe4dfe80497d43a05455 Mon Sep 17 00:00:00 2001 From: David Leadbeater Date: Thu, 21 Mar 2024 20:23:40 +1100 Subject: [PATCH 173/253] promtool: Avoid using testify for user rule tests Using testify outside of unit tests results in panics rather than a useful error for the user. Fixes #13703 Signed-off-by: David Leadbeater --- cmd/promtool/unittest.go | 11 ++++++++--- promql/test.go | 29 +++++++++++++++++------------ promql/test_test.go | 2 +- util/teststorage/storage.go | 23 +++++++++++++++++++---- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/cmd/promtool/unittest.go b/cmd/promtool/unittest.go index 4777b88098..6d6683a934 100644 --- a/cmd/promtool/unittest.go +++ b/cmd/promtool/unittest.go @@ -175,13 +175,18 @@ type testGroup struct { } // test performs the unit tests. -func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]int, queryOpts promql.LazyLoaderOpts, diffFlag bool, ruleFiles ...string) []error { +func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]int, queryOpts promql.LazyLoaderOpts, diffFlag bool, ruleFiles ...string) (outErr []error) { // Setup testing suite. - suite, err := promql.NewLazyLoader(nil, tg.seriesLoadingString(), queryOpts) + suite, err := promql.NewLazyLoader(tg.seriesLoadingString(), queryOpts) if err != nil { return []error{err} } - defer suite.Close() + defer func() { + err := suite.Close() + if err != nil { + outErr = append(outErr, err) + } + }() suite.SubqueryInterval = evalInterval // Load the rule files. diff --git a/promql/test.go b/promql/test.go index 589b1e5b6b..c45cfd8a51 100644 --- a/promql/test.go +++ b/promql/test.go @@ -704,8 +704,6 @@ func parseNumber(s string) (float64, error) { // LazyLoader lazily loads samples into storage. // This is specifically implemented for unit testing of rules. type LazyLoader struct { - testutil.T - loadCmd *loadCmd storage storage.Storage @@ -727,13 +725,15 @@ type LazyLoaderOpts struct { } // NewLazyLoader returns an initialized empty LazyLoader. -func NewLazyLoader(t testutil.T, input string, opts LazyLoaderOpts) (*LazyLoader, error) { +func NewLazyLoader(input string, opts LazyLoaderOpts) (*LazyLoader, error) { ll := &LazyLoader{ - T: t, opts: opts, } err := ll.parse(input) - ll.clear() + if err != nil { + return nil, err + } + err = ll.clear() return ll, err } @@ -761,15 +761,20 @@ func (ll *LazyLoader) parse(input string) error { } // clear the current test storage of all inserted samples. -func (ll *LazyLoader) clear() { +func (ll *LazyLoader) clear() error { if ll.storage != nil { - err := ll.storage.Close() - require.NoError(ll.T, err, "Unexpected error while closing test storage.") + if err := ll.storage.Close(); err != nil { + return fmt.Errorf("closing test storage: %w", err) + } } if ll.cancelCtx != nil { ll.cancelCtx() } - ll.storage = teststorage.New(ll) + var err error + ll.storage, err = teststorage.NewWithError() + if err != nil { + return err + } opts := EngineOpts{ Logger: nil, @@ -783,6 +788,7 @@ func (ll *LazyLoader) clear() { ll.queryEngine = NewEngine(opts) ll.context, ll.cancelCtx = context.WithCancel(context.Background()) + return nil } // appendTill appends the defined time series to the storage till the given timestamp (in milliseconds). @@ -836,8 +842,7 @@ func (ll *LazyLoader) Storage() storage.Storage { } // Close closes resources associated with the LazyLoader. -func (ll *LazyLoader) Close() { +func (ll *LazyLoader) Close() error { ll.cancelCtx() - err := ll.storage.Close() - require.NoError(ll.T, err, "Unexpected error while closing test storage.") + return ll.storage.Close() } diff --git a/promql/test_test.go b/promql/test_test.go index ee2a0e264b..316c177d77 100644 --- a/promql/test_test.go +++ b/promql/test_test.go @@ -110,7 +110,7 @@ func TestLazyLoader_WithSamplesTill(t *testing.T) { } for _, c := range cases { - suite, err := NewLazyLoader(t, c.loadString, LazyLoaderOpts{}) + suite, err := NewLazyLoader(c.loadString, LazyLoaderOpts{}) require.NoError(t, err) defer suite.Close() diff --git a/util/teststorage/storage.go b/util/teststorage/storage.go index 5d95437e99..7d1f9dda24 100644 --- a/util/teststorage/storage.go +++ b/util/teststorage/storage.go @@ -14,6 +14,7 @@ package teststorage import ( + "fmt" "os" "time" @@ -30,8 +31,18 @@ import ( // New returns a new TestStorage for testing purposes // that removes all associated files on closing. func New(t testutil.T) *TestStorage { + stor, err := NewWithError() + require.NoError(t, err) + return stor +} + +// NewWithError returns a new TestStorage for user facing tests, which reports +// errors directly. +func NewWithError() (*TestStorage, error) { dir, err := os.MkdirTemp("", "test_storage") - require.NoError(t, err, "unexpected error while opening test directory") + if err != nil { + return nil, fmt.Errorf("opening test directory: %w", err) + } // Tests just load data for a series sequentially. Thus we // need a long appendable window. @@ -41,13 +52,17 @@ func New(t testutil.T) *TestStorage { opts.RetentionDuration = 0 opts.EnableNativeHistograms = true db, err := tsdb.Open(dir, nil, nil, opts, tsdb.NewDBStats()) - require.NoError(t, err, "unexpected error while opening test storage") + if err != nil { + return nil, fmt.Errorf("opening test storage: %w", err) + } reg := prometheus.NewRegistry() eMetrics := tsdb.NewExemplarMetrics(reg) es, err := tsdb.NewCircularExemplarStorage(10, eMetrics) - require.NoError(t, err, "unexpected error while opening test exemplar storage") - return &TestStorage{DB: db, exemplarStorage: es, dir: dir} + if err != nil { + return nil, fmt.Errorf("opening test exemplar storage: %w", err) + } + return &TestStorage{DB: db, exemplarStorage: es, dir: dir}, nil } type TestStorage struct { From 3bb27c33e938e92cd505d852365e5e55ec805ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Thu, 21 Mar 2024 15:59:18 +0000 Subject: [PATCH 174/253] Use consistent keys for logs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rule warnings are logged with numDropped=N while every other component uses num_dropped=N: ``` notifier/notifier.go: level.Warn(n.logger).Log("msg", "Alert batch larger than queue capacity, dropping alerts", "num_dropped", d) notifier/notifier.go: level.Warn(n.logger).Log("msg", "Alert notification queue full, dropping alerts", "num_dropped", d) storage/remote/write_handler.go: _ = level.Warn(h.logger).Log("msg", "Error on ingesting out-of-order exemplars", "num_dropped", outOfOrderExemplarErrs) rules/group.go: level.Warn(logger).Log("msg", "Error on ingesting out-of-order result from rule evaluation", "num_dropped", numOutOfOrder) rules/group.go: level.Warn(logger).Log("msg", "Error on ingesting too old result from rule evaluation", "num_dropped", numTooOld) rules/group.go: level.Warn(logger).Log("msg", "Error on ingesting results from rule evaluation with different value but same timestamp", "num_dropped", numDuplicates) scrape/scrape.go: level.Warn(sl.l).Log("msg", "Error on ingesting out-of-order samples", "num_dropped", appErrs.numOutOfOrder) scrape/scrape.go: level.Warn(sl.l).Log("msg", "Error on ingesting samples with different value but same timestamp", "num_dropped", appErrs.numDuplicates) scrape/scrape.go: level.Warn(sl.l).Log("msg", "Error on ingesting samples that are too old or are too far into the future", "num_dropped", appErrs.numOutOfBounds) scrape/scrape.go: level.Warn(sl.l).Log("msg", "Error on ingesting out-of-order exemplars", "num_dropped", appErrs.numExemplarOutOfOrder) ``` Rename numDropped to num_dropped for consistency. Signed-off-by: Łukasz Mierzwa --- rules/group.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rules/group.go b/rules/group.go index b8694a255e..c268d2df7d 100644 --- a/rules/group.go +++ b/rules/group.go @@ -546,13 +546,13 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) { } } if numOutOfOrder > 0 { - level.Warn(logger).Log("msg", "Error on ingesting out-of-order result from rule evaluation", "numDropped", numOutOfOrder) + level.Warn(logger).Log("msg", "Error on ingesting out-of-order result from rule evaluation", "num_dropped", numOutOfOrder) } if numTooOld > 0 { - level.Warn(logger).Log("msg", "Error on ingesting too old result from rule evaluation", "numDropped", numTooOld) + level.Warn(logger).Log("msg", "Error on ingesting too old result from rule evaluation", "num_dropped", numTooOld) } if numDuplicates > 0 { - level.Warn(logger).Log("msg", "Error on ingesting results from rule evaluation with different value but same timestamp", "numDropped", numDuplicates) + level.Warn(logger).Log("msg", "Error on ingesting results from rule evaluation with different value but same timestamp", "num_dropped", numDuplicates) } for metric, lset := range g.seriesInPreviousEval[i] { From 9d32754bc0456f3026be8cb8ad7009e776b3d1a6 Mon Sep 17 00:00:00 2001 From: Jeanette Tan Date: Fri, 22 Mar 2024 03:42:50 +0800 Subject: [PATCH 175/253] add unit tests with all negative values for histogram_stddev and var Signed-off-by: Jeanette Tan --- promql/engine_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/promql/engine_test.go b/promql/engine_test.go index cc5d0ee780..3f5f2dc132 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -3498,6 +3498,38 @@ func TestNativeHistogram_HistogramStdDevVar(t *testing.T) { }, stdVar: 1544.8582535368798, // actual variance: 1738.4082 }, + { + name: "-100000, -10000, -1000, -888, -888, -100, -50, -9, -8, -3", + h: &histogram.Histogram{ + Count: 10, + ZeroCount: 0, + Sum: -112946, + Schema: 0, + NegativeSpans: []histogram.Span{ + {Offset: 2, Length: 3}, + {Offset: 1, Length: 2}, + {Offset: 2, Length: 1}, + {Offset: 3, Length: 1}, + {Offset: 2, Length: 1}, + }, + NegativeBuckets: []int64{1, 0, 0, 0, 0, 2, -2, 0}, + }, + stdVar: 1240930974.5260057, // actual variance: 882690990 + }, + { + name: "-10 x10", + h: &histogram.Histogram{ + Count: 10, + ZeroCount: 0, + Sum: -100, + Schema: 0, + NegativeSpans: []histogram.Span{ + {Offset: 4, Length: 1}, + }, + NegativeBuckets: []int64{10}, + }, + stdVar: 454.2741699796952, // actual variance: 0 + }, { name: "-50, -8, 0, 3, 8, 9, 100, NaN", h: &histogram.Histogram{ From d8e4230696123ec6750bc62847abb91c76b042ed Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Fri, 22 Mar 2024 07:44:38 +0100 Subject: [PATCH 176/253] storage: Fix mockChunkQuerier type name Signed-off-by: Arve Knudsen --- storage/merge_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/merge_test.go b/storage/merge_test.go index 05e1c75278..c3a4725aa0 100644 --- a/storage/merge_test.go +++ b/storage/merge_test.go @@ -357,12 +357,12 @@ func TestMergeChunkQuerierWithNoVerticalChunkSeriesMerger(t *testing.T) { t.Run(tc.name, func(t *testing.T) { var p ChunkQuerier if tc.primaryChkQuerierSeries != nil { - p = &mockChunkQurier{toReturn: tc.primaryChkQuerierSeries} + p = &mockChunkQuerier{toReturn: tc.primaryChkQuerierSeries} } var qs []ChunkQuerier for _, in := range tc.chkQuerierSeries { - qs = append(qs, &mockChunkQurier{toReturn: in}) + qs = append(qs, &mockChunkQuerier{toReturn: in}) } qs = append(qs, tc.extraQueriers...) @@ -934,7 +934,7 @@ func (m *mockQuerier) Select(_ context.Context, sortSeries bool, _ *SelectHints, return NewMockSeriesSet(cpy...) } -type mockChunkQurier struct { +type mockChunkQuerier struct { LabelQuerier toReturn []ChunkSeries @@ -948,7 +948,7 @@ func (a chunkSeriesByLabel) Less(i, j int) bool { return labels.Compare(a[i].Labels(), a[j].Labels()) < 0 } -func (m *mockChunkQurier) Select(_ context.Context, sortSeries bool, _ *SelectHints, _ ...*labels.Matcher) ChunkSeriesSet { +func (m *mockChunkQuerier) Select(_ context.Context, sortSeries bool, _ *SelectHints, _ ...*labels.Matcher) ChunkSeriesSet { cpy := make([]ChunkSeries, len(m.toReturn)) copy(cpy, m.toReturn) if sortSeries { From fab629855027c63e3cc746fa91ce8628c390efd6 Mon Sep 17 00:00:00 2001 From: deterclosed Date: Sat, 23 Mar 2024 13:39:27 +0800 Subject: [PATCH 177/253] chore: remove repetitive word Signed-off-by: deterclosed --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 57055ef38c..7687826ba4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,7 +90,7 @@ can modify the `./promql/parser/generated_parser.y.go` manually. ```golang // As of writing this was somewhere around line 600. var ( - yyDebug = 0 // This can be be a number 0 -> 5. + yyDebug = 0 // This can be a number 0 -> 5. yyErrorVerbose = false // This can be set to true. ) From 17e2c307541dae957dae7fe1e444190f6179d41a Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 20 Mar 2024 22:01:05 +0300 Subject: [PATCH 178/253] promql: validate `label_join` destination label Signed-off-by: tdakkota --- promql/functions.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/promql/functions.go b/promql/functions.go index da66af2f02..d5840374e7 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1386,6 +1386,9 @@ func (ev *evaluator) evalLabelJoin(args parser.Expressions) (parser.Value, annot } srcLabels[i-3] = src } + if !model.LabelName(dst).IsValid() { + panic(fmt.Errorf("invalid destination label name in label_join(): %s", dst)) + } val, ws := ev.eval(args[0]) matrix := val.(Matrix) From 44dcf02c697eba456bfeb28cd6587ee5b834d46f Mon Sep 17 00:00:00 2001 From: Artur Melanchyk Date: Sat, 23 Mar 2024 19:44:30 +0100 Subject: [PATCH 179/253] TSDB: make total lock-free by using atomic Signed-off-by: Artur Melanchyk --- cmd/promtool/tsdb.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/promtool/tsdb.go b/cmd/promtool/tsdb.go index 73258754e2..b786c92976 100644 --- a/cmd/promtool/tsdb.go +++ b/cmd/promtool/tsdb.go @@ -33,6 +33,7 @@ import ( "github.com/alecthomas/units" "github.com/go-kit/log" + "go.uber.org/atomic" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql/parser" @@ -149,8 +150,7 @@ func benchmarkWrite(outPath, samplesFile string, numMetrics, numScrapes int) err } func (b *writeBenchmark) ingestScrapes(lbls []labels.Labels, scrapeCount int) (uint64, error) { - var mu sync.Mutex - var total uint64 + var total atomic.Uint64 for i := 0; i < scrapeCount; i += 100 { var wg sync.WaitGroup @@ -165,22 +165,21 @@ func (b *writeBenchmark) ingestScrapes(lbls []labels.Labels, scrapeCount int) (u wg.Add(1) go func() { + defer wg.Done() + n, err := b.ingestScrapesShard(batch, 100, int64(timeDelta*i)) if err != nil { // exitWithError(err) fmt.Println(" err", err) } - mu.Lock() - total += n - mu.Unlock() - wg.Done() + total.Add(n) }() } wg.Wait() } fmt.Println("ingestion completed") - return total, nil + return total.Load(), nil } func (b *writeBenchmark) ingestScrapesShard(lbls []labels.Labels, scrapeCount int, baset int64) (uint64, error) { From ff15b17400dc579bdb7b9d9ebcea6465453a64b2 Mon Sep 17 00:00:00 2001 From: sellskin Date: Mon, 25 Mar 2024 12:18:33 +0800 Subject: [PATCH 180/253] remove code that will not be executed Signed-off-by: sellskin --- discovery/file/file_test.go | 1 - discovery/legacymanager/manager_test.go | 1 - discovery/manager_test.go | 1 - 3 files changed, 3 deletions(-) diff --git a/discovery/file/file_test.go b/discovery/file/file_test.go index 521a3c0f16..179ac5cd1c 100644 --- a/discovery/file/file_test.go +++ b/discovery/file/file_test.go @@ -208,7 +208,6 @@ func (t *testRunner) requireUpdate(ref time.Time, expected []*targetgroup.Group) select { case <-timeout: t.Fatalf("Expected update but got none") - return case <-time.After(defaultWait / 10): if ref.Equal(t.lastReceive()) { // No update received. diff --git a/discovery/legacymanager/manager_test.go b/discovery/legacymanager/manager_test.go index 6fbecabc2a..1ed699645d 100644 --- a/discovery/legacymanager/manager_test.go +++ b/discovery/legacymanager/manager_test.go @@ -733,7 +733,6 @@ func verifyPresence(t *testing.T, tSets map[poolKey]map[string]*targetgroup.Grou t.Helper() if _, ok := tSets[poolKey]; !ok { t.Fatalf("'%s' should be present in Pool keys: %v", poolKey, tSets) - return } match := false diff --git a/discovery/manager_test.go b/discovery/manager_test.go index 52159d94f6..8f2345911e 100644 --- a/discovery/manager_test.go +++ b/discovery/manager_test.go @@ -733,7 +733,6 @@ func verifySyncedPresence(t *testing.T, tGroups map[string][]*targetgroup.Group, t.Helper() if _, ok := tGroups[key]; !ok { t.Fatalf("'%s' should be present in Group map keys: %v", key, tGroups) - return } match := false var mergedTargets string From 48786ad4e8b644c31a0ce21f5275bb2dcba4a85f Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 25 Mar 2024 12:20:18 +0000 Subject: [PATCH 181/253] Use slices insteda of exp/slices Signed-off-by: Bryan Boreham --- go.mod | 2 +- model/labels/regexp.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 499104570d..5ea1124fa7 100644 --- a/go.mod +++ b/go.mod @@ -74,7 +74,6 @@ require ( go.uber.org/automaxprocs v1.5.3 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/net v0.22.0 golang.org/x/oauth2 v0.18.0 golang.org/x/sync v0.6.0 @@ -186,6 +185,7 @@ require ( go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect golang.org/x/crypto v0.21.0 // indirect + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/mod v0.16.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/model/labels/regexp.go b/model/labels/regexp.go index 5e470afa3b..f35dc76f60 100644 --- a/model/labels/regexp.go +++ b/model/labels/regexp.go @@ -14,11 +14,11 @@ package labels import ( + "slices" "strings" "github.com/grafana/regexp" "github.com/grafana/regexp/syntax" - "golang.org/x/exp/slices" ) const ( From ceca6c4716e275d39bd28798bd6ac0ec998938e7 Mon Sep 17 00:00:00 2001 From: Ben Ye Date: Tue, 26 Mar 2024 04:16:27 -0700 Subject: [PATCH 182/253] [ENHANCEMENT] TSDB: Log more statistics during startup (#13838) * log chunk snapshot and mmap chunks replay duration together with total replay duration Signed-off-by: Ben Ye --- tsdb/head.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tsdb/head.go b/tsdb/head.go index 7e6fda9c7e..820fba9e2c 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -620,6 +620,7 @@ func (h *Head) Init(minValidTime int64) error { refSeries := make(map[chunks.HeadSeriesRef]*memSeries) snapshotLoaded := false + var chunkSnapshotLoadDuration time.Duration if h.opts.EnableMemorySnapshotOnShutdown { level.Info(h.logger).Log("msg", "Chunk snapshot is enabled, replaying from the snapshot") // If there are any WAL files, there should be at least one WAL file with an index that is current or newer @@ -650,7 +651,8 @@ func (h *Head) Init(minValidTime int64) error { snapIdx, snapOffset, refSeries, err = h.loadChunkSnapshot() if err == nil { snapshotLoaded = true - level.Info(h.logger).Log("msg", "Chunk snapshot loading time", "duration", time.Since(start).String()) + chunkSnapshotLoadDuration = time.Since(start) + level.Info(h.logger).Log("msg", "Chunk snapshot loading time", "duration", chunkSnapshotLoadDuration.String()) } if err != nil { snapIdx, snapOffset = -1, 0 @@ -672,6 +674,8 @@ func (h *Head) Init(minValidTime int64) error { oooMmappedChunks map[chunks.HeadSeriesRef][]*mmappedChunk lastMmapRef chunks.ChunkDiskMapperRef err error + + mmapChunkReplayDuration time.Duration ) if snapshotLoaded || h.wal != nil { // If snapshot was not loaded and if there is no WAL, then m-map chunks will be discarded @@ -695,7 +699,8 @@ func (h *Head) Init(minValidTime int64) error { return err } } - level.Info(h.logger).Log("msg", "On-disk memory mappable chunks replay completed", "duration", time.Since(mmapChunkReplayStart).String()) + mmapChunkReplayDuration = time.Since(mmapChunkReplayStart) + level.Info(h.logger).Log("msg", "On-disk memory mappable chunks replay completed", "duration", mmapChunkReplayDuration.String()) } if h.wal == nil { @@ -817,6 +822,8 @@ func (h *Head) Init(minValidTime int64) error { "checkpoint_replay_duration", checkpointReplayDuration.String(), "wal_replay_duration", walReplayDuration.String(), "wbl_replay_duration", wblReplayDuration.String(), + "chunk_snapshot_load_duration", chunkSnapshotLoadDuration.String(), + "mmap_chunk_replay_duration", mmapChunkReplayDuration.String(), "total_replay_duration", totalReplayDuration.String(), ) From 481f14e1c0eabd57c5570b1b3f87aa9d8d3b9a81 Mon Sep 17 00:00:00 2001 From: Nick Pillitteri <56quarters@users.noreply.github.com> Date: Tue, 26 Mar 2024 07:17:38 -0400 Subject: [PATCH 183/253] TSDB: Don't rely on integer overflow in head compaction check (#13755) * TSDB: Don't compact the head block when empty Don't compact the Head block if there have not yet been any samples appended. Previously, the logic for determining if the head should be compacted relied on the default values for min and max time and integer overflow when they were checked in `Head.compactable()`. The check in `Head.compactable()` effectively did `math.MinInt64 - math.MaxInt64` which overflowed and wrapped to `1`. Since `1` is less than `1.5` times the chunk range, compaction did not happen. This was the correct behavior but relying on overflow wrapping is surprising. This change add a method for checking if the min and max time for the head is unset and uses it to short-circuit compaction in that case. It also replaces several explicit checks for the default value to determine if the head has not yet had any samples added. Signed-off-by: Nick Pillitteri --- tsdb/db_test.go | 5 +++++ tsdb/head.go | 21 +++++++++++++++------ tsdb/head_append.go | 4 ++-- tsdb/head_test.go | 13 +++++++++++++ 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 498e26c588..e98f60299e 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -1994,6 +1994,7 @@ func TestInitializeHeadTimestamp(t *testing.T) { // Should be set to init values if no WAL or blocks exist so far. require.Equal(t, int64(math.MaxInt64), db.head.MinTime()) require.Equal(t, int64(math.MinInt64), db.head.MaxTime()) + require.False(t, db.head.initialized()) // First added sample initializes the writable range. ctx := context.Background() @@ -2003,6 +2004,7 @@ func TestInitializeHeadTimestamp(t *testing.T) { require.Equal(t, int64(1000), db.head.MinTime()) require.Equal(t, int64(1000), db.head.MaxTime()) + require.True(t, db.head.initialized()) }) t.Run("wal-only", func(t *testing.T) { dir := t.TempDir() @@ -2031,6 +2033,7 @@ func TestInitializeHeadTimestamp(t *testing.T) { require.Equal(t, int64(5000), db.head.MinTime()) require.Equal(t, int64(15000), db.head.MaxTime()) + require.True(t, db.head.initialized()) }) t.Run("existing-block", func(t *testing.T) { dir := t.TempDir() @@ -2043,6 +2046,7 @@ func TestInitializeHeadTimestamp(t *testing.T) { require.Equal(t, int64(2000), db.head.MinTime()) require.Equal(t, int64(2000), db.head.MaxTime()) + require.True(t, db.head.initialized()) }) t.Run("existing-block-and-wal", func(t *testing.T) { dir := t.TempDir() @@ -2075,6 +2079,7 @@ func TestInitializeHeadTimestamp(t *testing.T) { require.Equal(t, int64(6000), db.head.MinTime()) require.Equal(t, int64(15000), db.head.MaxTime()) + require.True(t, db.head.initialized()) // Check that old series has been GCed. require.Equal(t, 1.0, prom_testutil.ToFloat64(db.head.metrics.series)) }) diff --git a/tsdb/head.go b/tsdb/head.go index 820fba9e2c..8b3d9787ca 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -1081,11 +1081,11 @@ func (h *Head) SetMinValidTime(minValidTime int64) { // Truncate removes old data before mint from the head and WAL. func (h *Head) Truncate(mint int64) (err error) { - initialize := h.MinTime() == math.MaxInt64 + initialized := h.initialized() if err := h.truncateMemory(mint); err != nil { return err } - if initialize { + if !initialized { return nil } return h.truncateWAL(mint) @@ -1107,9 +1107,9 @@ func (h *Head) truncateMemory(mint int64) (err error) { } }() - initialize := h.MinTime() == math.MaxInt64 + initialized := h.initialized() - if h.MinTime() >= mint && !initialize { + if h.MinTime() >= mint && initialized { return nil } @@ -1120,7 +1120,7 @@ func (h *Head) truncateMemory(mint int64) (err error) { defer h.memTruncationInProcess.Store(false) // We wait for pending queries to end that overlap with this truncation. - if !initialize { + if initialized { h.WaitForPendingReadersInTimeRange(h.MinTime(), mint) } @@ -1134,7 +1134,7 @@ func (h *Head) truncateMemory(mint int64) (err error) { // This was an initial call to Truncate after loading blocks on startup. // We haven't read back the WAL yet, so do not attempt to truncate it. - if initialize { + if !initialized { return nil } @@ -1622,10 +1622,19 @@ func (h *Head) MaxOOOTime() int64 { return h.maxOOOTime.Load() } +// initialized returns true if the head has a MinTime set, false otherwise. +func (h *Head) initialized() bool { + return h.MinTime() != math.MaxInt64 +} + // compactable returns whether the head has a compactable range. // The head has a compactable range when the head time range is 1.5 times the chunk range. // The 0.5 acts as a buffer of the appendable window. func (h *Head) compactable() bool { + if !h.initialized() { + return false + } + return h.MaxTime()-h.MinTime() > h.chunkRange.Load()/2*3 } diff --git a/tsdb/head_append.go b/tsdb/head_append.go index 6342a19d46..58d24ceb94 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -138,7 +138,7 @@ func (h *Head) Appender(_ context.Context) storage.Appender { // The head cache might not have a starting point yet. The init appender // picks up the first appended timestamp as the base. - if h.MinTime() == math.MaxInt64 { + if !h.initialized() { return &initAppender{ head: h, } @@ -191,7 +191,7 @@ func (h *Head) appendableMinValidTime() int64 { // AppendableMinValidTime returns the minimum valid time for samples to be appended to the Head. // Returns false if Head hasn't been initialized yet and the minimum time isn't known yet. func (h *Head) AppendableMinValidTime() (int64, bool) { - if h.MinTime() == math.MaxInt64 { + if !h.initialized() { return 0, false } diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 41c2e062f2..750c8a11e5 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -5819,3 +5819,16 @@ func TestHeadAppender_AppendCTZeroSample(t *testing.T) { require.Equal(t, chunkenc.ValNone, it.Next()) } } + +func TestHeadCompactableDoesNotCompactEmptyHead(t *testing.T) { + // Use a chunk range of 1 here so that if we attempted to determine if the head + // was compactable using default values for min and max times, `Head.compactable()` + // would return true which is incorrect. This test verifies that we short-circuit + // the check when the head has not yet had any samples added. + head, _ := newTestHead(t, 1, wlog.CompressionNone, false) + defer func() { + require.NoError(t, head.Close()) + }() + + require.False(t, head.compactable()) +} From 5cc97a1820773869bf898b8c2533a4d3bf5d9aba Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Tue, 26 Mar 2024 22:22:22 +1100 Subject: [PATCH 184/253] [tests]: extend test scripting language to support range queries (#13825) * Extract method to make it easier to test. Signed-off-by: Charles Korn * Remove superfluous interface definition. Signed-off-by: Charles Korn * Add test cases for existing instant query functionality. Signed-off-by: Charles Korn * Add support for testing range queries Signed-off-by: Charles Korn * Expand test coverage for instant queries and clarify error when a float is returned but a histogram is expected (or vice versa) Signed-off-by: Charles Korn * Improve error message formatting Signed-off-by: Charles Korn * Add test case for instant query command with invalid timestamp Signed-off-by: Charles Korn * Fix linting warning. Signed-off-by: Charles Korn * Remove superfluous print statement and expected result Signed-off-by: Charles Korn * Fix linting warning. Signed-off-by: Charles Korn * Add note about ordered range eval commands. Signed-off-by: Charles Korn * Check that matrix results are always sorted by labels. Signed-off-by: Charles Korn --------- Signed-off-by: Charles Korn --- promql/test.go | 431 +++++++++++++++++++++++++++++++++----------- promql/test_test.go | 351 ++++++++++++++++++++++++++++++++++++ 2 files changed, 681 insertions(+), 101 deletions(-) diff --git a/promql/test.go b/promql/test.go index c45cfd8a51..296b3d3cad 100644 --- a/promql/test.go +++ b/promql/test.go @@ -46,6 +46,7 @@ var ( patSpace = regexp.MustCompile("[\t ]+") patLoad = regexp.MustCompile(`^load\s+(.+?)$`) patEvalInstant = regexp.MustCompile(`^eval(?:_(fail|ordered))?\s+instant\s+(?:at\s+(.+?))?\s+(.+)$`) + patEvalRange = regexp.MustCompile(`^eval(?:_(fail))?\s+range\s+from\s+(.+)\s+to\s+(.+)\s+step\s+(.+?)\s+(.+)$`) ) const ( @@ -72,7 +73,7 @@ func LoadedStorage(t testutil.T, input string) *teststorage.TestStorage { } // RunBuiltinTests runs an acceptance test suite against the provided engine. -func RunBuiltinTests(t *testing.T, engine engineQuerier) { +func RunBuiltinTests(t *testing.T, engine QueryEngine) { t.Cleanup(func() { parser.EnableExperimentalFunctions = false }) parser.EnableExperimentalFunctions = true @@ -89,11 +90,19 @@ func RunBuiltinTests(t *testing.T, engine engineQuerier) { } // RunTest parses and runs the test against the provided engine. -func RunTest(t testutil.T, input string, engine engineQuerier) { - test, err := newTest(t, input) - require.NoError(t, err) +func RunTest(t testutil.T, input string, engine QueryEngine) { + require.NoError(t, runTest(t, input, engine)) +} +func runTest(t testutil.T, input string, engine QueryEngine) error { + test, err := newTest(t, input) + + // Why do this before checking err? newTest() can create the test storage and then return an error, + // and we want to make sure to clean that up to avoid leaking goroutines. defer func() { + if test == nil { + return + } if test.storage != nil { test.storage.Close() } @@ -102,11 +111,19 @@ func RunTest(t testutil.T, input string, engine engineQuerier) { } }() - for _, cmd := range test.cmds { - // TODO(fabxc): aggregate command errors, yield diffs for result - // comparison errors. - require.NoError(t, test.exec(cmd, engine)) + if err != nil { + return err } + + for _, cmd := range test.cmds { + if err := test.exec(cmd, engine); err != nil { + // TODO(fabxc): aggregate command errors, yield diffs for result + // comparison errors. + return err + } + } + + return nil } // test is a sequence of read and write commands that are run @@ -137,11 +154,6 @@ func newTest(t testutil.T, input string) (*test, error) { //go:embed testdata var testsFs embed.FS -type engineQuerier interface { - NewRangeQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) - NewInstantQuery(ctx context.Context, q storage.Queryable, opts QueryOpts, qs string, ts time.Time) (Query, error) -} - func raise(line int, format string, v ...interface{}) error { return &parser.ParseErr{ LineOffset: line, @@ -188,15 +200,26 @@ func parseSeries(defLine string, line int) (labels.Labels, []parser.SequenceValu } func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) { - if !patEvalInstant.MatchString(lines[i]) { - return i, nil, raise(i, "invalid evaluation command. (eval[_fail|_ordered] instant [at ] ") + instantParts := patEvalInstant.FindStringSubmatch(lines[i]) + rangeParts := patEvalRange.FindStringSubmatch(lines[i]) + + if instantParts == nil && rangeParts == nil { + return i, nil, raise(i, "invalid evaluation command. Must be either 'eval[_fail|_ordered] instant [at ] ' or 'eval[_fail] range from to step '") } - parts := patEvalInstant.FindStringSubmatch(lines[i]) - var ( - mod = parts[1] - at = parts[2] - expr = parts[3] - ) + + isInstant := instantParts != nil + + var mod string + var expr string + + if isInstant { + mod = instantParts[1] + expr = instantParts[3] + } else { + mod = rangeParts[1] + expr = rangeParts[5] + } + _, err := parser.ParseExpr(expr) if err != nil { parser.EnrichParseError(err, func(parseErr *parser.ParseErr) { @@ -209,15 +232,54 @@ func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) { return i, nil, err } - offset, err := model.ParseDuration(at) - if err != nil { - return i, nil, raise(i, "invalid step definition %q: %s", parts[1], err) - } - ts := testStartTime.Add(time.Duration(offset)) + formatErr := func(format string, args ...any) error { + combinedArgs := []any{expr, i + 1} + + combinedArgs = append(combinedArgs, args...) + return fmt.Errorf("error in eval %s (line %v): "+format, combinedArgs...) + } + + var cmd *evalCmd + + if isInstant { + at := instantParts[2] + offset, err := model.ParseDuration(at) + if err != nil { + return i, nil, formatErr("invalid timestamp definition %q: %s", at, err) + } + ts := testStartTime.Add(time.Duration(offset)) + cmd = newInstantEvalCmd(expr, ts, i+1) + } else { + from := rangeParts[2] + to := rangeParts[3] + step := rangeParts[4] + + parsedFrom, err := model.ParseDuration(from) + if err != nil { + return i, nil, formatErr("invalid start timestamp definition %q: %s", from, err) + } + + parsedTo, err := model.ParseDuration(to) + if err != nil { + return i, nil, formatErr("invalid end timestamp definition %q: %s", to, err) + } + + if parsedTo < parsedFrom { + return i, nil, formatErr("invalid test definition, end timestamp (%s) is before start timestamp (%s)", to, from) + } + + parsedStep, err := model.ParseDuration(step) + if err != nil { + return i, nil, formatErr("invalid step definition %q: %s", step, err) + } + + cmd = newRangeEvalCmd(expr, testStartTime.Add(time.Duration(parsedFrom)), testStartTime.Add(time.Duration(parsedTo)), time.Duration(parsedStep), i+1) + } - cmd := newEvalCmd(expr, ts, i+1) switch mod { case "ordered": + // Ordered results are not supported for range queries, but the regex for range query commands does not allow + // asserting an ordered result, so we don't need to do any error checking here. cmd.ordered = true case "fail": cmd.fail = true @@ -240,8 +302,8 @@ func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) { } // Currently, we are not expecting any matrices. - if len(vals) > 1 { - return i, nil, raise(i, "expecting multiple values in instant evaluation not allowed") + if len(vals) > 1 && isInstant { + return i, nil, formatErr("expecting multiple values in instant evaluation not allowed") } cmd.expectMetric(j, metric, vals...) } @@ -375,8 +437,11 @@ func appendSample(a storage.Appender, s Sample, m labels.Labels) error { type evalCmd struct { expr string start time.Time + end time.Time + step time.Duration line int + isRange bool // if false, instant query fail, ordered bool metrics map[uint64]labels.Labels @@ -392,7 +457,7 @@ func (e entry) String() string { return fmt.Sprintf("%d: %s", e.pos, e.vals) } -func newEvalCmd(expr string, start time.Time, line int) *evalCmd { +func newInstantEvalCmd(expr string, start time.Time, line int) *evalCmd { return &evalCmd{ expr: expr, start: start, @@ -403,6 +468,20 @@ func newEvalCmd(expr string, start time.Time, line int) *evalCmd { } } +func newRangeEvalCmd(expr string, start, end time.Time, step time.Duration, line int) *evalCmd { + return &evalCmd{ + expr: expr, + start: start, + end: end, + step: step, + line: line, + isRange: true, + + metrics: map[uint64]labels.Labels{}, + expected: map[uint64]entry{}, + } +} + func (ev *evalCmd) String() string { return "eval" } @@ -425,7 +504,77 @@ func (ev *evalCmd) expectMetric(pos int, m labels.Labels, vals ...parser.Sequenc func (ev *evalCmd) compareResult(result parser.Value) error { switch val := result.(type) { case Matrix: - return errors.New("received range result on instant evaluation") + if ev.ordered { + return fmt.Errorf("expected ordered result, but query returned a matrix") + } + + if err := assertMatrixSorted(val); err != nil { + return err + } + + seen := map[uint64]bool{} + for _, s := range val { + hash := s.Metric.Hash() + if _, ok := ev.metrics[hash]; !ok { + return fmt.Errorf("unexpected metric %s in result", s.Metric) + } + seen[hash] = true + exp := ev.expected[hash] + + var expectedFloats []FPoint + var expectedHistograms []HPoint + + for i, e := range exp.vals { + ts := ev.start.Add(time.Duration(i) * ev.step) + + if ts.After(ev.end) { + return fmt.Errorf("expected %v points for %s, but query time range cannot return this many points", len(exp.vals), ev.metrics[hash]) + } + + t := ts.UnixNano() / int64(time.Millisecond/time.Nanosecond) + + if e.Histogram != nil { + expectedHistograms = append(expectedHistograms, HPoint{T: t, H: e.Histogram}) + } else if !e.Omitted { + expectedFloats = append(expectedFloats, FPoint{T: t, F: e.Value}) + } + } + + if len(expectedFloats) != len(s.Floats) || len(expectedHistograms) != len(s.Histograms) { + return fmt.Errorf("expected %v float points and %v histogram points for %s, but got %s", len(expectedFloats), len(expectedHistograms), ev.metrics[hash], formatSeriesResult(s)) + } + + for i, expected := range expectedFloats { + actual := s.Floats[i] + + if expected.T != actual.T { + return fmt.Errorf("expected float value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s)) + } + + if !almostEqual(actual.F, expected.F, defaultEpsilon) { + return fmt.Errorf("expected float value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.F, actual.F, formatSeriesResult(s)) + } + } + + for i, expected := range expectedHistograms { + actual := s.Histograms[i] + + if expected.T != actual.T { + return fmt.Errorf("expected histogram value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s)) + } + + if !actual.H.Equals(expected.H) { + return fmt.Errorf("expected histogram value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.H, actual.H, formatSeriesResult(s)) + } + } + + } + + for hash := range ev.expected { + if !seen[hash] { + return fmt.Errorf("expected metric %s not found", ev.metrics[hash]) + } + } case Vector: seen := map[uint64]bool{} @@ -440,7 +589,13 @@ func (ev *evalCmd) compareResult(result parser.Value) error { } exp0 := exp.vals[0] expH := exp0.Histogram - if (expH == nil) != (v.H == nil) || (expH != nil && !expH.Equals(v.H)) { + if expH == nil && v.H != nil { + return fmt.Errorf("expected float value %v for %s but got histogram %s", exp0, v.Metric, HistogramTestExpression(v.H)) + } + if expH != nil && v.H == nil { + return fmt.Errorf("expected histogram %s for %s but got float value %v", HistogramTestExpression(expH), v.Metric, v.F) + } + if expH != nil && !expH.Equals(v.H) { return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H)) } if !almostEqual(exp0.Value, v.F, defaultEpsilon) { @@ -477,6 +632,21 @@ func (ev *evalCmd) compareResult(result parser.Value) error { return nil } +func formatSeriesResult(s Series) string { + floatPlural := "s" + histogramPlural := "s" + + if len(s.Floats) == 1 { + floatPlural = "" + } + + if len(s.Histograms) == 1 { + histogramPlural = "" + } + + return fmt.Sprintf("%v float point%s %v and %v histogram point%s %v", len(s.Floats), floatPlural, s.Floats, len(s.Histograms), histogramPlural, s.Histograms) +} + // HistogramTestExpression returns TestExpression() for the given histogram or "" if the histogram is nil. func HistogramTestExpression(h *histogram.FloatHistogram) string { if h != nil { @@ -561,7 +731,7 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa } // exec processes a single step of the test. -func (t *test) exec(tc testCommand, engine engineQuerier) error { +func (t *test) exec(tc testCommand, engine QueryEngine) error { switch cmd := tc.(type) { case *clearCmd: t.clear() @@ -578,74 +748,7 @@ func (t *test) exec(tc testCommand, engine engineQuerier) error { } case *evalCmd: - queries, err := atModifierTestCases(cmd.expr, cmd.start) - if err != nil { - return err - } - queries = append([]atModifierTestCase{{expr: cmd.expr, evalTime: cmd.start}}, queries...) - for _, iq := range queries { - q, err := engine.NewInstantQuery(t.context, t.storage, nil, iq.expr, iq.evalTime) - if err != nil { - return err - } - defer q.Close() - res := q.Exec(t.context) - if res.Err != nil { - if cmd.fail { - continue - } - return fmt.Errorf("error evaluating query %q (line %d): %w", iq.expr, cmd.line, res.Err) - } - if res.Err == nil && cmd.fail { - return fmt.Errorf("expected error evaluating query %q (line %d) but got none", iq.expr, cmd.line) - } - err = cmd.compareResult(res.Value) - if err != nil { - return fmt.Errorf("error in %s %s (line %d): %w", cmd, iq.expr, cmd.line, err) - } - - // Check query returns same result in range mode, - // by checking against the middle step. - q, err = engine.NewRangeQuery(t.context, t.storage, nil, iq.expr, iq.evalTime.Add(-time.Minute), iq.evalTime.Add(time.Minute), time.Minute) - if err != nil { - return err - } - rangeRes := q.Exec(t.context) - if rangeRes.Err != nil { - return fmt.Errorf("error evaluating query %q (line %d) in range mode: %w", iq.expr, cmd.line, rangeRes.Err) - } - defer q.Close() - if cmd.ordered { - // Ordering isn't defined for range queries. - continue - } - mat := rangeRes.Value.(Matrix) - vec := make(Vector, 0, len(mat)) - for _, series := range mat { - // We expect either Floats or Histograms. - for _, point := range series.Floats { - if point.T == timeMilliseconds(iq.evalTime) { - vec = append(vec, Sample{Metric: series.Metric, T: point.T, F: point.F}) - break - } - } - for _, point := range series.Histograms { - if point.T == timeMilliseconds(iq.evalTime) { - vec = append(vec, Sample{Metric: series.Metric, T: point.T, H: point.H}) - break - } - } - } - if _, ok := res.Value.(Scalar); ok { - err = cmd.compareResult(Scalar{V: vec[0].F}) - } else { - err = cmd.compareResult(vec) - } - if err != nil { - return fmt.Errorf("error in %s %s (line %d) range mode: %w", cmd, iq.expr, cmd.line, err) - } - - } + return t.execEval(cmd, engine) default: panic("promql.Test.exec: unknown test command type") @@ -653,6 +756,132 @@ func (t *test) exec(tc testCommand, engine engineQuerier) error { return nil } +func (t *test) execEval(cmd *evalCmd, engine QueryEngine) error { + if cmd.isRange { + return t.execRangeEval(cmd, engine) + } + + return t.execInstantEval(cmd, engine) +} + +func (t *test) execRangeEval(cmd *evalCmd, engine QueryEngine) error { + q, err := engine.NewRangeQuery(t.context, t.storage, nil, cmd.expr, cmd.start, cmd.end, cmd.step) + if err != nil { + return err + } + res := q.Exec(t.context) + if res.Err != nil { + if cmd.fail { + return nil + } + + return fmt.Errorf("error evaluating query %q (line %d): %w", cmd.expr, cmd.line, res.Err) + } + if res.Err == nil && cmd.fail { + return fmt.Errorf("expected error evaluating query %q (line %d) but got none", cmd.expr, cmd.line) + } + defer q.Close() + + if err := cmd.compareResult(res.Value); err != nil { + return fmt.Errorf("error in %s %s (line %d): %w", cmd, cmd.expr, cmd.line, err) + } + + return nil +} + +func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error { + queries, err := atModifierTestCases(cmd.expr, cmd.start) + if err != nil { + return err + } + queries = append([]atModifierTestCase{{expr: cmd.expr, evalTime: cmd.start}}, queries...) + for _, iq := range queries { + q, err := engine.NewInstantQuery(t.context, t.storage, nil, iq.expr, iq.evalTime) + if err != nil { + return err + } + defer q.Close() + res := q.Exec(t.context) + if res.Err != nil { + if cmd.fail { + continue + } + return fmt.Errorf("error evaluating query %q (line %d): %w", iq.expr, cmd.line, res.Err) + } + if res.Err == nil && cmd.fail { + return fmt.Errorf("expected error evaluating query %q (line %d) but got none", iq.expr, cmd.line) + } + err = cmd.compareResult(res.Value) + if err != nil { + return fmt.Errorf("error in %s %s (line %d): %w", cmd, iq.expr, cmd.line, err) + } + + // Check query returns same result in range mode, + // by checking against the middle step. + q, err = engine.NewRangeQuery(t.context, t.storage, nil, iq.expr, iq.evalTime.Add(-time.Minute), iq.evalTime.Add(time.Minute), time.Minute) + if err != nil { + return err + } + rangeRes := q.Exec(t.context) + if rangeRes.Err != nil { + return fmt.Errorf("error evaluating query %q (line %d) in range mode: %w", iq.expr, cmd.line, rangeRes.Err) + } + defer q.Close() + if cmd.ordered { + // Range queries are always sorted by labels, so skip this test case that expects results in a particular order. + continue + } + mat := rangeRes.Value.(Matrix) + if err := assertMatrixSorted(mat); err != nil { + return err + } + + vec := make(Vector, 0, len(mat)) + for _, series := range mat { + // We expect either Floats or Histograms. + for _, point := range series.Floats { + if point.T == timeMilliseconds(iq.evalTime) { + vec = append(vec, Sample{Metric: series.Metric, T: point.T, F: point.F}) + break + } + } + for _, point := range series.Histograms { + if point.T == timeMilliseconds(iq.evalTime) { + vec = append(vec, Sample{Metric: series.Metric, T: point.T, H: point.H}) + break + } + } + } + if _, ok := res.Value.(Scalar); ok { + err = cmd.compareResult(Scalar{V: vec[0].F}) + } else { + err = cmd.compareResult(vec) + } + if err != nil { + return fmt.Errorf("error in %s %s (line %d) range mode: %w", cmd, iq.expr, cmd.line, err) + } + } + + return nil +} + +func assertMatrixSorted(m Matrix) error { + if len(m) <= 1 { + return nil + } + + for i, s := range m[:len(m)-1] { + nextIndex := i + 1 + nextMetric := m[nextIndex].Metric + + if labels.Compare(s.Metric, nextMetric) > 0 { + return fmt.Errorf("matrix results should always be sorted by labels, but matrix is not sorted: series at index %v with labels %s sorts before series at index %v with labels %s", nextIndex, nextMetric, i, s.Metric) + } + } + + return nil +} + // clear the current test storage of all inserted samples. func (t *test) clear() { if t.storage != nil { diff --git a/promql/test_test.go b/promql/test_test.go index 316c177d77..0130a789d7 100644 --- a/promql/test_test.go +++ b/promql/test_test.go @@ -156,3 +156,354 @@ func TestLazyLoader_WithSamplesTill(t *testing.T) { } } } + +func TestRunTest(t *testing.T) { + testData := ` +load 5m + http_requests{job="api-server", instance="0", group="production"} 0+10x10 + http_requests{job="api-server", instance="1", group="production"} 0+20x10 + http_requests{job="api-server", instance="0", group="canary"} 0+30x10 + http_requests{job="api-server", instance="1", group="canary"} 0+40x10 +` + + testCases := map[string]struct { + input string + expectedError string + }{ + "instant query with expected float result": { + input: testData + ` +eval instant at 5m sum by (group) (http_requests) + {group="production"} 30 + {group="canary"} 70 +`, + }, + "instant query with unexpected float result": { + input: testData + ` +eval instant at 5m sum by (group) (http_requests) + {group="production"} 30 + {group="canary"} 80 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): expected 80 for {group="canary"} but got 70`, + }, + "instant query with expected histogram result": { + input: ` +load 5m + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} + +eval instant at 0 testmetric + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} +`, + }, + "instant query with unexpected histogram result": { + input: ` +load 5m + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} + +eval instant at 0 testmetric + testmetric {{schema:-1 sum:6 count:1 buckets:[1] offset:1}} +`, + expectedError: `error in eval testmetric (line 5): expected {{schema:-1 count:1 sum:6 offset:1 buckets:[1]}} for {__name__="testmetric"} but got {{schema:-1 count:1 sum:4 offset:1 buckets:[1]}}`, + }, + "instant query with float value returned when histogram expected": { + input: ` +load 5m + testmetric 2 + +eval instant at 0 testmetric + testmetric {{}} +`, + expectedError: `error in eval testmetric (line 5): expected histogram {{}} for {__name__="testmetric"} but got float value 2`, + }, + "instant query with histogram returned when float expected": { + input: ` +load 5m + testmetric {{}} + +eval instant at 0 testmetric + testmetric 2 +`, + expectedError: `error in eval testmetric (line 5): expected float value 2.000000 for {__name__="testmetric"} but got histogram {{}}`, + }, + "instant query, but result has an unexpected series": { + input: testData + ` +eval instant at 5m sum by (group) (http_requests) + {group="production"} 30 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): unexpected metric {group="canary"} in result`, + }, + "instant query, but result is missing a series": { + input: testData + ` +eval instant at 5m sum by (group) (http_requests) + {group="production"} 30 + {group="canary"} 70 + {group="test"} 100 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): expected metric {group="test"} with 3: [100.000000] not found`, + }, + "instant query expected to fail, and query fails": { + input: ` +load 5m + testmetric1{src="a",dst="b"} 0 + testmetric2{src="a",dst="b"} 1 + +eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'}) +`, + }, + "instant query expected to fail, but query succeeds": { + input: `eval_fail instant at 0s vector(0)`, + expectedError: `expected error evaluating query "vector(0)" (line 1) but got none`, + }, + "instant query with results expected to match provided order, and result is in expected order": { + input: testData + ` +eval_ordered instant at 50m sort(http_requests) + http_requests{group="production", instance="0", job="api-server"} 100 + http_requests{group="production", instance="1", job="api-server"} 200 + http_requests{group="canary", instance="0", job="api-server"} 300 + http_requests{group="canary", instance="1", job="api-server"} 400 +`, + }, + "instant query with results expected to match provided order, but result is out of order": { + input: testData + ` +eval_ordered instant at 50m sort(http_requests) + http_requests{group="production", instance="0", job="api-server"} 100 + http_requests{group="production", instance="1", job="api-server"} 200 + http_requests{group="canary", instance="1", job="api-server"} 400 + http_requests{group="canary", instance="0", job="api-server"} 300 +`, + expectedError: `error in eval sort(http_requests) (line 8): expected metric {__name__="http_requests", group="canary", instance="0", job="api-server"} with [300.000000] at position 4 but was at 3`, + }, + "instant query with results expected to match provided order, but result has an unexpected series": { + input: testData + ` +eval_ordered instant at 50m sort(http_requests) + http_requests{group="production", instance="0", job="api-server"} 100 + http_requests{group="production", instance="1", job="api-server"} 200 + http_requests{group="canary", instance="0", job="api-server"} 300 +`, + expectedError: `error in eval sort(http_requests) (line 8): unexpected metric {__name__="http_requests", group="canary", instance="1", job="api-server"} in result`, + }, + "instant query with invalid timestamp": { + input: `eval instant at abc123 vector(0)`, + expectedError: `error in eval vector(0) (line 1): invalid timestamp definition "abc123": not a valid duration string: "abc123"`, + }, + "range query with expected result": { + input: testData + ` +eval range from 0 to 10m step 5m sum by (group) (http_requests) + {group="production"} 0 30 60 + {group="canary"} 0 70 140 +`, + }, + "range query with unexpected float value": { + input: testData + ` +eval range from 0 to 10m step 5m sum by (group) (http_requests) + {group="production"} 0 30 60 + {group="canary"} 0 80 140 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): expected float value at index 1 (t=300000) for {group="canary"} to be 80, but got 70 (result has 3 float points [0 @[0] 70 @[300000] 140 @[600000]] and 0 histogram points [])`, + }, + "range query with expected histogram values": { + input: ` +load 5m + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} {{schema:-1 sum:5 count:1 buckets:[1] offset:1}} {{schema:-1 sum:6 count:1 buckets:[1] offset:1}} + +eval range from 0 to 10m step 5m testmetric + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} {{schema:-1 sum:5 count:1 buckets:[1] offset:1}} {{schema:-1 sum:6 count:1 buckets:[1] offset:1}} +`, + }, + "range query with unexpected histogram value": { + input: ` +load 5m + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} {{schema:-1 sum:5 count:1 buckets:[1] offset:1}} {{schema:-1 sum:6 count:1 buckets:[1] offset:1}} + +eval range from 0 to 10m step 5m testmetric + testmetric {{schema:-1 sum:4 count:1 buckets:[1] offset:1}} {{schema:-1 sum:7 count:1 buckets:[1] offset:1}} {{schema:-1 sum:8 count:1 buckets:[1] offset:1}} +`, + expectedError: `error in eval testmetric (line 5): expected histogram value at index 1 (t=300000) for {__name__="testmetric"} to be {count:1, sum:7, (1,4]:1}, but got {count:1, sum:5, (1,4]:1} (result has 0 float points [] and 3 histogram points [{count:1, sum:4, (1,4]:1} @[0] {count:1, sum:5, (1,4]:1} @[300000] {count:1, sum:6, (1,4]:1} @[600000]])`, + }, + "range query with too many points for query time range": { + input: testData + ` +eval range from 0 to 10m step 5m sum by (group) (http_requests) + {group="production"} 0 30 60 90 + {group="canary"} 0 70 140 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): expected 4 points for {group="production"}, but query time range cannot return this many points`, + }, + "range query with missing point in result": { + input: ` +load 5m + testmetric 5 + +eval range from 0 to 6m step 6m testmetric + testmetric 5 10 +`, + expectedError: `error in eval testmetric (line 5): expected 2 float points and 0 histogram points for {__name__="testmetric"}, but got 1 float point [5 @[0]] and 0 histogram points []`, + }, + "range query with extra point in result": { + input: testData + ` +eval range from 0 to 10m step 5m sum by (group) (http_requests) + {group="production"} 0 30 + {group="canary"} 0 70 140 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): expected 2 float points and 0 histogram points for {group="production"}, but got 3 float points [0 @[0] 30 @[300000] 60 @[600000]] and 0 histogram points []`, + }, + "range query, but result has an unexpected series": { + input: testData + ` +eval range from 0 to 10m step 5m sum by (group) (http_requests) + {group="production"} 0 30 60 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): unexpected metric {group="canary"} in result`, + }, + "range query, but result is missing a series": { + input: testData + ` +eval range from 0 to 10m step 5m sum by (group) (http_requests) + {group="production"} 0 30 60 + {group="canary"} 0 70 140 + {group="test"} 0 100 200 +`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): expected metric {group="test"} not found`, + }, + "range query expected to fail, and query fails": { + input: ` +load 5m + testmetric1{src="a",dst="b"} 0 + testmetric2{src="a",dst="b"} 1 + +eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'}) +`, + }, + "range query expected to fail, but query succeeds": { + input: `eval_fail range from 0 to 10m step 5m vector(0)`, + expectedError: `expected error evaluating query "vector(0)" (line 1) but got none`, + }, + "range query with from and to timestamps in wrong order": { + input: `eval range from 10m to 9m step 5m vector(0)`, + expectedError: `error in eval vector(0) (line 1): invalid test definition, end timestamp (9m) is before start timestamp (10m)`, + }, + "range query with sparse output": { + input: ` +load 6m + testmetric 1 _ 3 + +eval range from 0 to 18m step 6m testmetric + testmetric 1 _ 3 +`, + }, + "range query with float value returned when no value expected": { + input: ` +load 6m + testmetric 1 2 3 + +eval range from 0 to 18m step 6m testmetric + testmetric 1 _ 3 +`, + expectedError: `error in eval testmetric (line 5): expected 2 float points and 0 histogram points for {__name__="testmetric"}, but got 3 float points [1 @[0] 2 @[360000] 3 @[720000]] and 0 histogram points []`, + }, + "range query with float value returned when histogram expected": { + input: ` +load 5m + testmetric 2 3 + +eval range from 0 to 5m step 5m testmetric + testmetric {{}} {{}} +`, + expectedError: `error in eval testmetric (line 5): expected 0 float points and 2 histogram points for {__name__="testmetric"}, but got 2 float points [2 @[0] 3 @[300000]] and 0 histogram points []`, + }, + "range query with histogram returned when float expected": { + input: ` +load 5m + testmetric {{}} {{}} + +eval range from 0 to 5m step 5m testmetric + testmetric 2 3 +`, + expectedError: `error in eval testmetric (line 5): expected 2 float points and 0 histogram points for {__name__="testmetric"}, but got 0 float points [] and 2 histogram points [{count:0, sum:0} @[0] {count:0, sum:0} @[300000]]`, + }, + "range query with expected mixed results": { + input: ` +load 6m + testmetric{group="a"} {{}} _ _ + testmetric{group="b"} _ _ 3 + +eval range from 0 to 12m step 6m sum(testmetric) + {} {{}} _ 3 +`, + }, + "range query with mixed results and incorrect values": { + input: ` +load 5m + testmetric 3 {{}} + +eval range from 0 to 5m step 5m testmetric + testmetric {{}} 3 +`, + expectedError: `error in eval testmetric (line 5): expected float value at index 0 for {__name__="testmetric"} to have timestamp 300000, but it had timestamp 0 (result has 1 float point [3 @[0]] and 1 histogram point [{count:0, sum:0} @[300000]])`, + }, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + err := runTest(t, testCase.input, newTestEngine()) + + if testCase.expectedError == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, testCase.expectedError) + } + }) + } +} + +func TestAssertMatrixSorted(t *testing.T) { + testCases := map[string]struct { + matrix Matrix + expectedError string + }{ + "empty matrix": { + matrix: Matrix{}, + }, + "matrix with one series": { + matrix: Matrix{ + Series{Metric: labels.FromStrings("the_label", "value_1")}, + }, + }, + "matrix with two series, series in sorted order": { + matrix: Matrix{ + Series{Metric: labels.FromStrings("the_label", "value_1")}, + Series{Metric: labels.FromStrings("the_label", "value_2")}, + }, + }, + "matrix with two series, series in reverse order": { + matrix: Matrix{ + Series{Metric: labels.FromStrings("the_label", "value_2")}, + Series{Metric: labels.FromStrings("the_label", "value_1")}, + }, + expectedError: `matrix results should always be sorted by labels, but matrix is not sorted: series at index 1 with labels {the_label="value_1"} sorts before series at index 0 with labels {the_label="value_2"}`, + }, + "matrix with three series, series in sorted order": { + matrix: Matrix{ + Series{Metric: labels.FromStrings("the_label", "value_1")}, + Series{Metric: labels.FromStrings("the_label", "value_2")}, + Series{Metric: labels.FromStrings("the_label", "value_3")}, + }, + }, + "matrix with three series, series not in sorted order": { + matrix: Matrix{ + Series{Metric: labels.FromStrings("the_label", "value_1")}, + Series{Metric: labels.FromStrings("the_label", "value_3")}, + Series{Metric: labels.FromStrings("the_label", "value_2")}, + }, + expectedError: `matrix results should always be sorted by labels, but matrix is not sorted: series at index 2 with labels {the_label="value_2"} sorts before series at index 1 with labels {the_label="value_3"}`, + }, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + err := assertMatrixSorted(testCase.matrix) + + if testCase.expectedError == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, testCase.expectedError) + } + }) + } +} From 35aab01de02528714f75f8cdd197b633cbadf031 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Tue, 26 Mar 2024 15:16:45 +0100 Subject: [PATCH 185/253] tsdb/wlog.Checkpoint: Handle also float histograms Signed-off-by: Arve Knudsen --- tsdb/wlog/checkpoint.go | 43 ++++++++++++++++++++++++++---------- tsdb/wlog/checkpoint_test.go | 38 ++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/tsdb/wlog/checkpoint.go b/tsdb/wlog/checkpoint.go index 5491d9718e..a16cd5fc74 100644 --- a/tsdb/wlog/checkpoint.go +++ b/tsdb/wlog/checkpoint.go @@ -149,22 +149,23 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head r := NewReader(sgmReader) var ( - series []record.RefSeries - samples []record.RefSample - histogramSamples []record.RefHistogramSample - tstones []tombstones.Stone - exemplars []record.RefExemplar - metadata []record.RefMetadata - st = labels.NewSymbolTable() // Needed for decoding; labels do not outlive this function. - dec = record.NewDecoder(st) - enc record.Encoder - buf []byte - recs [][]byte + series []record.RefSeries + samples []record.RefSample + histogramSamples []record.RefHistogramSample + floatHistogramSamples []record.RefFloatHistogramSample + tstones []tombstones.Stone + exemplars []record.RefExemplar + metadata []record.RefMetadata + st = labels.NewSymbolTable() // Needed for decoding; labels do not outlive this function. + dec = record.NewDecoder(st) + enc record.Encoder + buf []byte + recs [][]byte latestMetadataMap = make(map[chunks.HeadSeriesRef]record.RefMetadata) ) for r.Next() { - series, samples, histogramSamples, tstones, exemplars, metadata = series[:0], samples[:0], histogramSamples[:0], tstones[:0], exemplars[:0], metadata[:0] + series, samples, histogramSamples, floatHistogramSamples, tstones, exemplars, metadata = series[:0], samples[:0], histogramSamples[:0], floatHistogramSamples[:0], tstones[:0], exemplars[:0], metadata[:0] // We don't reset the buffer since we batch up multiple records // before writing them to the checkpoint. @@ -227,6 +228,24 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head stats.TotalSamples += len(histogramSamples) stats.DroppedSamples += len(histogramSamples) - len(repl) + case record.FloatHistogramSamples: + floatHistogramSamples, err = dec.FloatHistogramSamples(rec, floatHistogramSamples) + if err != nil { + return nil, fmt.Errorf("decode float histogram samples: %w", err) + } + // Drop irrelevant floatHistogramSamples in place. + repl := floatHistogramSamples[:0] + for _, fh := range floatHistogramSamples { + if fh.T >= mint { + repl = append(repl, fh) + } + } + if len(repl) > 0 { + buf = enc.FloatHistogramSamples(repl, buf) + } + stats.TotalSamples += len(floatHistogramSamples) + stats.DroppedSamples += len(floatHistogramSamples) - len(repl) + case record.Tombstones: tstones, err = dec.Tombstones(rec, tstones) if err != nil { diff --git a/tsdb/wlog/checkpoint_test.go b/tsdb/wlog/checkpoint_test.go index 0d22171768..279f7c4356 100644 --- a/tsdb/wlog/checkpoint_test.go +++ b/tsdb/wlog/checkpoint_test.go @@ -125,6 +125,20 @@ func TestCheckpoint(t *testing.T) { PositiveBuckets: []int64{int64(i + 1), 1, -1, 0}, } } + makeFloatHistogram := func(i int) *histogram.FloatHistogram { + return &histogram.FloatHistogram{ + Count: 5 + float64(i*4), + ZeroCount: 2 + float64(i), + ZeroThreshold: 0.001, + Sum: 18.4 * float64(i+1), + Schema: 1, + PositiveSpans: []histogram.Span{ + {Offset: 0, Length: 2}, + {Offset: 1, Length: 2}, + }, + PositiveBuckets: []float64{float64(i + 1), 1, -1, 0}, + } + } for _, compress := range []CompressionType{CompressionNone, CompressionSnappy, CompressionZstd} { t.Run(fmt.Sprintf("compress=%s", compress), func(t *testing.T) { @@ -154,7 +168,7 @@ func TestCheckpoint(t *testing.T) { w, err = NewSize(nil, nil, dir, 64*1024, compress) require.NoError(t, err) - samplesInWAL, histogramsInWAL := 0, 0 + samplesInWAL, histogramsInWAL, floatHistogramsInWAL := 0, 0, 0 var last int64 for i := 0; ; i++ { _, n, err := Segments(w.Dir()) @@ -200,6 +214,15 @@ func TestCheckpoint(t *testing.T) { }, nil) require.NoError(t, w.Log(b)) histogramsInWAL += 4 + fh := makeFloatHistogram(i) + b = enc.FloatHistogramSamples([]record.RefFloatHistogramSample{ + {Ref: 0, T: last, FH: fh}, + {Ref: 1, T: last + 10000, FH: fh}, + {Ref: 2, T: last + 20000, FH: fh}, + {Ref: 3, T: last + 30000, FH: fh}, + }, nil) + require.NoError(t, w.Log(b)) + floatHistogramsInWAL += 4 b = enc.Exemplars([]record.RefExemplar{ {Ref: 1, T: last, V: float64(i), Labels: labels.FromStrings("trace_id", fmt.Sprintf("trace-%d", i))}, @@ -226,7 +249,7 @@ func TestCheckpoint(t *testing.T) { require.NoError(t, err) require.NoError(t, w.Truncate(107)) require.NoError(t, DeleteCheckpoints(w.Dir(), 106)) - require.Equal(t, histogramsInWAL+samplesInWAL, stats.TotalSamples) + require.Equal(t, histogramsInWAL+floatHistogramsInWAL+samplesInWAL, stats.TotalSamples) require.Greater(t, stats.DroppedSamples, 0) // Only the new checkpoint should be left. @@ -244,7 +267,7 @@ func TestCheckpoint(t *testing.T) { var metadata []record.RefMetadata r := NewReader(sr) - samplesInCheckpoint, histogramsInCheckpoint := 0, 0 + samplesInCheckpoint, histogramsInCheckpoint, floatHistogramsInCheckpoint := 0, 0, 0 for r.Next() { rec := r.Record() @@ -266,6 +289,13 @@ func TestCheckpoint(t *testing.T) { require.GreaterOrEqual(t, h.T, last/2, "histogram with wrong timestamp") } histogramsInCheckpoint += len(histograms) + case record.FloatHistogramSamples: + floatHistograms, err := dec.FloatHistogramSamples(rec, nil) + require.NoError(t, err) + for _, h := range floatHistograms { + require.GreaterOrEqual(t, h.T, last/2, "float histogram with wrong timestamp") + } + floatHistogramsInCheckpoint += len(floatHistograms) case record.Exemplars: exemplars, err := dec.Exemplars(rec, nil) require.NoError(t, err) @@ -283,6 +313,8 @@ func TestCheckpoint(t *testing.T) { require.Less(t, float64(samplesInCheckpoint)/float64(samplesInWAL), 0.8) require.Greater(t, float64(histogramsInCheckpoint)/float64(histogramsInWAL), 0.5) require.Less(t, float64(histogramsInCheckpoint)/float64(histogramsInWAL), 0.8) + require.Greater(t, float64(floatHistogramsInCheckpoint)/float64(floatHistogramsInWAL), 0.5) + require.Less(t, float64(floatHistogramsInCheckpoint)/float64(floatHistogramsInWAL), 0.8) expectedRefSeries := []record.RefSeries{ {Ref: 0, Labels: labels.FromStrings("a", "b", "c", "0")}, From 44f385fd519197f8b93075fc5ec795818f5fdb74 Mon Sep 17 00:00:00 2001 From: suntala Date: Tue, 12 Mar 2024 20:14:31 +0100 Subject: [PATCH 186/253] Support expansion of native histogram values in alert templates Co-authored-by: Aleks Fazlieva Signed-off-by: suntala --- model/rulefmt/rulefmt.go | 3 +- rules/alerting.go | 2 +- rules/alerting_test.go | 62 ++++++++++++++++++++++++++++++++++++++++ template/template.go | 14 ++++++--- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/model/rulefmt/rulefmt.go b/model/rulefmt/rulefmt.go index 03cbd8849c..4ed1619d64 100644 --- a/model/rulefmt/rulefmt.go +++ b/model/rulefmt/rulefmt.go @@ -27,6 +27,7 @@ import ( "gopkg.in/yaml.v3" "github.com/prometheus/prometheus/model/timestamp" + "github.com/prometheus/prometheus/promql" "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/template" ) @@ -256,7 +257,7 @@ func testTemplateParsing(rl *RuleNode) (errs []error) { } // Trying to parse templates. - tmplData := template.AlertTemplateData(map[string]string{}, map[string]string{}, "", 0) + tmplData := template.AlertTemplateData(map[string]string{}, map[string]string{}, "", promql.Sample{}) defs := []string{ "{{$labels := .Labels}}", "{{$externalLabels := .ExternalLabels}}", diff --git a/rules/alerting.go b/rules/alerting.go index 7b0921a724..50c67fa2d9 100644 --- a/rules/alerting.go +++ b/rules/alerting.go @@ -364,7 +364,7 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, // Provide the alert information to the template. l := smpl.Metric.Map() - tmplData := template.AlertTemplateData(l, r.externalLabels, r.externalURL, smpl.F) + tmplData := template.AlertTemplateData(l, r.externalLabels, r.externalURL, smpl) // Inject some convenience variables that are easier to remember for users // who are not used to Go's templating system. defs := []string{ diff --git a/rules/alerting_test.go b/rules/alerting_test.go index a270731d92..ddfe345efb 100644 --- a/rules/alerting_test.go +++ b/rules/alerting_test.go @@ -23,6 +23,7 @@ import ( "github.com/prometheus/common/model" "github.com/stretchr/testify/require" + "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/relabel" "github.com/prometheus/prometheus/model/timestamp" @@ -85,6 +86,67 @@ func TestAlertingRuleState(t *testing.T) { } } +func TestAlertingRuleTemplateWithHistogram(t *testing.T) { + h := histogram.FloatHistogram{ + Schema: 0, + Count: 30, + Sum: 1111.1, + ZeroThreshold: 0.001, + ZeroCount: 2, + PositiveSpans: []histogram.Span{ + {Offset: 0, Length: 1}, + {Offset: 1, Length: 5}, + }, + PositiveBuckets: []float64{1, 1, 2, 1, 1, 1}, + NegativeSpans: []histogram.Span{ + {Offset: 1, Length: 4}, + {Offset: 4, Length: 3}, + }, + NegativeBuckets: []float64{-2, 2, 2, 7, 5, 5, 2}, + } + + q := func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) { + return []promql.Sample{{H: &h}}, nil + } + + expr, err := parser.ParseExpr("foo") + require.NoError(t, err) + + rule := NewAlertingRule( + "HistogramAsValue", + expr, + time.Minute, + 0, + labels.FromStrings("histogram", "{{ $value }}"), + labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil, + ) + + evalTime := time.Now() + res, err := rule.Eval(context.TODO(), evalTime, q, nil, 0) + require.NoError(t, err) + + require.Len(t, res, 2) + for _, smpl := range res { + smplName := smpl.Metric.Get("__name__") + if smplName == "ALERTS" { + result := promql.Sample{ + Metric: labels.FromStrings( + "__name__", "ALERTS", + "alertname", "HistogramAsValue", + "alertstate", "pending", + "histogram", h.String(), + ), + T: timestamp.FromTime(evalTime), + F: 1, + } + testutil.RequireEqual(t, result, smpl) + } else { + // If not 'ALERTS', it has to be 'ALERTS_FOR_STATE'. + require.Equal(t, "ALERTS_FOR_STATE", smplName) + } + } +} + func TestAlertingRuleLabelsUpdate(t *testing.T) { storage := promql.LoadedStorage(t, ` load 1m diff --git a/template/template.go b/template/template.go index 5d72a7e83e..f04f5ea533 100644 --- a/template/template.go +++ b/template/template.go @@ -355,18 +355,24 @@ func NewTemplateExpander( } // AlertTemplateData returns the interface to be used in expanding the template. -func AlertTemplateData(labels, externalLabels map[string]string, externalURL string, value float64) interface{} { - return struct { +func AlertTemplateData(labels, externalLabels map[string]string, externalURL string, smpl promql.Sample) interface{} { + res := struct { Labels map[string]string ExternalLabels map[string]string ExternalURL string - Value float64 + Value interface{} }{ Labels: labels, ExternalLabels: externalLabels, ExternalURL: externalURL, - Value: value, + Value: smpl.F, } + + if smpl.H != nil { + res.Value = smpl.H + } + + return res } // Funcs adds the functions in fm to the Expander's function map. From 9a7c6a5cc44541dbdd71e985f182be7079aa4ff6 Mon Sep 17 00:00:00 2001 From: suntala Date: Tue, 26 Mar 2024 22:17:19 +0100 Subject: [PATCH 187/253] Support native histogram values in template functions Co-authored-by: Aleks Fazlieva Signed-off-by: suntala --- docs/configuration/template_reference.md | 4 ++-- template/template.go | 7 +++++-- template/template_test.go | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/configuration/template_reference.md b/docs/configuration/template_reference.md index 06942891b1..47df9d1e09 100644 --- a/docs/configuration/template_reference.md +++ b/docs/configuration/template_reference.md @@ -18,7 +18,7 @@ The primary data structure for dealing with time series data is the sample, defi ```go type sample struct { Labels map[string]string - Value float64 + Value interface{} } ``` @@ -44,7 +44,7 @@ If functions are used in a pipeline, the pipeline value is passed as the last ar | query | query string | []sample | Queries the database, does not support returning range vectors. | | first | []sample | sample | Equivalent to `index a 0` | | label | label, sample | string | Equivalent to `index sample.Labels label` | -| value | sample | float64 | Equivalent to `sample.Value` | +| value | sample | interface{} | Equivalent to `sample.Value` | | sortByLabel | label, []samples | []sample | Sorts the samples by the given label. Is stable. | `first`, `label` and `value` are intended to make query results easily usable in pipelines. diff --git a/template/template.go b/template/template.go index f04f5ea533..43772805cd 100644 --- a/template/template.go +++ b/template/template.go @@ -57,7 +57,7 @@ func init() { // A version of vector that's easier to use from templates. type sample struct { Labels map[string]string - Value float64 + Value interface{} } type queryResult []*sample @@ -96,6 +96,9 @@ func query(ctx context.Context, q string, ts time.Time, queryFn QueryFunc) (quer Value: v.F, Labels: v.Metric.Map(), } + if v.H != nil { + s.Value = v.H + } result[n] = &s } return result, nil @@ -160,7 +163,7 @@ func NewTemplateExpander( "label": func(label string, s *sample) string { return s.Labels[label] }, - "value": func(s *sample) float64 { + "value": func(s *sample) interface{} { return s.Value }, "strvalue": func(s *sample) string { diff --git a/template/template_test.go b/template/template_test.go index e7bdcc3b80..57de1d0f55 100644 --- a/template/template_test.go +++ b/template/template_test.go @@ -23,6 +23,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql" ) @@ -39,6 +40,12 @@ func TestTemplateExpansion(t *testing.T) { text: "{{ 1 }}", output: "1", }, + { + // Native histogram value. + text: "{{ . | value }}", + input: &sample{Value: &histogram.FloatHistogram{Count: 3, Sum: 10}}, + output: (&histogram.FloatHistogram{Count: 3, Sum: 10}).String(), + }, { // Non-ASCII space (not allowed in text/template, see https://github.com/golang/go/blob/master/src/text/template/parse/lex.go#L98) text: "{{ }}", @@ -84,6 +91,18 @@ func TestTemplateExpansion(t *testing.T) { }, output: "11", }, + { + // Get value of a native histogram from query. + text: "{{ query \"metric{instance='a'}\" | first | value }}", + queryResult: promql.Vector{ + { + Metric: labels.FromStrings(labels.MetricName, "metric", "instance", "a"), + T: 0, + H: &histogram.FloatHistogram{Count: 3, Sum: 10}, + }, + }, + output: (&histogram.FloatHistogram{Count: 3, Sum: 10}).String(), + }, { // Get label from query. text: "{{ query \"metric{instance='a'}\" | first | label \"instance\" }}", From 435f330d0b139111c1c6e9a3ab5854c7077e4056 Mon Sep 17 00:00:00 2001 From: Domantas Date: Wed, 27 Mar 2024 12:35:17 +0200 Subject: [PATCH 188/253] [BUGFIX] labels: don't modify original labels in DropMetricName (#13845) Restrict the capacity of first argument to `append()` to force an allocation. This is for the slice implementation only. Signed-off-by: Domantas Jadenkus --- model/labels/labels.go | 4 +++- model/labels/labels_test.go | 6 +++++- promql/engine_test.go | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/model/labels/labels.go b/model/labels/labels.go index e998248269..01514abf38 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -349,7 +349,9 @@ func (ls Labels) DropMetricName() Labels { if i == 0 { // Make common case fast with no allocations. return ls[1:] } - return append(ls[:i], ls[i+1:]...) + // Avoid modifying original Labels - use [:i:i] so that left slice would not + // have any spare capacity and append would have to allocate a new slice for the result. + return append(ls[:i:i], ls[i+1:]...) } } return ls diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index cedeb95a6c..90ae41ccea 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -457,7 +457,11 @@ func TestLabels_Get(t *testing.T) { func TestLabels_DropMetricName(t *testing.T) { require.True(t, Equal(FromStrings("aaa", "111", "bbb", "222"), FromStrings("aaa", "111", "bbb", "222").DropMetricName())) require.True(t, Equal(FromStrings("aaa", "111"), FromStrings(MetricName, "myname", "aaa", "111").DropMetricName())) - require.True(t, Equal(FromStrings("__aaa__", "111", "bbb", "222"), FromStrings("__aaa__", "111", MetricName, "myname", "bbb", "222").DropMetricName())) + + original := FromStrings("__aaa__", "111", MetricName, "myname", "bbb", "222") + check := FromStrings("__aaa__", "111", MetricName, "myname", "bbb", "222") + require.True(t, Equal(FromStrings("__aaa__", "111", "bbb", "222"), check.DropMetricName())) + require.True(t, Equal(original, check)) } // BenchmarkLabels_Get was written to check whether a binary search can improve the performance vs the linear search implementation diff --git a/promql/engine_test.go b/promql/engine_test.go index cc5d0ee780..3f6727d849 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -3212,6 +3212,24 @@ func TestRangeQuery(t *testing.T) { End: time.Unix(120, 0), Interval: 1 * time.Minute, }, + { + Name: "drop-metric-name", + Load: `load 30s + requests{job="1", __address__="bar"} 100`, + Query: `requests * 2`, + Result: Matrix{ + Series{ + Floats: []FPoint{{F: 200, T: 0}, {F: 200, T: 60000}, {F: 200, T: 120000}}, + Metric: labels.FromStrings( + "__address__", "bar", + "job", "1", + ), + }, + }, + Start: time.Unix(0, 0), + End: time.Unix(120, 0), + Interval: 1 * time.Minute, + }, } for _, c := range cases { t.Run(c.Name, func(t *testing.T) { From 3929d6500a89c36b31264b50fd60de28426eaa43 Mon Sep 17 00:00:00 2001 From: Domantas Date: Wed, 27 Mar 2024 12:35:17 +0200 Subject: [PATCH 189/253] [BUGFIX] labels: don't modify original labels in DropMetricName (#13845) Restrict the capacity of first argument to `append()` to force an allocation. This is for the slice implementation only. Signed-off-by: Domantas Jadenkus Signed-off-by: Bryan Boreham --- model/labels/labels.go | 4 +++- model/labels/labels_test.go | 6 +++++- promql/engine_test.go | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/model/labels/labels.go b/model/labels/labels.go index e998248269..01514abf38 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -349,7 +349,9 @@ func (ls Labels) DropMetricName() Labels { if i == 0 { // Make common case fast with no allocations. return ls[1:] } - return append(ls[:i], ls[i+1:]...) + // Avoid modifying original Labels - use [:i:i] so that left slice would not + // have any spare capacity and append would have to allocate a new slice for the result. + return append(ls[:i:i], ls[i+1:]...) } } return ls diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index c2ac6d63a0..359e6de3b8 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -450,7 +450,11 @@ func TestLabels_Get(t *testing.T) { func TestLabels_DropMetricName(t *testing.T) { require.True(t, Equal(FromStrings("aaa", "111", "bbb", "222"), FromStrings("aaa", "111", "bbb", "222").DropMetricName())) require.True(t, Equal(FromStrings("aaa", "111"), FromStrings(MetricName, "myname", "aaa", "111").DropMetricName())) - require.True(t, Equal(FromStrings("__aaa__", "111", "bbb", "222"), FromStrings("__aaa__", "111", MetricName, "myname", "bbb", "222").DropMetricName())) + + original := FromStrings("__aaa__", "111", MetricName, "myname", "bbb", "222") + check := FromStrings("__aaa__", "111", MetricName, "myname", "bbb", "222") + require.True(t, Equal(FromStrings("__aaa__", "111", "bbb", "222"), check.DropMetricName())) + require.True(t, Equal(original, check)) } // BenchmarkLabels_Get was written to check whether a binary search can improve the performance vs the linear search implementation diff --git a/promql/engine_test.go b/promql/engine_test.go index 105108d5b2..ea65e01a63 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -3136,6 +3136,24 @@ func TestRangeQuery(t *testing.T) { End: time.Unix(120, 0), Interval: 1 * time.Minute, }, + { + Name: "drop-metric-name", + Load: `load 30s + requests{job="1", __address__="bar"} 100`, + Query: `requests * 2`, + Result: Matrix{ + Series{ + Floats: []FPoint{{F: 200, T: 0}, {F: 200, T: 60000}, {F: 200, T: 120000}}, + Metric: labels.FromStrings( + "__address__", "bar", + "job", "1", + ), + }, + }, + Start: time.Unix(0, 0), + End: time.Unix(120, 0), + Interval: 1 * time.Minute, + }, } for _, c := range cases { t.Run(c.Name, func(t *testing.T) { From 64dfd8a158fe8de72d8019c54ea4242956e4d652 Mon Sep 17 00:00:00 2001 From: Ziqi Zhao Date: Wed, 27 Mar 2024 23:32:37 +0800 Subject: [PATCH 190/253] fix the bug of setting native histogram min bucket factor (#13846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix the bug of setting native histogram min bucket factor Signed-off-by: Ziqi Zhao * Add unit test for checking that min_bucket_factor is correctly applied Signed-off-by: György Krajcsovits --------- Signed-off-by: Ziqi Zhao Signed-off-by: György Krajcsovits Co-authored-by: György Krajcsovits --- scrape/scrape.go | 2 + scrape/scrape_test.go | 135 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/scrape/scrape.go b/scrape/scrape.go index 064b0b67bc..734c248130 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -427,6 +427,7 @@ func (sp *scrapePool) sync(targets []*Target) { bodySizeLimit = int64(sp.config.BodySizeLimit) sampleLimit = int(sp.config.SampleLimit) bucketLimit = int(sp.config.NativeHistogramBucketLimit) + maxSchema = pickSchema(sp.config.NativeHistogramMinBucketFactor) labelLimits = &labelLimits{ labelLimit: int(sp.config.LabelLimit), labelNameLengthLimit: int(sp.config.LabelNameLengthLimit), @@ -464,6 +465,7 @@ func (sp *scrapePool) sync(targets []*Target) { scraper: s, sampleLimit: sampleLimit, bucketLimit: bucketLimit, + maxSchema: maxSchema, labelLimits: labelLimits, honorLabels: honorLabels, honorTimestamps: honorTimestamps, diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index 0dfca538d8..20b21936b9 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -41,6 +41,7 @@ import ( "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/config" + "github.com/prometheus/prometheus/discovery" "github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/model/exemplar" "github.com/prometheus/prometheus/model/histogram" @@ -3631,3 +3632,137 @@ func TestScrapeLoopSeriesAddedDuplicates(t *testing.T) { value := metric.GetCounter().GetValue() require.Equal(t, 4.0, value) } + +// This tests running a full scrape loop and checking that the scrape option +// `native_histogram_min_bucket_factor` is used correctly. +func TestNativeHistogramMaxSchemaSet(t *testing.T) { + testcases := map[string]struct { + minBucketFactor string + expectedSchema int32 + }{ + "min factor not specified": { + minBucketFactor: "", + expectedSchema: 3, // Factor 1.09. + }, + "min factor 1": { + minBucketFactor: "native_histogram_min_bucket_factor: 1", + expectedSchema: 3, // Factor 1.09. + }, + "min factor 2": { + minBucketFactor: "native_histogram_min_bucket_factor: 2", + expectedSchema: 0, // Factor 2.00. + }, + } + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + testNativeHistogramMaxSchemaSet(t, tc.minBucketFactor, tc.expectedSchema) + }) + } +} + +func testNativeHistogramMaxSchemaSet(t *testing.T, minBucketFactor string, expectedSchema int32) { + // Create a ProtoBuf message to serve as a Prometheus metric. + nativeHistogram := prometheus.NewHistogram( + prometheus.HistogramOpts{ + Namespace: "testing", + Name: "example_native_histogram", + Help: "This is used for testing", + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + }, + ) + registry := prometheus.NewRegistry() + registry.Register(nativeHistogram) + nativeHistogram.Observe(1.0) + nativeHistogram.Observe(1.0) + nativeHistogram.Observe(1.0) + nativeHistogram.Observe(10.0) // in different bucket since > 1*1.1. + nativeHistogram.Observe(10.0) + + gathered, err := registry.Gather() + require.NoError(t, err) + require.NotEmpty(t, gathered) + + histogramMetricFamily := gathered[0] + buffer := protoMarshalDelimited(t, histogramMetricFamily) + + // Create a HTTP server to serve /metrics via ProtoBuf + metricsServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`) + w.Write(buffer) + })) + defer metricsServer.Close() + + // Create a scrape loop with the HTTP server as the target. + configStr := fmt.Sprintf(` +global: + scrape_interval: 1s + scrape_timeout: 1s +scrape_configs: + - job_name: test + %s + static_configs: + - targets: [%s] +`, minBucketFactor, strings.ReplaceAll(metricsServer.URL, "http://", "")) + + s := teststorage.New(t) + defer s.Close() + s.DB.EnableNativeHistograms() + reg := prometheus.NewRegistry() + + mng, err := NewManager(nil, nil, s, reg) + require.NoError(t, err) + cfg, err := config.Load(configStr, false, log.NewNopLogger()) + require.NoError(t, err) + mng.ApplyConfig(cfg) + tsets := make(chan map[string][]*targetgroup.Group) + go func() { + err = mng.Run(tsets) + require.NoError(t, err) + }() + defer mng.Stop() + + // Get the static targets and apply them to the scrape manager. + require.Len(t, cfg.ScrapeConfigs, 1) + scrapeCfg := cfg.ScrapeConfigs[0] + require.Len(t, scrapeCfg.ServiceDiscoveryConfigs, 1) + staticDiscovery, ok := scrapeCfg.ServiceDiscoveryConfigs[0].(discovery.StaticConfig) + require.True(t, ok) + require.Len(t, staticDiscovery, 1) + tsets <- map[string][]*targetgroup.Group{"test": staticDiscovery} + + // Wait for the scrape loop to scrape the target. + require.Eventually(t, func() bool { + q, err := s.Querier(0, math.MaxInt64) + require.NoError(t, err) + seriesS := q.Select(context.Background(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "__name__", "testing_example_native_histogram")) + countSeries := 0 + for seriesS.Next() { + countSeries++ + } + return countSeries > 0 + }, 15*time.Second, 100*time.Millisecond) + + // Check that native histogram schema is as expected. + q, err := s.Querier(0, math.MaxInt64) + require.NoError(t, err) + seriesS := q.Select(context.Background(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "__name__", "testing_example_native_histogram")) + histogramSamples := []*histogram.Histogram{} + for seriesS.Next() { + series := seriesS.At() + it := series.Iterator(nil) + for vt := it.Next(); vt != chunkenc.ValNone; vt = it.Next() { + if vt != chunkenc.ValHistogram { + // don't care about other samples + continue + } + _, h := it.AtHistogram(nil) + histogramSamples = append(histogramSamples, h) + } + } + require.NoError(t, seriesS.Err()) + require.NotEmpty(t, histogramSamples) + for _, h := range histogramSamples { + require.Equal(t, expectedSchema, h.Schema) + } +} From d64c6fe34faf5ea0d64ea1555b7b0a66cbc09020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Wed, 27 Mar 2024 16:41:23 +0100 Subject: [PATCH 191/253] fix the bug of setting native histogram min bucket factor (#13846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix the bug of setting native histogram min bucket factor Signed-off-by: Ziqi Zhao * Add unit test for checking that min_bucket_factor is correctly applied Signed-off-by: György Krajcsovits --------- Signed-off-by: Ziqi Zhao Signed-off-by: György Krajcsovits Co-authored-by: György Krajcsovits --- scrape/scrape.go | 2 + scrape/scrape_test.go | 135 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/scrape/scrape.go b/scrape/scrape.go index f6f3367736..219eba4d99 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -427,6 +427,7 @@ func (sp *scrapePool) sync(targets []*Target) { bodySizeLimit = int64(sp.config.BodySizeLimit) sampleLimit = int(sp.config.SampleLimit) bucketLimit = int(sp.config.NativeHistogramBucketLimit) + maxSchema = pickSchema(sp.config.NativeHistogramMinBucketFactor) labelLimits = &labelLimits{ labelLimit: int(sp.config.LabelLimit), labelNameLengthLimit: int(sp.config.LabelNameLengthLimit), @@ -464,6 +465,7 @@ func (sp *scrapePool) sync(targets []*Target) { scraper: s, sampleLimit: sampleLimit, bucketLimit: bucketLimit, + maxSchema: maxSchema, labelLimits: labelLimits, honorLabels: honorLabels, honorTimestamps: honorTimestamps, diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index bcaeb460e2..4dfa4f684e 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -41,6 +41,7 @@ import ( "github.com/stretchr/testify/require" "github.com/prometheus/prometheus/config" + "github.com/prometheus/prometheus/discovery" "github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/model/exemplar" "github.com/prometheus/prometheus/model/histogram" @@ -3599,3 +3600,137 @@ func BenchmarkTargetScraperGzip(b *testing.B) { }) } } + +// This tests running a full scrape loop and checking that the scrape option +// `native_histogram_min_bucket_factor` is used correctly. +func TestNativeHistogramMaxSchemaSet(t *testing.T) { + testcases := map[string]struct { + minBucketFactor string + expectedSchema int32 + }{ + "min factor not specified": { + minBucketFactor: "", + expectedSchema: 3, // Factor 1.09. + }, + "min factor 1": { + minBucketFactor: "native_histogram_min_bucket_factor: 1", + expectedSchema: 3, // Factor 1.09. + }, + "min factor 2": { + minBucketFactor: "native_histogram_min_bucket_factor: 2", + expectedSchema: 0, // Factor 2.00. + }, + } + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + testNativeHistogramMaxSchemaSet(t, tc.minBucketFactor, tc.expectedSchema) + }) + } +} + +func testNativeHistogramMaxSchemaSet(t *testing.T, minBucketFactor string, expectedSchema int32) { + // Create a ProtoBuf message to serve as a Prometheus metric. + nativeHistogram := prometheus.NewHistogram( + prometheus.HistogramOpts{ + Namespace: "testing", + Name: "example_native_histogram", + Help: "This is used for testing", + NativeHistogramBucketFactor: 1.1, + NativeHistogramMaxBucketNumber: 100, + }, + ) + registry := prometheus.NewRegistry() + registry.Register(nativeHistogram) + nativeHistogram.Observe(1.0) + nativeHistogram.Observe(1.0) + nativeHistogram.Observe(1.0) + nativeHistogram.Observe(10.0) // in different bucket since > 1*1.1. + nativeHistogram.Observe(10.0) + + gathered, err := registry.Gather() + require.NoError(t, err) + require.NotEmpty(t, gathered) + + histogramMetricFamily := gathered[0] + buffer := protoMarshalDelimited(t, histogramMetricFamily) + + // Create a HTTP server to serve /metrics via ProtoBuf + metricsServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`) + w.Write(buffer) + })) + defer metricsServer.Close() + + // Create a scrape loop with the HTTP server as the target. + configStr := fmt.Sprintf(` +global: + scrape_interval: 1s + scrape_timeout: 1s +scrape_configs: + - job_name: test + %s + static_configs: + - targets: [%s] +`, minBucketFactor, strings.ReplaceAll(metricsServer.URL, "http://", "")) + + s := teststorage.New(t) + defer s.Close() + s.DB.EnableNativeHistograms() + reg := prometheus.NewRegistry() + + mng, err := NewManager(nil, nil, s, reg) + require.NoError(t, err) + cfg, err := config.Load(configStr, false, log.NewNopLogger()) + require.NoError(t, err) + mng.ApplyConfig(cfg) + tsets := make(chan map[string][]*targetgroup.Group) + go func() { + err = mng.Run(tsets) + require.NoError(t, err) + }() + defer mng.Stop() + + // Get the static targets and apply them to the scrape manager. + require.Len(t, cfg.ScrapeConfigs, 1) + scrapeCfg := cfg.ScrapeConfigs[0] + require.Len(t, scrapeCfg.ServiceDiscoveryConfigs, 1) + staticDiscovery, ok := scrapeCfg.ServiceDiscoveryConfigs[0].(discovery.StaticConfig) + require.True(t, ok) + require.Len(t, staticDiscovery, 1) + tsets <- map[string][]*targetgroup.Group{"test": staticDiscovery} + + // Wait for the scrape loop to scrape the target. + require.Eventually(t, func() bool { + q, err := s.Querier(0, math.MaxInt64) + require.NoError(t, err) + seriesS := q.Select(context.Background(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "__name__", "testing_example_native_histogram")) + countSeries := 0 + for seriesS.Next() { + countSeries++ + } + return countSeries > 0 + }, 15*time.Second, 100*time.Millisecond) + + // Check that native histogram schema is as expected. + q, err := s.Querier(0, math.MaxInt64) + require.NoError(t, err) + seriesS := q.Select(context.Background(), false, nil, labels.MustNewMatcher(labels.MatchEqual, "__name__", "testing_example_native_histogram")) + histogramSamples := []*histogram.Histogram{} + for seriesS.Next() { + series := seriesS.At() + it := series.Iterator(nil) + for vt := it.Next(); vt != chunkenc.ValNone; vt = it.Next() { + if vt != chunkenc.ValHistogram { + // don't care about other samples + continue + } + _, h := it.AtHistogram(nil) + histogramSamples = append(histogramSamples, h) + } + } + require.NoError(t, seriesS.Err()) + require.NotEmpty(t, histogramSamples) + for _, h := range histogramSamples { + require.Equal(t, expectedSchema, h.Schema) + } +} From 22d0f4f114b9143c66d7805ed92c5f692e74c066 Mon Sep 17 00:00:00 2001 From: Jeanette Tan Date: Fri, 22 Mar 2024 03:42:50 +0800 Subject: [PATCH 192/253] improve handling of negative bounds in histogram std dev/var Signed-off-by: Jeanette Tan --- promql/engine_test.go | 6 +++--- promql/functions.go | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/promql/engine_test.go b/promql/engine_test.go index 3f5f2dc132..9d43efdb90 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -3496,7 +3496,7 @@ func TestNativeHistogram_HistogramStdDevVar(t *testing.T) { }, NegativeBuckets: []int64{1, 0}, }, - stdVar: 1544.8582535368798, // actual variance: 1738.4082 + stdVar: 1844.4651144196398, // actual variance: 1738.4082 }, { name: "-100000, -10000, -1000, -888, -888, -100, -50, -9, -8, -3", @@ -3514,7 +3514,7 @@ func TestNativeHistogram_HistogramStdDevVar(t *testing.T) { }, NegativeBuckets: []int64{1, 0, 0, 0, 0, 2, -2, 0}, }, - stdVar: 1240930974.5260057, // actual variance: 882690990 + stdVar: 759352122.1939945, // actual variance: 882690990 }, { name: "-10 x10", @@ -3528,7 +3528,7 @@ func TestNativeHistogram_HistogramStdDevVar(t *testing.T) { }, NegativeBuckets: []int64{10}, }, - stdVar: 454.2741699796952, // actual variance: 0 + stdVar: 1.725830020304794, // actual variance: 0 }, { name: "-50, -8, 0, 3, 8, 9, 100, NaN", diff --git a/promql/functions.go b/promql/functions.go index da66af2f02..e0b811a09d 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1116,6 +1116,9 @@ func funcHistogramStdDev(vals []parser.Value, args parser.Expressions, enh *Eval val = 0 } else { val = math.Sqrt(bucket.Upper * bucket.Lower) + if bucket.Upper < 0 { + val = -val + } } delta := val - mean variance, cVariance = kahanSumInc(bucket.Count*delta*delta, variance, cVariance) @@ -1149,6 +1152,9 @@ func funcHistogramStdVar(vals []parser.Value, args parser.Expressions, enh *Eval val = 0 } else { val = math.Sqrt(bucket.Upper * bucket.Lower) + if bucket.Upper < 0 { + val = -val + } } delta := val - mean variance, cVariance = kahanSumInc(bucket.Count*delta*delta, variance, cVariance) From 4f2df329bd8d49f69eff060da04edf91756a36fb Mon Sep 17 00:00:00 2001 From: Jeanette Tan Date: Fri, 22 Mar 2024 03:42:50 +0800 Subject: [PATCH 193/253] improve handling of empty buckets with infinite bounds in histogram std dev/var Signed-off-by: Jeanette Tan --- promql/functions.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/promql/functions.go b/promql/functions.go index e0b811a09d..6853307d0e 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1111,6 +1111,9 @@ func funcHistogramStdDev(vals []parser.Value, args parser.Expressions, enh *Eval it := sample.H.AllBucketIterator() for it.Next() { bucket := it.At() + if bucket.Count == 0 { + continue + } var val float64 if bucket.Lower <= 0 && 0 <= bucket.Upper { val = 0 @@ -1147,6 +1150,9 @@ func funcHistogramStdVar(vals []parser.Value, args parser.Expressions, enh *Eval it := sample.H.AllBucketIterator() for it.Next() { bucket := it.At() + if bucket.Count == 0 { + continue + } var val float64 if bucket.Lower <= 0 && 0 <= bucket.Upper { val = 0 From 2c1f9558b26341c1842150dd235e0d01ef939b96 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 27 Mar 2024 19:00:16 +0100 Subject: [PATCH 194/253] promql: Fix histogram comparison in test framework The definition of histograms in the test framework may create histograms in a non-compact form. Since histogram comparison relies on exact equality of the bucket layout, we have to compact the histograms created by the test framework language before comparing them to histograms returned from the PromQL engine. Signed-off-by: beorn7 --- promql/test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/promql/test.go b/promql/test.go index 296b3d3cad..a7b5b8b99f 100644 --- a/promql/test.go +++ b/promql/test.go @@ -563,7 +563,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error { return fmt.Errorf("expected histogram value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s)) } - if !actual.H.Equals(expected.H) { + if !actual.H.Equals(expected.H.Compact(0)) { return fmt.Errorf("expected histogram value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.H, actual.H, formatSeriesResult(s)) } } @@ -595,7 +595,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error { if expH != nil && v.H == nil { return fmt.Errorf("expected histogram %s for %s but got float value %v", HistogramTestExpression(expH), v.Metric, v.F) } - if expH != nil && !expH.Equals(v.H) { + if expH != nil && !expH.Compact(0).Equals(v.H) { return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H)) } if !almostEqual(exp0.Value, v.F, defaultEpsilon) { From 65b4696b88521197668c09dd08dd5e46777c6845 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Wed, 27 Mar 2024 19:02:27 +0100 Subject: [PATCH 195/253] promql: Remove leftover debug output Signed-off-by: beorn7 --- promql/test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/promql/test.go b/promql/test.go index a7b5b8b99f..ba716d1eea 100644 --- a/promql/test.go +++ b/promql/test.go @@ -606,10 +606,6 @@ func (ev *evalCmd) compareResult(result parser.Value) error { } for fp, expVals := range ev.expected { if !seen[fp] { - fmt.Println("vector result", len(val), ev.expr) - for _, ss := range val { - fmt.Println(" ", ss.Metric, ss.T, ss.F) - } return fmt.Errorf("expected metric %s with %v not found", ev.metrics[fp], expVals) } } From 855b5ac4b80956874eb1790a04c92327f2f99e38 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 28 Mar 2024 09:23:45 +0000 Subject: [PATCH 196/253] Cut release 2.51.1 (#13853) * Cut release 2.51.1 Co-authored-by: George Krajcsovits Signed-off-by: Bryan Boreham --- CHANGELOG.md | 8 ++++++++ VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 ++-- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8951866819..046d3ea60a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.51.1 / 2024-03-27 + +Bugfix release. + +* [BUGFIX] PromQL: Re-instate validation of label_join destination label #13803 +* [BUGFIX] Scraping (experimental native histograms): Fix handling of the min bucket factor on sync of targets #13846 +* [BUGFIX] PromQL: Some queries could return the same series twice (library use only) #13845 + ## 2.51.0 / 2024-03-18 This version is built with Go 1.22.1. diff --git a/VERSION b/VERSION index d66b738716..8e00e241f3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.51.0 +2.51.1 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index 5139bce620..c364e05584 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.51.0", + "version": "0.51.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.51.0", + "@prometheus-io/lezer-promql": "0.51.1", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index 2983206f5c..f5ea66602f 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.51.0", + "version": "0.51.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 d2581baf40..fdb348d669 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.51.0", + "version": "0.51.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.51.0", + "version": "0.51.1", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.51.0", + "version": "0.51.1", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.51.0", + "@prometheus-io/lezer-promql": "0.51.1", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.51.0", + "version": "0.51.1", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.51.0", + "version": "0.51.1", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.51.0", + "@prometheus-io/codemirror-promql": "0.51.1", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index 7eedd0b217..0772aad7de 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.51.0" + "version": "0.51.1" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index 4d2b5be920..b47c9180a3 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.51.0", + "version": "0.51.1", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.51.0", + "@prometheus-io/codemirror-promql": "0.51.1", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 255098e0538fdc2ae51390ea386f0edc737c3a09 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 28 Mar 2024 10:05:10 +0000 Subject: [PATCH 197/253] CI: Publish step should require all Go tests to pass This was an unintentional effect of splitting out Go tests into multiple parallel blocks. Signed-off-by: Bryan Boreham --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 498db12b6f..8866384dba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -172,7 +172,7 @@ jobs: publish_main: name: Publish main branch artifacts runs-on: ubuntu-latest - needs: [test_ui, test_go, test_windows, golangci, codeql, build_all] + needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all] if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -186,7 +186,7 @@ jobs: publish_release: name: Publish release artefacts runs-on: ubuntu-latest - needs: [test_ui, test_go, test_windows, golangci, codeql, build_all] + needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all] if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v2.') steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 From fc3ad66539a3fc371bcd640ea20bfe079309fd74 Mon Sep 17 00:00:00 2001 From: beorn7 Date: Thu, 28 Mar 2024 18:33:39 +0100 Subject: [PATCH 198/253] Appoint release shepherds for v2.52 and v2.53 Note that we have delayed v2.52 by a week to avoid collisions with events and travels. Signed-off-by: beorn7 --- RELEASE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index c2f98ab2ce..f313c4172d 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -56,6 +56,8 @@ Release cadence of first pre-releases being cut is 6 weeks. | v2.49 | 2023-12-05 | Bartek Plotka (GitHub: @bwplotka) | | v2.50 | 2024-01-16 | Augustin Husson (GitHub: @nexucis) | | v2.51 | 2024-03-07 | Bryan Boreham (GitHub: @bboreham) | +| v2.52 | 2024-04-22 | Arthur Silva Sens (GitHub: @ArthurSens) | +| v2.53 | 2024-06-03 | George Krajcsovits (GitHub: @krajorama) | If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice. From 8bd6ae1b205d72616f3289825a4c5562263a057b Mon Sep 17 00:00:00 2001 From: Simon Pasquier Date: Fri, 29 Mar 2024 14:32:39 +0100 Subject: [PATCH 199/253] Notifier: fix deadlock when zero alerts When all alerts were dropped after alert relabeling, the `sendAll()` function didn't release the lock properly which created a deadlock with the Alertmanager target discovery. In addition, the commit detects early when there are no Alertmanager endpoint to notify to avoid unnecessary work. Signed-off-by: Simon Pasquier --- notifier/notifier.go | 5 +++ notifier/notifier_test.go | 95 +++++++++++++++++++++++++++------------ 2 files changed, 72 insertions(+), 28 deletions(-) diff --git a/notifier/notifier.go b/notifier/notifier.go index d1832402f7..ff8b05aa1e 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -471,6 +471,10 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { numSuccess atomic.Uint64 ) for _, ams := range amSets { + if len(ams.ams) == 0 { + continue + } + var ( payload []byte err error @@ -482,6 +486,7 @@ func (n *Manager) sendAll(alerts ...*Alert) bool { if len(ams.cfg.AlertRelabelConfigs) > 0 { amAlerts = relabelAlerts(ams.cfg.AlertRelabelConfigs, labels.Labels{}, alerts) if len(amAlerts) == 0 { + ams.mtx.RUnlock() continue } // We can't use the cached values from previous iteration. diff --git a/notifier/notifier_test.go b/notifier/notifier_test.go index 4f32994587..e7a9243bc2 100644 --- a/notifier/notifier_test.go +++ b/notifier/notifier_test.go @@ -219,17 +219,19 @@ func TestHandlerSendAllRemapPerAm(t *testing.T) { errc = make(chan error, 1) expected1 = make([]*Alert, 0, maxBatchSize) expected2 = make([]*Alert, 0, maxBatchSize) + expected3 = make([]*Alert, 0) - status1, status2 atomic.Int32 + statusOK atomic.Int32 ) - status1.Store(int32(http.StatusOK)) - status2.Store(int32(http.StatusOK)) + statusOK.Store(int32(http.StatusOK)) - server1 := newTestHTTPServerBuilder(&expected1, errc, "", "", &status1) - server2 := newTestHTTPServerBuilder(&expected2, errc, "", "", &status2) + server1 := newTestHTTPServerBuilder(&expected1, errc, "", "", &statusOK) + server2 := newTestHTTPServerBuilder(&expected2, errc, "", "", &statusOK) + server3 := newTestHTTPServerBuilder(&expected3, errc, "", "", &statusOK) defer server1.Close() defer server2.Close() + defer server3.Close() h := NewManager(&Options{}, nil) h.alertmanagers = make(map[string]*alertmanagerSet) @@ -247,38 +249,68 @@ func TestHandlerSendAllRemapPerAm(t *testing.T) { }, } - h.alertmanagers["1"] = &alertmanagerSet{ - ams: []alertmanager{ - alertmanagerMock{ - urlf: func() string { return server1.URL }, - }, + am3Cfg := config.DefaultAlertmanagerConfig + am3Cfg.Timeout = model.Duration(time.Second) + am3Cfg.AlertRelabelConfigs = []*relabel.Config{ + { + SourceLabels: model.LabelNames{"alertname"}, + Action: "drop", + Regex: relabel.MustNewRegexp(".+"), }, - cfg: &am1Cfg, } - h.alertmanagers["2"] = &alertmanagerSet{ - ams: []alertmanager{ - alertmanagerMock{ - urlf: func() string { return server2.URL }, + h.alertmanagers = map[string]*alertmanagerSet{ + // Drop no alerts. + "1": { + ams: []alertmanager{ + alertmanagerMock{ + urlf: func() string { return server1.URL }, + }, }, + cfg: &am1Cfg, + }, + // Drop only alerts with the "alertnamedrop" label. + "2": { + ams: []alertmanager{ + alertmanagerMock{ + urlf: func() string { return server2.URL }, + }, + }, + cfg: &am2Cfg, + }, + // Drop all alerts. + "3": { + ams: []alertmanager{ + alertmanagerMock{ + urlf: func() string { return server3.URL }, + }, + }, + cfg: &am3Cfg, + }, + // Empty list of Alertmanager endpoints. + "4": { + ams: []alertmanager{}, + cfg: &config.DefaultAlertmanagerConfig, }, - cfg: &am2Cfg, } for i := range make([]struct{}, maxBatchSize/2) { - h.queue = append(h.queue, &Alert{ - Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), - }) - h.queue = append(h.queue, &Alert{ - Labels: labels.FromStrings("alertnamedrop", fmt.Sprintf("%d", i)), - }) + h.queue = append(h.queue, + &Alert{ + Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), + }, + &Alert{ + Labels: labels.FromStrings("alertname", "test", "alertnamedrop", fmt.Sprintf("%d", i)), + }, + ) - expected1 = append(expected1, &Alert{ - Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), - }) - expected1 = append(expected1, &Alert{ - Labels: labels.FromStrings("alertnamedrop", fmt.Sprintf("%d", i)), - }) + expected1 = append(expected1, + &Alert{ + Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), + }, &Alert{ + Labels: labels.FromStrings("alertname", "test", "alertnamedrop", fmt.Sprintf("%d", i)), + }, + ) expected2 = append(expected2, &Alert{ Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)), @@ -296,6 +328,13 @@ func TestHandlerSendAllRemapPerAm(t *testing.T) { require.True(t, h.sendAll(h.queue...), "all sends failed unexpectedly") checkNoErr() + + // Verify that individual locks are released. + for k := range h.alertmanagers { + h.alertmanagers[k].mtx.Lock() + h.alertmanagers[k].ams = nil + h.alertmanagers[k].mtx.Unlock() + } } func TestCustomDo(t *testing.T) { From 0b762db15434e9f85613a30cbe746023a849da26 Mon Sep 17 00:00:00 2001 From: Nicolas Takashi Date: Fri, 29 Mar 2024 23:33:15 +0000 Subject: [PATCH 200/253] [refactor] moving mergedOOOChunks to ooo_head_read Signed-off-by: Nicolas Takashi --- RELEASE.md | 2 ++ promql/test.go | 8 ++------ tsdb/head_read.go | 7 ------- tsdb/ooo_head_read.go | 7 +++++++ 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index c2f98ab2ce..f313c4172d 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -56,6 +56,8 @@ Release cadence of first pre-releases being cut is 6 weeks. | v2.49 | 2023-12-05 | Bartek Plotka (GitHub: @bwplotka) | | v2.50 | 2024-01-16 | Augustin Husson (GitHub: @nexucis) | | v2.51 | 2024-03-07 | Bryan Boreham (GitHub: @bboreham) | +| v2.52 | 2024-04-22 | Arthur Silva Sens (GitHub: @ArthurSens) | +| v2.53 | 2024-06-03 | George Krajcsovits (GitHub: @krajorama) | If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice. diff --git a/promql/test.go b/promql/test.go index 296b3d3cad..ba716d1eea 100644 --- a/promql/test.go +++ b/promql/test.go @@ -563,7 +563,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error { return fmt.Errorf("expected histogram value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s)) } - if !actual.H.Equals(expected.H) { + if !actual.H.Equals(expected.H.Compact(0)) { return fmt.Errorf("expected histogram value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.H, actual.H, formatSeriesResult(s)) } } @@ -595,7 +595,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error { if expH != nil && v.H == nil { return fmt.Errorf("expected histogram %s for %s but got float value %v", HistogramTestExpression(expH), v.Metric, v.F) } - if expH != nil && !expH.Equals(v.H) { + if expH != nil && !expH.Compact(0).Equals(v.H) { return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H)) } if !almostEqual(exp0.Value, v.F, defaultEpsilon) { @@ -606,10 +606,6 @@ func (ev *evalCmd) compareResult(result parser.Value) error { } for fp, expVals := range ev.expected { if !seen[fp] { - fmt.Println("vector result", len(val), ev.expr) - for _, ss := range val { - fmt.Println(" ", ss.Metric, ss.T, ss.F) - } return fmt.Errorf("expected metric %s with %v not found", ev.metrics[fp], expVals) } } diff --git a/tsdb/head_read.go b/tsdb/head_read.go index 10a4623924..0ad885da20 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -582,13 +582,6 @@ func (s *memSeries) oooMergedChunks(meta chunks.Meta, cdm *chunks.ChunkDiskMappe return mc, nil } -var _ chunkenc.Iterable = &mergedOOOChunks{} - -// mergedOOOChunks holds the list of iterables for overlapping chunks. -type mergedOOOChunks struct { - chunkIterables []chunkenc.Iterable -} - func (o mergedOOOChunks) Iterator(iterator chunkenc.Iterator) chunkenc.Iterator { return storage.ChainSampleIteratorFromIterables(iterator, o.chunkIterables) } diff --git a/tsdb/ooo_head_read.go b/tsdb/ooo_head_read.go index c9fe5cd580..4985ebb987 100644 --- a/tsdb/ooo_head_read.go +++ b/tsdb/ooo_head_read.go @@ -42,6 +42,13 @@ type OOOHeadIndexReader struct { lastGarbageCollectedMmapRef chunks.ChunkDiskMapperRef } +var _ chunkenc.Iterable = &mergedOOOChunks{} + +// mergedOOOChunks holds the list of iterables for overlapping chunks. +type mergedOOOChunks struct { + chunkIterables []chunkenc.Iterable +} + func NewOOOHeadIndexReader(head *Head, mint, maxt int64, lastGarbageCollectedMmapRef chunks.ChunkDiskMapperRef) *OOOHeadIndexReader { hr := &headIndexReader{ head: head, From ded35ef20dd070972ba43b2b3ec81df39f50e69e Mon Sep 17 00:00:00 2001 From: Ben Ye Date: Sun, 31 Mar 2024 15:10:29 -0700 Subject: [PATCH 201/253] expose compactor metrics Signed-off-by: Ben Ye --- tsdb/compact.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tsdb/compact.go b/tsdb/compact.go index 3d8d9130c4..4d345ffd4a 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -96,7 +96,8 @@ type CompactorMetrics struct { ChunkRange prometheus.Histogram } -func newCompactorMetrics(r prometheus.Registerer) *CompactorMetrics { +// NewCompactorMetrics initializes metrics for Compactor. +func NewCompactorMetrics(r prometheus.Registerer) *CompactorMetrics { m := &CompactorMetrics{} m.Ran = prometheus.NewCounter(prometheus.CounterOpts{ @@ -203,7 +204,7 @@ func NewLeveledCompactorWithOptions(ctx context.Context, r prometheus.Registerer ranges: ranges, chunkPool: pool, logger: l, - metrics: newCompactorMetrics(r), + metrics: NewCompactorMetrics(r), ctx: ctx, maxBlockChunkSegmentSize: maxBlockChunkSegmentSize, mergeFunc: mergeFunc, From a1d4fc71c644087a9a5d82ae038c0576957c0fa6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 12:30:53 +0000 Subject: [PATCH 202/253] build(deps): bump actions/checkout from 4.1.1 to 4.1.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/b4ffde65f46336ab88eb53be808477a3936bae11...9bb56186c3b09b4f86b1c65136769dd318469633) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/buf-lint.yml | 2 +- .github/workflows/buf.yml | 2 +- .github/workflows/ci.yml | 24 ++++++++++----------- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/container_description.yml | 4 ++-- .github/workflows/repo_sync.yml | 2 +- .github/workflows/scorecards.yml | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/buf-lint.yml b/.github/workflows/buf-lint.yml index 942db6e9b2..04e5cea792 100644 --- a/.github/workflows/buf-lint.yml +++ b/.github/workflows/buf-lint.yml @@ -12,7 +12,7 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: bufbuild/buf-setup-action@517ee23296d5caf38df31c21945e6a54bbc8a89f # v1.30.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/buf.yml b/.github/workflows/buf.yml index 9bbfd236e7..db240c9f80 100644 --- a/.github/workflows/buf.yml +++ b/.github/workflows/buf.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest if: github.repository_owner == 'prometheus' steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: bufbuild/buf-setup-action@517ee23296d5caf38df31c21945e6a54bbc8a89f # v1.30.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8866384dba..426c415fea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: # should also be updated. image: quay.io/prometheus/golang-builder:1.22-base steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/setup_environment - run: make GOOPTS=--tags=stringlabels GO_ONLY=1 SKIP_GOLANGCI_LINT=1 @@ -27,7 +27,7 @@ jobs: container: image: quay.io/prometheus/golang-builder:1.22-base steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/setup_environment - run: go test --tags=dedupelabels ./... @@ -43,7 +43,7 @@ jobs: # The go version in this image should be N-1 wrt test_go. image: quay.io/prometheus/golang-builder:1.21-base steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - run: make build # Don't run NPM build; don't run race-detector. - run: make test GO_ONLY=1 test-flags="" @@ -57,7 +57,7 @@ jobs: image: quay.io/prometheus/golang-builder:1.22-base steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/setup_environment with: @@ -74,7 +74,7 @@ jobs: name: Go tests on Windows runs-on: windows-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: 1.22.x @@ -91,7 +91,7 @@ jobs: container: image: quay.io/prometheus/golang-builder:1.22-base steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - run: go install ./cmd/promtool/. - run: go install github.com/google/go-jsonnet/cmd/jsonnet@latest - run: go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest @@ -114,7 +114,7 @@ jobs: matrix: thread: [ 0, 1, 2 ] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/build with: @@ -137,7 +137,7 @@ jobs: # Whenever the Go version is updated here, .promu.yml # should also be updated. steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/build with: @@ -148,7 +148,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Install Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: @@ -175,7 +175,7 @@ jobs: needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all] if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/publish_main with: @@ -189,7 +189,7 @@ jobs: needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all] if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v2.') steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - uses: ./.github/promci/actions/publish_release with: @@ -204,7 +204,7 @@ jobs: needs: [test_ui, codeql] steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 - name: Install nodejs uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e271405209..836fb25682 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Initialize CodeQL uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12 diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index 8a57107dd9..d0368eaa1c 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -17,7 +17,7 @@ jobs: if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. steps: - name: git checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set docker hub repo name run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV - name: Push README to Dockerhub @@ -37,7 +37,7 @@ jobs: if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. steps: - name: git checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set quay.io org name run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV - name: Set quay.io repo name diff --git a/.github/workflows/repo_sync.yml b/.github/workflows/repo_sync.yml index 1cf2eee242..3458d7b119 100644 --- a/.github/workflows/repo_sync.yml +++ b/.github/workflows/repo_sync.yml @@ -13,7 +13,7 @@ jobs: container: image: quay.io/prometheus/golang-builder steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - run: ./scripts/sync_repo_files.sh env: GITHUB_TOKEN: ${{ secrets.PROMBOT_GITHUB_TOKEN }} diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d81013c3d3..51ff643ab2 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -21,7 +21,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag=v4.1.2 with: persist-credentials: false From a67266207377f8294dcd4bd3043ecfe6dac4a086 Mon Sep 17 00:00:00 2001 From: carehabit <165479941+carehabit@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:06:05 +0800 Subject: [PATCH 203/253] all: fix some typos (#13863) Signed-off-by: carehabit --- model/labels/labels_test.go | 8 ++++---- model/labels/regexp_test.go | 2 +- model/rulefmt/testdata/bad_field.bad.yaml | 2 +- storage/remote/write_test.go | 2 +- tsdb/db.go | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index 90ae41ccea..5ec7764ca9 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -25,20 +25,20 @@ import ( func TestLabels_String(t *testing.T) { cases := []struct { - lables Labels + labels Labels expected string }{ { - lables: FromStrings("t1", "t1", "t2", "t2"), + labels: FromStrings("t1", "t1", "t2", "t2"), expected: "{t1=\"t1\", t2=\"t2\"}", }, { - lables: Labels{}, + labels: Labels{}, expected: "{}", }, } for _, c := range cases { - str := c.lables.String() + str := c.labels.String() require.Equal(t, c.expected, str) } } diff --git a/model/labels/regexp_test.go b/model/labels/regexp_test.go index fc21459ed0..ac48bdc5b5 100644 --- a/model/labels/regexp_test.go +++ b/model/labels/regexp_test.go @@ -1045,7 +1045,7 @@ func visitStringMatcher(matcher StringMatcher, callback func(matcher StringMatch visitStringMatcher(entry, callback) } - // No nested matchers for the folling ones. + // No nested matchers for the following ones. case emptyStringMatcher: case *equalStringMatcher: case *equalMultiStringSliceMatcher: diff --git a/model/rulefmt/testdata/bad_field.bad.yaml b/model/rulefmt/testdata/bad_field.bad.yaml index d85eab1e5f..729bbadfbc 100644 --- a/model/rulefmt/testdata/bad_field.bad.yaml +++ b/model/rulefmt/testdata/bad_field.bad.yaml @@ -6,4 +6,4 @@ groups: labels: instance: localhost annotation: - summary: annonations is written without s above + summary: annotations is written without s above diff --git a/storage/remote/write_test.go b/storage/remote/write_test.go index 4a9a3bafc4..c79ac3ab7d 100644 --- a/storage/remote/write_test.go +++ b/storage/remote/write_test.go @@ -409,7 +409,7 @@ func generateOTLPWriteRequest(t *testing.T) pmetricotlp.ExportRequest { // Generate One Counter, One Gauge, One Histogram, One Exponential-Histogram // with resource attributes: service.name="test-service", service.instance.id="test-instance", host.name="test-host" - // with metric attibute: foo.bar="baz" + // with metric attribute: foo.bar="baz" timestamp := time.Now() diff --git a/tsdb/db.go b/tsdb/db.go index 856a9a68a3..293ba646ea 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -42,7 +42,7 @@ import ( "github.com/prometheus/prometheus/tsdb/chunks" tsdb_errors "github.com/prometheus/prometheus/tsdb/errors" "github.com/prometheus/prometheus/tsdb/fileutil" - _ "github.com/prometheus/prometheus/tsdb/goversion" // Load the package into main to make sure minium Go version is met. + _ "github.com/prometheus/prometheus/tsdb/goversion" // Load the package into main to make sure minimum Go version is met. "github.com/prometheus/prometheus/tsdb/tsdbutil" "github.com/prometheus/prometheus/tsdb/wlog" ) From 1eb88a8723f90bd97b9e4014fe33e4edcc7477f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 23:33:16 +0000 Subject: [PATCH 204/253] build(deps): bump github.com/prometheus/prometheus Bumps [github.com/prometheus/prometheus](https://github.com/prometheus/prometheus) from 0.50.1 to 0.51.1. - [Release notes](https://github.com/prometheus/prometheus/releases) - [Changelog](https://github.com/prometheus/prometheus/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/prometheus/compare/v0.50.1...v0.51.1) --- updated-dependencies: - dependency-name: github.com/prometheus/prometheus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- documentation/examples/remote_storage/go.mod | 35 +++-- documentation/examples/remote_storage/go.sum | 131 +++++++++---------- 2 files changed, 82 insertions(+), 84 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index 917563f00c..36ee5c4d20 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -10,17 +10,17 @@ require ( github.com/influxdata/influxdb v1.11.5 github.com/prometheus/client_golang v1.19.0 github.com/prometheus/common v0.50.0 - github.com/prometheus/prometheus v0.50.1 + github.com/prometheus/prometheus v0.51.1 github.com/stretchr/testify v1.9.0 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect - github.com/aws/aws-sdk-go v1.50.0 // indirect + github.com/aws/aws-sdk-go v1.50.32 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -31,13 +31,13 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/compress v1.17.7 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -49,30 +49,29 @@ require ( github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - go.opentelemetry.io/collector/featuregate v1.0.1 // indirect - go.opentelemetry.io/collector/pdata v1.0.1 // indirect - go.opentelemetry.io/collector/semconv v0.93.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect - go.opentelemetry.io/otel v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/otel/trace v1.22.0 // indirect + go.opentelemetry.io/collector/featuregate v1.3.0 // indirect + go.opentelemetry.io/collector/pdata v1.3.0 // indirect + go.opentelemetry.io/collector/semconv v0.96.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.21.0 // indirect - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/grpc v1.61.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect + google.golang.org/grpc v1.62.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apimachinery v0.28.6 // indirect - k8s.io/client-go v0.28.6 // indirect + k8s.io/apimachinery v0.29.2 // indirect + k8s.io/client-go v0.29.2 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect ) diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index 50db8d7934..bc5b2ddaa1 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -1,11 +1,11 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 h1:MxA59PGoCFb+vCwRQi3PhQEwHj4+r2dhuv9HG+vM7iM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= @@ -26,8 +26,8 @@ github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8V github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI= -github.com/aws/aws-sdk-go v1.50.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.50.32 h1:POt81DvegnpQKM4DMDLlHz1CO6OBnEoQ1gRhYFd7QRY= +github.com/aws/aws-sdk-go v1.50.32/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -37,8 +37,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -46,14 +46,14 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= -github.com/digitalocean/godo v1.108.0 h1:fWyMENvtxpCpva1UbKzOFnyAS04N1FNuBWWfPeTGquQ= -github.com/digitalocean/godo v1.108.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= +github.com/digitalocean/godo v1.109.0 h1:4W97RJLJSUQ3veRZDNbp1Ol3Rbn6Lmt9bKGvfqYI5SU= +github.com/digitalocean/godo v1.109.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= 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 v25.0.0+incompatible h1:g9b6wZTblhMgzOT2tspESstfw6ySZ9kdm94BLDKaZac= -github.com/docker/docker v25.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= +github.com/docker/docker v25.0.3+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= @@ -89,12 +89,12 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +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/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +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-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -135,16 +135,16 @@ 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/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk= github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= -github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8= +github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= +github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -165,8 +165,8 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= +github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702 h1:fI1LXuBaS1d9z1kmb++Og6YD8uMRwadXorCwE+xgOFA= +github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702/go.mod h1:z71gkJdrkAt/Rl6C7Q79VE7AwJ5lUF+M+fzFTyIHYB0= 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.6.0 h1:RJOA2hHZ7rD1pScA4O1NF6qhkHyUdbbxjHgFNot8928= @@ -194,8 +194,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -210,8 +210,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/linode/linodego v1.27.1 h1:KoQm5g2fppw8qIClJqUEL0yKH0+f+7te3Mewagb5QKE= -github.com/linode/linodego v1.27.1/go.mod h1:5oAsx+uinHtVo6U77nXXXtox7MWzUW6aEkTOKXxA9uo= +github.com/linode/linodego v1.29.0 h1:gDSQWAbKMAQX8db9FDCXHhodQPrJmLcmthjx6m+PyV4= +github.com/linode/linodego v1.29.0/go.mod h1:3k6WvCM10gillgYcnoLqIL23ST27BD9HhMsCJWb3Bpk= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -279,12 +279,12 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.50.1 h1:N2L+DYrxqPh4WZStU+o1p/gQlBaqFbcLBTjlp3vpdXw= -github.com/prometheus/prometheus v0.50.1/go.mod h1:FvE8dtQ1Ww63IlyKBn1V4s+zMwF9kHkVNkQBR1pM4CU= +github.com/prometheus/prometheus v0.51.1 h1:V2e7x2oiUC0Megp26+xjffxBf9EGkyP1iQuGd4VjUSU= +github.com/prometheus/prometheus v0.51.1/go.mod h1:yv4MwOn3yHMQ6MZGHPg/U7Fcyqf+rxqiZfSur6myVtc= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22 h1:wJrcTdddKOI8TFxs8cemnhKP2EmKy3yfUKHj3ZdfzYo= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.22/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 h1:/8rfZAdFfafRXOgz+ZpMZZWZ5pYggCY9t7e/BvjaBHM= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -307,20 +307,20 @@ github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtX github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/collector/featuregate v1.0.1 h1:ok//hLSXttBbyu4sSV1pTx1nKdr5udSmrWy5sFMIIbM= -go.opentelemetry.io/collector/featuregate v1.0.1/go.mod h1:QQXjP4etmJQhkQ20j4P/rapWuItYxoFozg/iIwuKnYg= -go.opentelemetry.io/collector/pdata v1.0.1 h1:dGX2h7maA6zHbl5D3AsMnF1c3Nn+3EUftbVCLzeyNvA= -go.opentelemetry.io/collector/pdata v1.0.1/go.mod h1:jutXeu0QOXYY8wcZ/hege+YAnSBP3+jpTqYU1+JTI5Y= -go.opentelemetry.io/collector/semconv v0.93.0 h1:eBlMcVNTwYYsVdAsCVDs4wvVYs75K1xcIDpqj16PG4c= -go.opentelemetry.io/collector/semconv v0.93.0/go.mod h1:gZ0uzkXsN+J5NpiRcdp9xOhNGQDDui8Y62p15sKrlzo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.opentelemetry.io/collector/featuregate v1.3.0 h1:nrFSx+zfjdisjE9oCx25Aep3nJ9RaUjeE1qFL6eovoU= +go.opentelemetry.io/collector/featuregate v1.3.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A= +go.opentelemetry.io/collector/pdata v1.3.0 h1:JRYN7tVHYFwmtQhIYbxWeiKSa2L1nCohyAs8sYqKFZo= +go.opentelemetry.io/collector/pdata v1.3.0/go.mod h1:t7W0Undtes53HODPdSujPLTnfSR5fzT+WpL+RTaaayo= +go.opentelemetry.io/collector/semconv v0.96.0 h1:DrZy8BpzJDnN2zFxXRj6BhfGYxNlqpFHBqyuS9fVHRY= +go.opentelemetry.io/collector/semconv v0.96.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= 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/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -339,8 +339,8 @@ golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/i golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -410,8 +410,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -420,14 +420,13 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= @@ -458,12 +457,12 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.6 h1:yy6u9CuIhmg55YvF/BavPBBXB+5QicB64njJXxVnzLo= -k8s.io/api v0.28.6/go.mod h1:AM6Ys6g9MY3dl/XNaNfg/GePI0FT7WBGu8efU/lirAo= -k8s.io/apimachinery v0.28.6 h1:RsTeR4z6S07srPg6XYrwXpTJVMXsjPXn0ODakMytSW0= -k8s.io/apimachinery v0.28.6/go.mod h1:QFNX/kCl/EMT2WTSz8k4WLCv2XnkOLMaL8GAVRMdpsA= -k8s.io/client-go v0.28.6 h1:Gge6ziyIdafRchfoBKcpaARuz7jfrK1R1azuwORIsQI= -k8s.io/client-go v0.28.6/go.mod h1:+nu0Yp21Oeo/cBCsprNVXB2BfJTV51lFfe5tXl2rUL8= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= +k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= From 2e6c1c35a4dfe63350044713107dd0f4c2fcc433 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 23:37:04 +0000 Subject: [PATCH 205/253] build(deps): bump the go-opentelemetry-io group with 3 updates Bumps the go-opentelemetry-io group with 3 updates: [go.opentelemetry.io/collector/featuregate](https://github.com/open-telemetry/opentelemetry-collector), [go.opentelemetry.io/collector/pdata](https://github.com/open-telemetry/opentelemetry-collector) and [go.opentelemetry.io/collector/semconv](https://github.com/open-telemetry/opentelemetry-collector). Updates `go.opentelemetry.io/collector/featuregate` from 1.3.0 to 1.4.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-collector/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CHANGELOG-API.md) - [Commits](https://github.com/open-telemetry/opentelemetry-collector/compare/pdata/v1.3.0...pdata/v1.4.0) Updates `go.opentelemetry.io/collector/pdata` from 1.3.0 to 1.4.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-collector/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CHANGELOG-API.md) - [Commits](https://github.com/open-telemetry/opentelemetry-collector/compare/pdata/v1.3.0...pdata/v1.4.0) Updates `go.opentelemetry.io/collector/semconv` from 0.96.0 to 0.97.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-collector/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CHANGELOG-API.md) - [Commits](https://github.com/open-telemetry/opentelemetry-collector/compare/v0.96.0...v0.97.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/collector/featuregate dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/collector/pdata dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io - dependency-name: go.opentelemetry.io/collector/semconv dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-opentelemetry-io ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 5ea1124fa7..8e9824b49d 100644 --- a/go.mod +++ b/go.mod @@ -60,9 +60,9 @@ require ( github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c github.com/stretchr/testify v1.9.0 github.com/vultr/govultr/v2 v2.17.2 - go.opentelemetry.io/collector/featuregate v1.3.0 - go.opentelemetry.io/collector/pdata v1.3.0 - go.opentelemetry.io/collector/semconv v0.96.0 + go.opentelemetry.io/collector/featuregate v1.4.0 + go.opentelemetry.io/collector/pdata v1.4.0 + go.opentelemetry.io/collector/semconv v0.97.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 go.opentelemetry.io/otel v1.24.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 diff --git a/go.sum b/go.sum index 1876425ea5..135e3afafc 100644 --- a/go.sum +++ b/go.sum @@ -720,12 +720,12 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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/featuregate v1.3.0 h1:nrFSx+zfjdisjE9oCx25Aep3nJ9RaUjeE1qFL6eovoU= -go.opentelemetry.io/collector/featuregate v1.3.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A= -go.opentelemetry.io/collector/pdata v1.3.0 h1:JRYN7tVHYFwmtQhIYbxWeiKSa2L1nCohyAs8sYqKFZo= -go.opentelemetry.io/collector/pdata v1.3.0/go.mod h1:t7W0Undtes53HODPdSujPLTnfSR5fzT+WpL+RTaaayo= -go.opentelemetry.io/collector/semconv v0.96.0 h1:DrZy8BpzJDnN2zFxXRj6BhfGYxNlqpFHBqyuS9fVHRY= -go.opentelemetry.io/collector/semconv v0.96.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs= +go.opentelemetry.io/collector/featuregate v1.4.0 h1:RWE9M659C9iuUQc4GzBsndkGHG1jIzIY+nZJWvcKy1M= +go.opentelemetry.io/collector/featuregate v1.4.0/go.mod h1:w7nUODKxEi3FLf1HslCiE6YWtMtOOrMnSwsDam8Mg9w= +go.opentelemetry.io/collector/pdata v1.4.0 h1:cA6Pr7Z2V7mE+i7FmYpavX7nefzd6H4CICgW0T9aJX0= +go.opentelemetry.io/collector/pdata v1.4.0/go.mod h1:0Ttp4wQinhV5oJTd9MjyvUegmZBO9O0nrlh/+EDLw+Q= +go.opentelemetry.io/collector/semconv v0.97.0 h1:iF3nTfThbiOwz7o5Pocn0dDnDoffd18ijDuf6Mwzi1s= +go.opentelemetry.io/collector/semconv v0.97.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= From 9b7de4778732ca2f2ab5028e9d1955109f440c4c Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Tue, 2 Apr 2024 18:45:46 +0200 Subject: [PATCH 206/253] Remove unused Dmn field on EvalNodeHelper (#13877) https://github.com/prometheus/prometheus/pull/13446 removed the last usage of this field, but didn't remove the field. Signed-off-by: Julius Volz --- promql/engine.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index cf60f477af..2f7dcb222e 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1081,8 +1081,6 @@ type EvalNodeHelper struct { Out Vector // Caches. - // label_*. - Dmn map[uint64]labels.Labels // funcHistogramQuantile for classic histograms. signatureToMetricWithBuckets map[string]*metricWithBuckets From db64d2dcdc09f474b158c341f43468b67686b81a Mon Sep 17 00:00:00 2001 From: Arthur Silva Sens Date: Tue, 2 Apr 2024 19:13:39 -0300 Subject: [PATCH 207/253] Update documentation about existing feature-flags Signed-off-by: Arthur Silva Sens --- cmd/prometheus/main.go | 2 +- docs/command-line/prometheus.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/prometheus/main.go b/cmd/prometheus/main.go index f64c00e824..0e15d5ca5f 100644 --- a/cmd/prometheus/main.go +++ b/cmd/prometheus/main.go @@ -447,7 +447,7 @@ func main() { a.Flag("scrape.discovery-reload-interval", "Interval used by scrape manager to throttle target groups updates."). Hidden().Default("5s").SetValue(&cfg.scrape.DiscoveryReloadInterval) - a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: agent, auto-gomemlimit, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-at-modifier, promql-negative-offset, promql-per-step-stats, promql-experimental-functions, remote-write-receiver (DEPRECATED), extra-scrape-metrics, new-service-discovery-manager, auto-gomaxprocs, no-default-scrape-port, native-histograms, otlp-write-receiver. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details."). + a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: agent, auto-gomemlimit, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-per-step-stats, promql-experimental-functions, remote-write-receiver (DEPRECATED), extra-scrape-metrics, new-service-discovery-manager, auto-gomaxprocs, no-default-scrape-port, native-histograms, otlp-write-receiver, created-timestamp-zero-ingestion, concurrent-rule-eval. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details."). Default("").StringsVar(&cfg.featureList) promlogflag.AddFlags(a, &cfg.promlogConfig) diff --git a/docs/command-line/prometheus.md b/docs/command-line/prometheus.md index 2faea5b15e..93eaf251d0 100644 --- a/docs/command-line/prometheus.md +++ b/docs/command-line/prometheus.md @@ -54,7 +54,7 @@ The Prometheus monitoring server | --query.timeout | Maximum time a query may take before being aborted. Use with server mode only. | `2m` | | --query.max-concurrency | Maximum number of queries executed concurrently. Use with server mode only. | `20` | | --query.max-samples | Maximum number of samples a single query can load into memory. Note that queries will fail if they try to load more samples than this into memory, so this also limits the number of samples a query can return. Use with server mode only. | `50000000` | -| --enable-feature | Comma separated feature names to enable. Valid options: agent, auto-gomemlimit, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-at-modifier, promql-negative-offset, promql-per-step-stats, promql-experimental-functions, remote-write-receiver (DEPRECATED), extra-scrape-metrics, new-service-discovery-manager, auto-gomaxprocs, no-default-scrape-port, native-histograms, otlp-write-receiver. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | | +| --enable-feature | Comma separated feature names to enable. Valid options: agent, auto-gomemlimit, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-per-step-stats, promql-experimental-functions, remote-write-receiver (DEPRECATED), extra-scrape-metrics, new-service-discovery-manager, auto-gomaxprocs, no-default-scrape-port, native-histograms, otlp-write-receiver, created-timestamp-zero-ingestion, concurrent-rule-eval. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | | | --log.level | Only log messages with the given severity or above. One of: [debug, info, warn, error] | `info` | | --log.format | Output format of log messages. One of: [logfmt, json] | `logfmt` | From 812563408683d7c4e5048a6ebcda3d3eb802fe00 Mon Sep 17 00:00:00 2001 From: Nicolas Takashi Date: Wed, 3 Apr 2024 09:14:34 +0100 Subject: [PATCH 208/253] [refactor] moving mergedOOOChunks Iterator (#13881) Signed-off-by: Nicolas Takashi --- tsdb/head_read.go | 4 ---- tsdb/ooo_head_read.go | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tsdb/head_read.go b/tsdb/head_read.go index 0ad885da20..45bbc81f18 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -582,10 +582,6 @@ func (s *memSeries) oooMergedChunks(meta chunks.Meta, cdm *chunks.ChunkDiskMappe return mc, nil } -func (o mergedOOOChunks) Iterator(iterator chunkenc.Iterator) chunkenc.Iterator { - return storage.ChainSampleIteratorFromIterables(iterator, o.chunkIterables) -} - var _ chunkenc.Iterable = &boundedIterable{} // boundedIterable is an implementation of chunkenc.Iterable that uses a diff --git a/tsdb/ooo_head_read.go b/tsdb/ooo_head_read.go index 4985ebb987..ed0b3fd227 100644 --- a/tsdb/ooo_head_read.go +++ b/tsdb/ooo_head_read.go @@ -49,6 +49,10 @@ type mergedOOOChunks struct { chunkIterables []chunkenc.Iterable } +func (o mergedOOOChunks) Iterator(iterator chunkenc.Iterator) chunkenc.Iterator { + return storage.ChainSampleIteratorFromIterables(iterator, o.chunkIterables) +} + func NewOOOHeadIndexReader(head *Head, mint, maxt int64, lastGarbageCollectedMmapRef chunks.ChunkDiskMapperRef) *OOOHeadIndexReader { hr := &headIndexReader{ head: head, From cd72ebb05f79bdd4ddd96a65e3759e2310b173d8 Mon Sep 17 00:00:00 2001 From: Charles Korn Date: Wed, 3 Apr 2024 19:57:08 +1100 Subject: [PATCH 209/253] promql: include more details in error message when creating test query fails or an unexpected series is returned (#13847) * promql: include more details in error message when creating test query fails Signed-off-by: Charles Korn * Include more details when an unexpected metric is returned Signed-off-by: Charles Korn --------- Signed-off-by: Charles Korn --- promql/test.go | 14 +++++++++----- promql/test_test.go | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/promql/test.go b/promql/test.go index ba716d1eea..2a9a4a2b81 100644 --- a/promql/test.go +++ b/promql/test.go @@ -516,7 +516,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error { for _, s := range val { hash := s.Metric.Hash() if _, ok := ev.metrics[hash]; !ok { - return fmt.Errorf("unexpected metric %s in result", s.Metric) + return fmt.Errorf("unexpected metric %s in result, has %s", s.Metric, formatSeriesResult(s)) } seen[hash] = true exp := ev.expected[hash] @@ -581,7 +581,11 @@ func (ev *evalCmd) compareResult(result parser.Value) error { for pos, v := range val { fp := v.Metric.Hash() if _, ok := ev.metrics[fp]; !ok { - return fmt.Errorf("unexpected metric %s in result", v.Metric) + if v.H != nil { + return fmt.Errorf("unexpected metric %s in result, has value %v", v.Metric, v.H) + } + + return fmt.Errorf("unexpected metric %s in result, has value %v", v.Metric, v.F) } exp := ev.expected[fp] if ev.ordered && exp.pos != pos+1 { @@ -763,7 +767,7 @@ func (t *test) execEval(cmd *evalCmd, engine QueryEngine) error { func (t *test) execRangeEval(cmd *evalCmd, engine QueryEngine) error { q, err := engine.NewRangeQuery(t.context, t.storage, nil, cmd.expr, cmd.start, cmd.end, cmd.step) if err != nil { - return err + return fmt.Errorf("error creating range query for %q (line %d): %w", cmd.expr, cmd.line, err) } res := q.Exec(t.context) if res.Err != nil { @@ -794,7 +798,7 @@ func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error { for _, iq := range queries { q, err := engine.NewInstantQuery(t.context, t.storage, nil, iq.expr, iq.evalTime) if err != nil { - return err + return fmt.Errorf("error creating instant query for %q (line %d): %w", cmd.expr, cmd.line, err) } defer q.Close() res := q.Exec(t.context) @@ -816,7 +820,7 @@ func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error { // by checking against the middle step. q, err = engine.NewRangeQuery(t.context, t.storage, nil, iq.expr, iq.evalTime.Add(-time.Minute), iq.evalTime.Add(time.Minute), time.Minute) if err != nil { - return err + return fmt.Errorf("error creating range query for %q (line %d): %w", cmd.expr, cmd.line, err) } rangeRes := q.Exec(t.context) if rangeRes.Err != nil { diff --git a/promql/test_test.go b/promql/test_test.go index 0130a789d7..a5b24ac698 100644 --- a/promql/test_test.go +++ b/promql/test_test.go @@ -224,12 +224,21 @@ eval instant at 0 testmetric `, expectedError: `error in eval testmetric (line 5): expected float value 2.000000 for {__name__="testmetric"} but got histogram {{}}`, }, - "instant query, but result has an unexpected series": { + "instant query, but result has an unexpected series with a float value": { input: testData + ` eval instant at 5m sum by (group) (http_requests) {group="production"} 30 `, - expectedError: `error in eval sum by (group) (http_requests) (line 8): unexpected metric {group="canary"} in result`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): unexpected metric {group="canary"} in result, has value 70`, + }, + "instant query, but result has an unexpected series with a histogram value": { + input: ` +load 5m + testmetric {{}} + +eval instant at 5m testmetric +`, + expectedError: `error in eval testmetric (line 5): unexpected metric {__name__="testmetric"} in result, has value {count:0, sum:0}`, }, "instant query, but result is missing a series": { input: testData + ` @@ -279,7 +288,7 @@ eval_ordered instant at 50m sort(http_requests) http_requests{group="production", instance="1", job="api-server"} 200 http_requests{group="canary", instance="0", job="api-server"} 300 `, - expectedError: `error in eval sort(http_requests) (line 8): unexpected metric {__name__="http_requests", group="canary", instance="1", job="api-server"} in result`, + expectedError: `error in eval sort(http_requests) (line 8): unexpected metric {__name__="http_requests", group="canary", instance="1", job="api-server"} in result, has value 400`, }, "instant query with invalid timestamp": { input: `eval instant at abc123 vector(0)`, @@ -350,7 +359,7 @@ eval range from 0 to 10m step 5m sum by (group) (http_requests) eval range from 0 to 10m step 5m sum by (group) (http_requests) {group="production"} 0 30 60 `, - expectedError: `error in eval sum by (group) (http_requests) (line 8): unexpected metric {group="canary"} in result`, + expectedError: `error in eval sum by (group) (http_requests) (line 8): unexpected metric {group="canary"} in result, has 3 float points [0 @[0] 70 @[300000] 140 @[600000]] and 0 histogram points []`, }, "range query, but result is missing a series": { input: testData + ` From 7c2852145153026ca6adbe9280b64fd35c91ad39 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 3 Apr 2024 10:10:35 +0100 Subject: [PATCH 210/253] [TESTS] Truncate some long test names, for readability The strings produced by these tests can run to thousands of characters, which makes test logs difficult to read. Signed-off-by: Bryan Boreham --- model/labels/regexp_test.go | 10 +++++++++- promql/parser/parse_test.go | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/model/labels/regexp_test.go b/model/labels/regexp_test.go index ac48bdc5b5..3a15b52b40 100644 --- a/model/labels/regexp_test.go +++ b/model/labels/regexp_test.go @@ -100,7 +100,7 @@ func TestFastRegexMatcher_MatchString(t *testing.T) { r := r for _, v := range testValues { v := v - t.Run(r+` on "`+v+`"`, func(t *testing.T) { + t.Run(readable(r)+` on "`+readable(v)+`"`, func(t *testing.T) { t.Parallel() m, err := NewFastRegexMatcher(r) require.NoError(t, err) @@ -111,6 +111,14 @@ func TestFastRegexMatcher_MatchString(t *testing.T) { } } +func readable(s string) string { + const maxReadableStringLen = 40 + if len(s) < maxReadableStringLen { + return s + } + return s[:maxReadableStringLen] + "..." +} + func TestOptimizeConcatRegex(t *testing.T) { cases := []struct { regex string diff --git a/promql/parser/parse_test.go b/promql/parser/parse_test.go index ff6e0b0828..c56d845947 100644 --- a/promql/parser/parse_test.go +++ b/promql/parser/parse_test.go @@ -3696,9 +3696,17 @@ func makeInt64Pointer(val int64) *int64 { return valp } +func readable(s string) string { + const maxReadableStringLen = 40 + if len(s) < maxReadableStringLen { + return s + } + return s[:maxReadableStringLen] + "..." +} + func TestParseExpressions(t *testing.T) { for _, test := range testExpr { - t.Run(test.input, func(t *testing.T) { + t.Run(readable(test.input), func(t *testing.T) { expr, err := ParseExpr(test.input) // Unexpected errors are always caused by a bug. From 0249e080b4e16b9fe78336195b03b08fec5e9e50 Mon Sep 17 00:00:00 2001 From: komisan19 <18901496+komisan19@users.noreply.github.com> Date: Thu, 4 Apr 2024 03:11:16 +0900 Subject: [PATCH 211/253] refactor: utilize standard functions max/min Signed-off-by: komisan19 <18901496+komisan19@users.noreply.github.com> --- cmd/promtool/rules.go | 14 -------------- tsdb/head_append.go | 7 ------- tsdb/wlog/live_reader.go | 7 ------- 3 files changed, 28 deletions(-) diff --git a/cmd/promtool/rules.go b/cmd/promtool/rules.go index d8d6bb83e1..5a18644842 100644 --- a/cmd/promtool/rules.go +++ b/cmd/promtool/rules.go @@ -234,17 +234,3 @@ func (m *multipleAppender) flushAndCommit(ctx context.Context) error { } return nil } - -func max(x, y int64) int64 { - if x > y { - return x - } - return y -} - -func min(x, y int64) int64 { - if x < y { - return x - } - return y -} diff --git a/tsdb/head_append.go b/tsdb/head_append.go index 58d24ceb94..23c2c0fbd7 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -198,13 +198,6 @@ func (h *Head) AppendableMinValidTime() (int64, bool) { return h.appendableMinValidTime(), true } -func max(a, b int64) int64 { - if a > b { - return a - } - return b -} - func (h *Head) getAppendBuffer() []record.RefSample { b := h.appendPool.Get() if b == nil { diff --git a/tsdb/wlog/live_reader.go b/tsdb/wlog/live_reader.go index 905bbf00d6..6eaef5f396 100644 --- a/tsdb/wlog/live_reader.go +++ b/tsdb/wlog/live_reader.go @@ -327,10 +327,3 @@ func (r *LiveReader) readRecord() ([]byte, int, error) { return rec, length + recordHeaderSize, nil } - -func min(i, j int) int { - if i < j { - return i - } - return j -} From 113938aeb894e60c5706ff9ca993344a990a96e7 Mon Sep 17 00:00:00 2001 From: Jonathan Halterman Date: Thu, 4 Apr 2024 05:26:13 -0700 Subject: [PATCH 212/253] Log out of order when writing a block (#13888) Signed-off-by: Jonathan Halterman --- tsdb/compact.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tsdb/compact.go b/tsdb/compact.go index 3d8d9130c4..b83649564d 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -575,6 +575,7 @@ func (c *LeveledCompactor) Write(dest string, b BlockReader, mint, maxt int64, p "maxt", meta.MaxTime, "ulid", meta.ULID, "duration", time.Since(start), + "ooo", meta.Compaction.FromOutOfOrder(), ) return uid, nil } From 38b75bc0d70418945fb58e4ad7bf55f3b9c8ffe2 Mon Sep 17 00:00:00 2001 From: dandrucz <161746538+dandrucz@users.noreply.github.com> Date: Fri, 5 Apr 2024 04:31:59 -0400 Subject: [PATCH 213/253] Linode IPv6 Range support, Optional region filtering, Missing fields in Documentation fixed (#13774) * Add support for discovering Linode IPv6 ranges associated with linodes. * Add optional but recommended region filtering (faster queries, more relevant information). * Added missing fields in configuration.md, updated linode test cases. * Convert to TableDrivenTests as per tjhop request. Signed-off-by: David Andruczyk --- discovery/linode/linode.go | 51 +- discovery/linode/linode_test.go | 367 +++++++++------ discovery/linode/mock_test.go | 439 ++---------------- .../ca-central/v4/account/events.json | 6 + .../ca-central/v4/linode/instances.json | 49 ++ .../ca-central/v4/networking/ips.json | 29 ++ .../ca-central/v4/networking/ipv6/ranges.json | 13 + .../no_region_filter/v4/account/events.json | 6 + .../no_region_filter/v4/linode/instances.json | 180 +++++++ .../no_region_filter/v4/networking/ips.json | 150 ++++++ .../v4/networking/ipv6/ranges.json | 19 + .../testdata/us-east/v4/account/events.json | 6 + .../testdata/us-east/v4/linode/instances.json | 97 ++++ .../testdata/us-east/v4/networking/ips.json | 106 +++++ .../us-east/v4/networking/ipv6/ranges.json | 13 + docs/configuration/configuration.md | 8 + documentation/examples/prometheus-linode.yml | 1 + 17 files changed, 982 insertions(+), 558 deletions(-) create mode 100644 discovery/linode/testdata/ca-central/v4/account/events.json create mode 100644 discovery/linode/testdata/ca-central/v4/linode/instances.json create mode 100644 discovery/linode/testdata/ca-central/v4/networking/ips.json create mode 100644 discovery/linode/testdata/ca-central/v4/networking/ipv6/ranges.json create mode 100644 discovery/linode/testdata/no_region_filter/v4/account/events.json create mode 100644 discovery/linode/testdata/no_region_filter/v4/linode/instances.json create mode 100644 discovery/linode/testdata/no_region_filter/v4/networking/ips.json create mode 100644 discovery/linode/testdata/no_region_filter/v4/networking/ipv6/ranges.json create mode 100644 discovery/linode/testdata/us-east/v4/account/events.json create mode 100644 discovery/linode/testdata/us-east/v4/linode/instances.json create mode 100644 discovery/linode/testdata/us-east/v4/networking/ips.json create mode 100644 discovery/linode/testdata/us-east/v4/networking/ipv6/ranges.json diff --git a/discovery/linode/linode.go b/discovery/linode/linode.go index 94f0a63bbb..2a5475b854 100644 --- a/discovery/linode/linode.go +++ b/discovery/linode/linode.go @@ -59,17 +59,22 @@ const ( linodeLabelSpecsVCPUs = linodeLabel + "specs_vcpus" linodeLabelSpecsTransferBytes = linodeLabel + "specs_transfer_bytes" linodeLabelExtraIPs = linodeLabel + "extra_ips" + linodeLabelIPv6Ranges = linodeLabel + "ipv6_ranges" // This is our events filter; when polling for changes, we care only about // events since our last refresh. - // Docs: https://www.linode.com/docs/api/account/#events-list + // Docs: https://www.linode.com/docs/api/account/#events-list. filterTemplate = `{"created": {"+gte": "%s"}}` + + // Optional region filtering. + regionFilterTemplate = `{"region": "%s"}` ) // DefaultSDConfig is the default Linode SD configuration. var DefaultSDConfig = SDConfig{ TagSeparator: ",", Port: 80, + Region: "", RefreshInterval: model.Duration(60 * time.Second), HTTPClientConfig: config.DefaultHTTPClientConfig, } @@ -85,6 +90,7 @@ type SDConfig struct { RefreshInterval model.Duration `yaml:"refresh_interval"` Port int `yaml:"port"` TagSeparator string `yaml:"tag_separator,omitempty"` + Region string `yaml:"region,omitempty"` } // NewDiscovererMetrics implements discovery.Config. @@ -122,6 +128,7 @@ type Discovery struct { *refresh.Discovery client *linodego.Client port int + region string tagSeparator string lastRefreshTimestamp time.Time pollCount int @@ -139,6 +146,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger, metrics discovery.Discovere d := &Discovery{ port: conf.Port, + region: conf.Region, tagSeparator: conf.TagSeparator, pollCount: 0, lastRefreshTimestamp: time.Now().UTC(), @@ -224,16 +232,31 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro tg := &targetgroup.Group{ Source: "Linode", } + opts := linodego.ListOptions{ + PageSize: 500, + } + + // If region filter provided, use it to constrain results. + if d.region != "" { + opts.Filter = fmt.Sprintf(regionFilterTemplate, d.region) + } // Gather all linode instances. - instances, err := d.client.ListInstances(ctx, &linodego.ListOptions{PageSize: 500}) + instances, err := d.client.ListInstances(ctx, &opts) if err != nil { d.metrics.failuresCount.Inc() return nil, err } // Gather detailed IP address info for all IPs on all linode instances. - detailedIPs, err := d.client.ListIPAddresses(ctx, &linodego.ListOptions{PageSize: 500}) + detailedIPs, err := d.client.ListIPAddresses(ctx, &opts) + if err != nil { + d.metrics.failuresCount.Inc() + return nil, err + } + + // Gather detailed IPv6 Range info for all linode instances. + ipv6RangeList, err := d.client.ListIPv6Ranges(ctx, &opts) if err != nil { d.metrics.failuresCount.Inc() return nil, err @@ -248,7 +271,7 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro privateIPv4, publicIPv4, publicIPv6 string privateIPv4RDNS, publicIPv4RDNS, publicIPv6RDNS string backupsStatus string - extraIPs []string + extraIPs, ipv6Ranges []string ) for _, ip := range instance.IPv4 { @@ -276,17 +299,23 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro } if instance.IPv6 != "" { + slaac := strings.Split(instance.IPv6, "/")[0] for _, detailedIP := range detailedIPs { - if detailedIP.Address != strings.Split(instance.IPv6, "/")[0] { + if detailedIP.Address != slaac { continue } - publicIPv6 = detailedIP.Address if detailedIP.RDNS != "" && detailedIP.RDNS != "null" { publicIPv6RDNS = detailedIP.RDNS } } + for _, ipv6Range := range ipv6RangeList { + if ipv6Range.RouteTarget != slaac { + continue + } + ipv6Ranges = append(ipv6Ranges, fmt.Sprintf("%s/%d", ipv6Range.Range, ipv6Range.Prefix)) + } } if instance.Backups.Enabled { @@ -330,12 +359,20 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro if len(extraIPs) > 0 { // This instance has more than one of at least one type of IP address (public, private, - // IPv4, IPv6, etc. We provide those extra IPs found here just like we do for instance + // IPv4,etc. We provide those extra IPs found here just like we do for instance // tags, we surround a separated list with the tagSeparator config. ips := d.tagSeparator + strings.Join(extraIPs, d.tagSeparator) + d.tagSeparator labels[linodeLabelExtraIPs] = model.LabelValue(ips) } + if len(ipv6Ranges) > 0 { + // This instance has more than one IPv6 Ranges routed to it we provide these + // Ranges found here just like we do for instance tags, we surround a separated + // list with the tagSeparator config. + ips := d.tagSeparator + strings.Join(ipv6Ranges, d.tagSeparator) + d.tagSeparator + labels[linodeLabelIPv6Ranges] = model.LabelValue(ips) + } + tg.Targets = append(tg.Targets, labels) } return []*targetgroup.Group{tg}, nil diff --git a/discovery/linode/linode_test.go b/discovery/linode/linode_test.go index a6a16d82aa..3c10650653 100644 --- a/discovery/linode/linode_test.go +++ b/discovery/linode/linode_test.go @@ -28,159 +28,236 @@ import ( "github.com/prometheus/prometheus/discovery" ) -type LinodeSDTestSuite struct { - Mock *SDMock -} - -func (s *LinodeSDTestSuite) TearDownSuite() { - s.Mock.ShutdownServer() -} - -func (s *LinodeSDTestSuite) SetupTest(t *testing.T) { - s.Mock = NewSDMock(t) - s.Mock.Setup() - - s.Mock.HandleLinodeInstancesList() - s.Mock.HandleLinodeNeworkingIPs() - s.Mock.HandleLinodeAccountEvents() -} - func TestLinodeSDRefresh(t *testing.T) { - sdmock := &LinodeSDTestSuite{} - sdmock.SetupTest(t) - t.Cleanup(sdmock.TearDownSuite) + sdmock := NewSDMock(t) + sdmock.Setup() - cfg := DefaultSDConfig - cfg.HTTPClientConfig.Authorization = &config.Authorization{ - Credentials: tokenID, - Type: "Bearer", + tests := map[string]struct { + region string + targetCount int + want []model.LabelSet + }{ + "no_region": {region: "", targetCount: 4, want: []model.LabelSet{ + { + "__address__": model.LabelValue("45.33.82.151:80"), + "__meta_linode_instance_id": model.LabelValue("26838044"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-1"), + "__meta_linode_image": model.LabelValue("linode/arch"), + "__meta_linode_private_ipv4": model.LabelValue("192.168.170.51"), + "__meta_linode_public_ipv4": model.LabelValue("45.33.82.151"), + "__meta_linode_public_ipv6": model.LabelValue("2600:3c03::f03c:92ff:fe1a:1382"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li1028-151.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("us-east"), + "__meta_linode_type": model.LabelValue("g6-standard-2"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("85899345920"), + "__meta_linode_specs_memory_bytes": model.LabelValue("4294967296"), + "__meta_linode_specs_vcpus": model.LabelValue("2"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("4194304000"), + "__meta_linode_extra_ips": model.LabelValue(",96.126.108.16,192.168.201.25,"), + }, + { + "__address__": model.LabelValue("139.162.196.43:80"), + "__meta_linode_instance_id": model.LabelValue("26848419"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-2"), + "__meta_linode_image": model.LabelValue("linode/debian10"), + "__meta_linode_private_ipv4": model.LabelValue(""), + "__meta_linode_public_ipv4": model.LabelValue("139.162.196.43"), + "__meta_linode_public_ipv6": model.LabelValue("2a01:7e00::f03c:92ff:fe1a:9976"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li1359-43.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("eu-west"), + "__meta_linode_type": model.LabelValue("g6-standard-2"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("85899345920"), + "__meta_linode_specs_memory_bytes": model.LabelValue("4294967296"), + "__meta_linode_specs_vcpus": model.LabelValue("2"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("4194304000"), + }, + { + "__address__": model.LabelValue("192.53.120.25:80"), + "__meta_linode_instance_id": model.LabelValue("26837938"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-3"), + "__meta_linode_image": model.LabelValue("linode/ubuntu20.04"), + "__meta_linode_private_ipv4": model.LabelValue(""), + "__meta_linode_public_ipv4": model.LabelValue("192.53.120.25"), + "__meta_linode_public_ipv6": model.LabelValue("2600:3c04::f03c:92ff:fe1a:fb68"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li2216-25.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("ca-central"), + "__meta_linode_type": model.LabelValue("g6-standard-1"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("53687091200"), + "__meta_linode_specs_memory_bytes": model.LabelValue("2147483648"), + "__meta_linode_specs_vcpus": model.LabelValue("1"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("2097152000"), + "__meta_linode_ipv6_ranges": model.LabelValue(",2600:3c04:e001:456::/64,"), + }, + { + "__address__": model.LabelValue("66.228.47.103:80"), + "__meta_linode_instance_id": model.LabelValue("26837992"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-4"), + "__meta_linode_image": model.LabelValue("linode/ubuntu20.04"), + "__meta_linode_private_ipv4": model.LabelValue("192.168.148.94"), + "__meta_linode_public_ipv4": model.LabelValue("66.228.47.103"), + "__meta_linode_public_ipv6": model.LabelValue("2600:3c03::f03c:92ff:fe1a:fb4c"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li328-103.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("us-east"), + "__meta_linode_type": model.LabelValue("g6-nanode-1"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("26843545600"), + "__meta_linode_specs_memory_bytes": model.LabelValue("1073741824"), + "__meta_linode_specs_vcpus": model.LabelValue("1"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("1048576000"), + "__meta_linode_extra_ips": model.LabelValue(",172.104.18.104,"), + "__meta_linode_ipv6_ranges": model.LabelValue(",2600:3c03:e000:123::/64,"), + }, + }}, + "us-east": {region: "us-east", targetCount: 2, want: []model.LabelSet{ + { + "__address__": model.LabelValue("45.33.82.151:80"), + "__meta_linode_instance_id": model.LabelValue("26838044"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-1"), + "__meta_linode_image": model.LabelValue("linode/arch"), + "__meta_linode_private_ipv4": model.LabelValue("192.168.170.51"), + "__meta_linode_public_ipv4": model.LabelValue("45.33.82.151"), + "__meta_linode_public_ipv6": model.LabelValue("2600:3c03::f03c:92ff:fe1a:1382"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li1028-151.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("us-east"), + "__meta_linode_type": model.LabelValue("g6-standard-2"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("85899345920"), + "__meta_linode_specs_memory_bytes": model.LabelValue("4294967296"), + "__meta_linode_specs_vcpus": model.LabelValue("2"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("4194304000"), + "__meta_linode_extra_ips": model.LabelValue(",96.126.108.16,192.168.201.25,"), + }, + { + "__address__": model.LabelValue("66.228.47.103:80"), + "__meta_linode_instance_id": model.LabelValue("26837992"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-4"), + "__meta_linode_image": model.LabelValue("linode/ubuntu20.04"), + "__meta_linode_private_ipv4": model.LabelValue("192.168.148.94"), + "__meta_linode_public_ipv4": model.LabelValue("66.228.47.103"), + "__meta_linode_public_ipv6": model.LabelValue("2600:3c03::f03c:92ff:fe1a:fb4c"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li328-103.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("us-east"), + "__meta_linode_type": model.LabelValue("g6-nanode-1"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("26843545600"), + "__meta_linode_specs_memory_bytes": model.LabelValue("1073741824"), + "__meta_linode_specs_vcpus": model.LabelValue("1"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("1048576000"), + "__meta_linode_extra_ips": model.LabelValue(",172.104.18.104,"), + "__meta_linode_ipv6_ranges": model.LabelValue(",2600:3c03:e000:123::/64,"), + }, + }}, + "us-central": {region: "ca-central", targetCount: 1, want: []model.LabelSet{ + { + "__address__": model.LabelValue("192.53.120.25:80"), + "__meta_linode_instance_id": model.LabelValue("26837938"), + "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-3"), + "__meta_linode_image": model.LabelValue("linode/ubuntu20.04"), + "__meta_linode_private_ipv4": model.LabelValue(""), + "__meta_linode_public_ipv4": model.LabelValue("192.53.120.25"), + "__meta_linode_public_ipv6": model.LabelValue("2600:3c04::f03c:92ff:fe1a:fb68"), + "__meta_linode_private_ipv4_rdns": model.LabelValue(""), + "__meta_linode_public_ipv4_rdns": model.LabelValue("li2216-25.members.linode.com"), + "__meta_linode_public_ipv6_rdns": model.LabelValue(""), + "__meta_linode_region": model.LabelValue("ca-central"), + "__meta_linode_type": model.LabelValue("g6-standard-1"), + "__meta_linode_status": model.LabelValue("running"), + "__meta_linode_tags": model.LabelValue(",monitoring,"), + "__meta_linode_group": model.LabelValue(""), + "__meta_linode_gpus": model.LabelValue("0"), + "__meta_linode_hypervisor": model.LabelValue("kvm"), + "__meta_linode_backups": model.LabelValue("disabled"), + "__meta_linode_specs_disk_bytes": model.LabelValue("53687091200"), + "__meta_linode_specs_memory_bytes": model.LabelValue("2147483648"), + "__meta_linode_specs_vcpus": model.LabelValue("1"), + "__meta_linode_specs_transfer_bytes": model.LabelValue("2097152000"), + "__meta_linode_ipv6_ranges": model.LabelValue(",2600:3c04:e001:456::/64,"), + }, + }}, } - reg := prometheus.NewRegistry() - refreshMetrics := discovery.NewRefreshMetrics(reg) - metrics := cfg.NewDiscovererMetrics(reg, refreshMetrics) - require.NoError(t, metrics.Register()) - defer metrics.Unregister() - defer refreshMetrics.Unregister() + for _, tc := range tests { + cfg := DefaultSDConfig + if tc.region != "" { + cfg.Region = tc.region + } + cfg.HTTPClientConfig.Authorization = &config.Authorization{ + Credentials: tokenID, + Type: "Bearer", + } - d, err := NewDiscovery(&cfg, log.NewNopLogger(), metrics) - require.NoError(t, err) - endpoint, err := url.Parse(sdmock.Mock.Endpoint()) - require.NoError(t, err) - d.client.SetBaseURL(endpoint.String()) + reg := prometheus.NewRegistry() + refreshMetrics := discovery.NewRefreshMetrics(reg) + metrics := cfg.NewDiscovererMetrics(reg, refreshMetrics) + require.NoError(t, metrics.Register()) + defer metrics.Unregister() + defer refreshMetrics.Unregister() - tgs, err := d.refresh(context.Background()) - require.NoError(t, err) + d, err := NewDiscovery(&cfg, log.NewNopLogger(), metrics) + require.NoError(t, err) + endpoint, err := url.Parse(sdmock.Endpoint()) + require.NoError(t, err) + d.client.SetBaseURL(endpoint.String()) - require.Len(t, tgs, 1) + tgs, err := d.refresh(context.Background()) + require.NoError(t, err) - tg := tgs[0] - require.NotNil(t, tg) - require.NotNil(t, tg.Targets) - require.Len(t, tg.Targets, 4) + require.Len(t, tgs, 1) - for i, lbls := range []model.LabelSet{ - { - "__address__": model.LabelValue("45.33.82.151:80"), - "__meta_linode_instance_id": model.LabelValue("26838044"), - "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-1"), - "__meta_linode_image": model.LabelValue("linode/arch"), - "__meta_linode_private_ipv4": model.LabelValue("192.168.170.51"), - "__meta_linode_public_ipv4": model.LabelValue("45.33.82.151"), - "__meta_linode_public_ipv6": model.LabelValue("2600:3c03::f03c:92ff:fe1a:1382"), - "__meta_linode_private_ipv4_rdns": model.LabelValue(""), - "__meta_linode_public_ipv4_rdns": model.LabelValue("li1028-151.members.linode.com"), - "__meta_linode_public_ipv6_rdns": model.LabelValue(""), - "__meta_linode_region": model.LabelValue("us-east"), - "__meta_linode_type": model.LabelValue("g6-standard-2"), - "__meta_linode_status": model.LabelValue("running"), - "__meta_linode_tags": model.LabelValue(",monitoring,"), - "__meta_linode_group": model.LabelValue(""), - "__meta_linode_gpus": model.LabelValue("0"), - "__meta_linode_hypervisor": model.LabelValue("kvm"), - "__meta_linode_backups": model.LabelValue("disabled"), - "__meta_linode_specs_disk_bytes": model.LabelValue("85899345920"), - "__meta_linode_specs_memory_bytes": model.LabelValue("4294967296"), - "__meta_linode_specs_vcpus": model.LabelValue("2"), - "__meta_linode_specs_transfer_bytes": model.LabelValue("4194304000"), - "__meta_linode_extra_ips": model.LabelValue(",96.126.108.16,192.168.201.25,"), - }, - { - "__address__": model.LabelValue("139.162.196.43:80"), - "__meta_linode_instance_id": model.LabelValue("26848419"), - "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-2"), - "__meta_linode_image": model.LabelValue("linode/debian10"), - "__meta_linode_private_ipv4": model.LabelValue(""), - "__meta_linode_public_ipv4": model.LabelValue("139.162.196.43"), - "__meta_linode_public_ipv6": model.LabelValue("2a01:7e00::f03c:92ff:fe1a:9976"), - "__meta_linode_private_ipv4_rdns": model.LabelValue(""), - "__meta_linode_public_ipv4_rdns": model.LabelValue("li1359-43.members.linode.com"), - "__meta_linode_public_ipv6_rdns": model.LabelValue(""), - "__meta_linode_region": model.LabelValue("eu-west"), - "__meta_linode_type": model.LabelValue("g6-standard-2"), - "__meta_linode_status": model.LabelValue("running"), - "__meta_linode_tags": model.LabelValue(",monitoring,"), - "__meta_linode_group": model.LabelValue(""), - "__meta_linode_gpus": model.LabelValue("0"), - "__meta_linode_hypervisor": model.LabelValue("kvm"), - "__meta_linode_backups": model.LabelValue("disabled"), - "__meta_linode_specs_disk_bytes": model.LabelValue("85899345920"), - "__meta_linode_specs_memory_bytes": model.LabelValue("4294967296"), - "__meta_linode_specs_vcpus": model.LabelValue("2"), - "__meta_linode_specs_transfer_bytes": model.LabelValue("4194304000"), - }, - { - "__address__": model.LabelValue("192.53.120.25:80"), - "__meta_linode_instance_id": model.LabelValue("26837938"), - "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-3"), - "__meta_linode_image": model.LabelValue("linode/ubuntu20.04"), - "__meta_linode_private_ipv4": model.LabelValue(""), - "__meta_linode_public_ipv4": model.LabelValue("192.53.120.25"), - "__meta_linode_public_ipv6": model.LabelValue("2600:3c04::f03c:92ff:fe1a:fb68"), - "__meta_linode_private_ipv4_rdns": model.LabelValue(""), - "__meta_linode_public_ipv4_rdns": model.LabelValue("li2216-25.members.linode.com"), - "__meta_linode_public_ipv6_rdns": model.LabelValue(""), - "__meta_linode_region": model.LabelValue("ca-central"), - "__meta_linode_type": model.LabelValue("g6-standard-1"), - "__meta_linode_status": model.LabelValue("running"), - "__meta_linode_tags": model.LabelValue(",monitoring,"), - "__meta_linode_group": model.LabelValue(""), - "__meta_linode_gpus": model.LabelValue("0"), - "__meta_linode_hypervisor": model.LabelValue("kvm"), - "__meta_linode_backups": model.LabelValue("disabled"), - "__meta_linode_specs_disk_bytes": model.LabelValue("53687091200"), - "__meta_linode_specs_memory_bytes": model.LabelValue("2147483648"), - "__meta_linode_specs_vcpus": model.LabelValue("1"), - "__meta_linode_specs_transfer_bytes": model.LabelValue("2097152000"), - }, - { - "__address__": model.LabelValue("66.228.47.103:80"), - "__meta_linode_instance_id": model.LabelValue("26837992"), - "__meta_linode_instance_label": model.LabelValue("prometheus-linode-sd-exporter-4"), - "__meta_linode_image": model.LabelValue("linode/ubuntu20.04"), - "__meta_linode_private_ipv4": model.LabelValue("192.168.148.94"), - "__meta_linode_public_ipv4": model.LabelValue("66.228.47.103"), - "__meta_linode_public_ipv6": model.LabelValue("2600:3c03::f03c:92ff:fe1a:fb4c"), - "__meta_linode_private_ipv4_rdns": model.LabelValue(""), - "__meta_linode_public_ipv4_rdns": model.LabelValue("li328-103.members.linode.com"), - "__meta_linode_public_ipv6_rdns": model.LabelValue(""), - "__meta_linode_region": model.LabelValue("us-east"), - "__meta_linode_type": model.LabelValue("g6-nanode-1"), - "__meta_linode_status": model.LabelValue("running"), - "__meta_linode_tags": model.LabelValue(",monitoring,"), - "__meta_linode_group": model.LabelValue(""), - "__meta_linode_gpus": model.LabelValue("0"), - "__meta_linode_hypervisor": model.LabelValue("kvm"), - "__meta_linode_backups": model.LabelValue("disabled"), - "__meta_linode_specs_disk_bytes": model.LabelValue("26843545600"), - "__meta_linode_specs_memory_bytes": model.LabelValue("1073741824"), - "__meta_linode_specs_vcpus": model.LabelValue("1"), - "__meta_linode_specs_transfer_bytes": model.LabelValue("1048576000"), - "__meta_linode_extra_ips": model.LabelValue(",172.104.18.104,"), - }, - } { - t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) { - require.Equal(t, lbls, tg.Targets[i]) - }) + tg := tgs[0] + require.NotNil(t, tg) + require.NotNil(t, tg.Targets) + require.Len(t, tg.Targets, tc.targetCount) + + for i, lbls := range tc.want { + t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) { + require.Equal(t, lbls, tg.Targets[i]) + }) + } } } diff --git a/discovery/linode/mock_test.go b/discovery/linode/mock_test.go index ea0e8e0a8b..50f0572ecd 100644 --- a/discovery/linode/mock_test.go +++ b/discovery/linode/mock_test.go @@ -14,12 +14,17 @@ package linode import ( + "encoding/json" "fmt" "net/http" "net/http/httptest" + "os" + "path/filepath" "testing" ) +const tokenID = "7b2c56dd51edd90952c1b94c472b94b176f20c5c777e376849edd8ad1c6c03bb" + // SDMock is the interface for the Linode mock. type SDMock struct { t *testing.T @@ -43,412 +48,34 @@ func (m *SDMock) Endpoint() string { func (m *SDMock) Setup() { m.Mux = http.NewServeMux() m.Server = httptest.NewServer(m.Mux) + m.t.Cleanup(m.Server.Close) + m.SetupHandlers() } -// ShutdownServer creates the mock server. -func (m *SDMock) ShutdownServer() { - m.Server.Close() -} - -const tokenID = "7b2c56dd51edd90952c1b94c472b94b176f20c5c777e376849edd8ad1c6c03bb" - -// HandleLinodeInstancesList mocks linode instances list. -func (m *SDMock) HandleLinodeInstancesList() { - m.Mux.HandleFunc("/v4/linode/instances", func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) { - w.WriteHeader(http.StatusUnauthorized) - return - } - - w.Header().Set("content-type", "application/json; charset=utf-8") - w.WriteHeader(http.StatusOK) - - fmt.Fprint(w, ` -{ - "data": [ - { - "id": 26838044, - "label": "prometheus-linode-sd-exporter-1", - "group": "", - "status": "running", - "created": "2021-05-12T04:23:44", - "updated": "2021-05-12T04:23:44", - "type": "g6-standard-2", - "ipv4": [ - "45.33.82.151", - "96.126.108.16", - "192.168.170.51", - "192.168.201.25" - ], - "ipv6": "2600:3c03::f03c:92ff:fe1a:1382/128", - "image": "linode/arch", - "region": "us-east", - "specs": { - "disk": 81920, - "memory": 4096, - "vcpus": 2, - "gpus": 0, - "transfer": 4000 - }, - "alerts": { - "cpu": 180, - "network_in": 10, - "network_out": 10, - "transfer_quota": 80, - "io": 10000 - }, - "backups": { - "enabled": false, - "schedule": { - "day": null, - "window": null - }, - "last_successful": null - }, - "hypervisor": "kvm", - "watchdog_enabled": true, - "tags": [ - "monitoring" - ] - }, - { - "id": 26848419, - "label": "prometheus-linode-sd-exporter-2", - "group": "", - "status": "running", - "created": "2021-05-12T12:41:49", - "updated": "2021-05-12T12:41:49", - "type": "g6-standard-2", - "ipv4": [ - "139.162.196.43" - ], - "ipv6": "2a01:7e00::f03c:92ff:fe1a:9976/128", - "image": "linode/debian10", - "region": "eu-west", - "specs": { - "disk": 81920, - "memory": 4096, - "vcpus": 2, - "gpus": 0, - "transfer": 4000 - }, - "alerts": { - "cpu": 180, - "network_in": 10, - "network_out": 10, - "transfer_quota": 80, - "io": 10000 - }, - "backups": { - "enabled": false, - "schedule": { - "day": null, - "window": null - }, - "last_successful": null - }, - "hypervisor": "kvm", - "watchdog_enabled": true, - "tags": [ - "monitoring" - ] - }, - { - "id": 26837938, - "label": "prometheus-linode-sd-exporter-3", - "group": "", - "status": "running", - "created": "2021-05-12T04:20:11", - "updated": "2021-05-12T04:20:11", - "type": "g6-standard-1", - "ipv4": [ - "192.53.120.25" - ], - "ipv6": "2600:3c04::f03c:92ff:fe1a:fb68/128", - "image": "linode/ubuntu20.04", - "region": "ca-central", - "specs": { - "disk": 51200, - "memory": 2048, - "vcpus": 1, - "gpus": 0, - "transfer": 2000 - }, - "alerts": { - "cpu": 90, - "network_in": 10, - "network_out": 10, - "transfer_quota": 80, - "io": 10000 - }, - "backups": { - "enabled": false, - "schedule": { - "day": null, - "window": null - }, - "last_successful": null - }, - "hypervisor": "kvm", - "watchdog_enabled": true, - "tags": [ - "monitoring" - ] - }, - { - "id": 26837992, - "label": "prometheus-linode-sd-exporter-4", - "group": "", - "status": "running", - "created": "2021-05-12T04:22:06", - "updated": "2021-05-12T04:22:06", - "type": "g6-nanode-1", - "ipv4": [ - "66.228.47.103", - "172.104.18.104", - "192.168.148.94" - ], - "ipv6": "2600:3c03::f03c:92ff:fe1a:fb4c/128", - "image": "linode/ubuntu20.04", - "region": "us-east", - "specs": { - "disk": 25600, - "memory": 1024, - "vcpus": 1, - "gpus": 0, - "transfer": 1000 - }, - "alerts": { - "cpu": 90, - "network_in": 10, - "network_out": 10, - "transfer_quota": 80, - "io": 10000 - }, - "backups": { - "enabled": false, - "schedule": { - "day": null, - "window": null - }, - "last_successful": null - }, - "hypervisor": "kvm", - "watchdog_enabled": true, - "tags": [ - "monitoring" - ] - } - ], - "page": 1, - "pages": 1, - "results": 4 -}`, - ) - }) -} - -// HandleLinodeNeworkingIPs mocks linode networking ips endpoint. -func (m *SDMock) HandleLinodeNeworkingIPs() { - m.Mux.HandleFunc("/v4/networking/ips", func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) { - w.WriteHeader(http.StatusUnauthorized) - return - } - - w.Header().Set("content-type", "application/json; charset=utf-8") - w.WriteHeader(http.StatusOK) - - fmt.Fprint(w, ` -{ - "page": 1, - "pages": 1, - "results": 13, - "data": [ - { - "address": "192.53.120.25", - "gateway": "192.53.120.1", - "subnet_mask": "255.255.255.0", - "prefix": 24, - "type": "ipv4", - "public": true, - "rdns": "li2216-25.members.linode.com", - "linode_id": 26837938, - "region": "ca-central" - }, - { - "address": "66.228.47.103", - "gateway": "66.228.47.1", - "subnet_mask": "255.255.255.0", - "prefix": 24, - "type": "ipv4", - "public": true, - "rdns": "li328-103.members.linode.com", - "linode_id": 26837992, - "region": "us-east" - }, - { - "address": "172.104.18.104", - "gateway": "172.104.18.1", - "subnet_mask": "255.255.255.0", - "prefix": 24, - "type": "ipv4", - "public": true, - "rdns": "li1832-104.members.linode.com", - "linode_id": 26837992, - "region": "us-east" - }, - { - "address": "192.168.148.94", - "gateway": null, - "subnet_mask": "255.255.128.0", - "prefix": 17, - "type": "ipv4", - "public": false, - "rdns": null, - "linode_id": 26837992, - "region": "us-east" - }, - { - "address": "192.168.170.51", - "gateway": null, - "subnet_mask": "255.255.128.0", - "prefix": 17, - "type": "ipv4", - "public": false, - "rdns": null, - "linode_id": 26838044, - "region": "us-east" - }, - { - "address": "96.126.108.16", - "gateway": "96.126.108.1", - "subnet_mask": "255.255.255.0", - "prefix": 24, - "type": "ipv4", - "public": true, - "rdns": "li365-16.members.linode.com", - "linode_id": 26838044, - "region": "us-east" - }, - { - "address": "45.33.82.151", - "gateway": "45.33.82.1", - "subnet_mask": "255.255.255.0", - "prefix": 24, - "type": "ipv4", - "public": true, - "rdns": "li1028-151.members.linode.com", - "linode_id": 26838044, - "region": "us-east" - }, - { - "address": "192.168.201.25", - "gateway": null, - "subnet_mask": "255.255.128.0", - "prefix": 17, - "type": "ipv4", - "public": false, - "rdns": null, - "linode_id": 26838044, - "region": "us-east" - }, - { - "address": "139.162.196.43", - "gateway": "139.162.196.1", - "subnet_mask": "255.255.255.0", - "prefix": 24, - "type": "ipv4", - "public": true, - "rdns": "li1359-43.members.linode.com", - "linode_id": 26848419, - "region": "eu-west" - }, - { - "address": "2600:3c04::f03c:92ff:fe1a:fb68", - "gateway": "fe80::1", - "subnet_mask": "ffff:ffff:ffff:ffff::", - "prefix": 64, - "type": "ipv6", - "rdns": null, - "linode_id": 26837938, - "region": "ca-central", - "public": true - }, - { - "address": "2600:3c03::f03c:92ff:fe1a:fb4c", - "gateway": "fe80::1", - "subnet_mask": "ffff:ffff:ffff:ffff::", - "prefix": 64, - "type": "ipv6", - "rdns": null, - "linode_id": 26837992, - "region": "us-east", - "public": true - }, - { - "address": "2600:3c03::f03c:92ff:fe1a:1382", - "gateway": "fe80::1", - "subnet_mask": "ffff:ffff:ffff:ffff::", - "prefix": 64, - "type": "ipv6", - "rdns": null, - "linode_id": 26838044, - "region": "us-east", - "public": true - }, - { - "address": "2a01:7e00::f03c:92ff:fe1a:9976", - "gateway": "fe80::1", - "subnet_mask": "ffff:ffff:ffff:ffff::", - "prefix": 64, - "type": "ipv6", - "rdns": null, - "linode_id": 26848419, - "region": "eu-west", - "public": true - } - ] -}`, - ) - }) -} - -// HandleLinodeAccountEvents mocks linode the account/events endpoint. -func (m *SDMock) HandleLinodeAccountEvents() { - m.Mux.HandleFunc("/v4/account/events", func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) { - w.WriteHeader(http.StatusUnauthorized) - return - } - - if r.Header.Get("X-Filter") == "" { - // This should never happen; if the client sends an events request without - // a filter, cause it to fail. The error below is not a real response from - // the API, but should aid in debugging failed tests. - w.WriteHeader(http.StatusBadRequest) - fmt.Fprint(w, ` -{ - "errors": [ - { - "reason": "Request missing expected X-Filter headers" - } - ] -}`, - ) - return - } - - w.Header().Set("content-type", "application/json; charset=utf-8") - w.WriteHeader(http.StatusOK) - - fmt.Fprint(w, ` -{ - "data": [], - "results": 0, - "pages": 1, - "page": 1 -}`, - ) - }) +// SetupHandlers for endpoints of interest. +func (m *SDMock) SetupHandlers() { + for _, handler := range []string{"/v4/account/events", "/v4/linode/instances", "/v4/networking/ips", "/v4/networking/ipv6/ranges"} { + m.Mux.HandleFunc(handler, func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) { + w.WriteHeader(http.StatusUnauthorized) + return + } + xFilter := struct { + Region string `json:"region"` + }{} + json.Unmarshal([]byte(r.Header.Get("X-Filter")), &xFilter) + + directory := "testdata/no_region_filter" + if xFilter.Region != "" { // Validate region filter matches test criteria. + directory = "testdata/" + xFilter.Region + } + if response, err := os.ReadFile(filepath.Join(directory, r.URL.Path+".json")); err == nil { + w.Header().Add("content-type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusOK) + w.Write(response) + return + } + w.WriteHeader(http.StatusInternalServerError) + }) + } } diff --git a/discovery/linode/testdata/ca-central/v4/account/events.json b/discovery/linode/testdata/ca-central/v4/account/events.json new file mode 100644 index 0000000000..ca302e4fd0 --- /dev/null +++ b/discovery/linode/testdata/ca-central/v4/account/events.json @@ -0,0 +1,6 @@ +{ + "data": [], + "results": 0, + "pages": 1, + "page": 1 +} diff --git a/discovery/linode/testdata/ca-central/v4/linode/instances.json b/discovery/linode/testdata/ca-central/v4/linode/instances.json new file mode 100644 index 0000000000..dfc1172477 --- /dev/null +++ b/discovery/linode/testdata/ca-central/v4/linode/instances.json @@ -0,0 +1,49 @@ +{ + "data": [ + { + "id": 26837938, + "label": "prometheus-linode-sd-exporter-3", + "group": "", + "status": "running", + "created": "2021-05-12T04:20:11", + "updated": "2021-05-12T04:20:11", + "type": "g6-standard-1", + "ipv4": [ + "192.53.120.25" + ], + "ipv6": "2600:3c04::f03c:92ff:fe1a:fb68/128", + "image": "linode/ubuntu20.04", + "region": "ca-central", + "specs": { + "disk": 51200, + "memory": 2048, + "vcpus": 1, + "gpus": 0, + "transfer": 2000 + }, + "alerts": { + "cpu": 90, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + } + ], + "page": 1, + "pages": 1, + "results": 1 +} diff --git a/discovery/linode/testdata/ca-central/v4/networking/ips.json b/discovery/linode/testdata/ca-central/v4/networking/ips.json new file mode 100644 index 0000000000..23d974a886 --- /dev/null +++ b/discovery/linode/testdata/ca-central/v4/networking/ips.json @@ -0,0 +1,29 @@ +{ + "page": 1, + "pages": 1, + "results": 2, + "data": [ + { + "address": "192.53.120.25", + "gateway": "192.53.120.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li2216-25.members.linode.com", + "linode_id": 26837938, + "region": "ca-central" + }, + { + "address": "2600:3c04::f03c:92ff:fe1a:fb68", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26837938, + "region": "ca-central", + "public": true + } + ] +} diff --git a/discovery/linode/testdata/ca-central/v4/networking/ipv6/ranges.json b/discovery/linode/testdata/ca-central/v4/networking/ipv6/ranges.json new file mode 100644 index 0000000000..442615cbbc --- /dev/null +++ b/discovery/linode/testdata/ca-central/v4/networking/ipv6/ranges.json @@ -0,0 +1,13 @@ +{ + "data": [ + { + "range": "2600:3c04:e001:456::", + "prefix": 64, + "region": "ca-central", + "route_target": "2600:3c04::f03c:92ff:fe1a:fb68" + } + ], + "page": 1, + "pages": 1, + "results": 1 +} diff --git a/discovery/linode/testdata/no_region_filter/v4/account/events.json b/discovery/linode/testdata/no_region_filter/v4/account/events.json new file mode 100644 index 0000000000..ca302e4fd0 --- /dev/null +++ b/discovery/linode/testdata/no_region_filter/v4/account/events.json @@ -0,0 +1,6 @@ +{ + "data": [], + "results": 0, + "pages": 1, + "page": 1 +} diff --git a/discovery/linode/testdata/no_region_filter/v4/linode/instances.json b/discovery/linode/testdata/no_region_filter/v4/linode/instances.json new file mode 100644 index 0000000000..25d5271d9c --- /dev/null +++ b/discovery/linode/testdata/no_region_filter/v4/linode/instances.json @@ -0,0 +1,180 @@ +{ + "data": [ + { + "id": 26838044, + "label": "prometheus-linode-sd-exporter-1", + "group": "", + "status": "running", + "created": "2021-05-12T04:23:44", + "updated": "2021-05-12T04:23:44", + "type": "g6-standard-2", + "ipv4": [ + "45.33.82.151", + "96.126.108.16", + "192.168.170.51", + "192.168.201.25" + ], + "ipv6": "2600:3c03::f03c:92ff:fe1a:1382/128", + "image": "linode/arch", + "region": "us-east", + "specs": { + "disk": 81920, + "memory": 4096, + "vcpus": 2, + "gpus": 0, + "transfer": 4000 + }, + "alerts": { + "cpu": 180, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + }, + { + "id": 26848419, + "label": "prometheus-linode-sd-exporter-2", + "group": "", + "status": "running", + "created": "2021-05-12T12:41:49", + "updated": "2021-05-12T12:41:49", + "type": "g6-standard-2", + "ipv4": [ + "139.162.196.43" + ], + "ipv6": "2a01:7e00::f03c:92ff:fe1a:9976/128", + "image": "linode/debian10", + "region": "eu-west", + "specs": { + "disk": 81920, + "memory": 4096, + "vcpus": 2, + "gpus": 0, + "transfer": 4000 + }, + "alerts": { + "cpu": 180, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + }, + { + "id": 26837938, + "label": "prometheus-linode-sd-exporter-3", + "group": "", + "status": "running", + "created": "2021-05-12T04:20:11", + "updated": "2021-05-12T04:20:11", + "type": "g6-standard-1", + "ipv4": [ + "192.53.120.25" + ], + "ipv6": "2600:3c04::f03c:92ff:fe1a:fb68/128", + "image": "linode/ubuntu20.04", + "region": "ca-central", + "specs": { + "disk": 51200, + "memory": 2048, + "vcpus": 1, + "gpus": 0, + "transfer": 2000 + }, + "alerts": { + "cpu": 90, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + }, + { + "id": 26837992, + "label": "prometheus-linode-sd-exporter-4", + "group": "", + "status": "running", + "created": "2021-05-12T04:22:06", + "updated": "2021-05-12T04:22:06", + "type": "g6-nanode-1", + "ipv4": [ + "66.228.47.103", + "172.104.18.104", + "192.168.148.94" + ], + "ipv6": "2600:3c03::f03c:92ff:fe1a:fb4c/128", + "image": "linode/ubuntu20.04", + "region": "us-east", + "specs": { + "disk": 25600, + "memory": 1024, + "vcpus": 1, + "gpus": 0, + "transfer": 1000 + }, + "alerts": { + "cpu": 90, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + } + ], + "page": 1, + "pages": 1, + "results": 4 +} diff --git a/discovery/linode/testdata/no_region_filter/v4/networking/ips.json b/discovery/linode/testdata/no_region_filter/v4/networking/ips.json new file mode 100644 index 0000000000..5173036f1c --- /dev/null +++ b/discovery/linode/testdata/no_region_filter/v4/networking/ips.json @@ -0,0 +1,150 @@ +{ + "page": 1, + "pages": 1, + "results": 13, + "data": [ + { + "address": "192.53.120.25", + "gateway": "192.53.120.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li2216-25.members.linode.com", + "linode_id": 26837938, + "region": "ca-central" + }, + { + "address": "66.228.47.103", + "gateway": "66.228.47.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li328-103.members.linode.com", + "linode_id": 26837992, + "region": "us-east" + }, + { + "address": "172.104.18.104", + "gateway": "172.104.18.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li1832-104.members.linode.com", + "linode_id": 26837992, + "region": "us-east" + }, + { + "address": "192.168.148.94", + "gateway": null, + "subnet_mask": "255.255.128.0", + "prefix": 17, + "type": "ipv4", + "public": false, + "rdns": null, + "linode_id": 26837992, + "region": "us-east" + }, + { + "address": "192.168.170.51", + "gateway": null, + "subnet_mask": "255.255.128.0", + "prefix": 17, + "type": "ipv4", + "public": false, + "rdns": null, + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "96.126.108.16", + "gateway": "96.126.108.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li365-16.members.linode.com", + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "45.33.82.151", + "gateway": "45.33.82.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li1028-151.members.linode.com", + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "192.168.201.25", + "gateway": null, + "subnet_mask": "255.255.128.0", + "prefix": 17, + "type": "ipv4", + "public": false, + "rdns": null, + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "139.162.196.43", + "gateway": "139.162.196.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li1359-43.members.linode.com", + "linode_id": 26848419, + "region": "eu-west" + }, + { + "address": "2600:3c04::f03c:92ff:fe1a:fb68", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26837938, + "region": "ca-central", + "public": true + }, + { + "address": "2600:3c03::f03c:92ff:fe1a:fb4c", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26837992, + "region": "us-east", + "public": true + }, + { + "address": "2600:3c03::f03c:92ff:fe1a:1382", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26838044, + "region": "us-east", + "public": true + }, + { + "address": "2a01:7e00::f03c:92ff:fe1a:9976", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26848419, + "region": "eu-west", + "public": true + } + ] +} diff --git a/discovery/linode/testdata/no_region_filter/v4/networking/ipv6/ranges.json b/discovery/linode/testdata/no_region_filter/v4/networking/ipv6/ranges.json new file mode 100644 index 0000000000..511a4d9a8c --- /dev/null +++ b/discovery/linode/testdata/no_region_filter/v4/networking/ipv6/ranges.json @@ -0,0 +1,19 @@ +{ + "data": [ + { + "range": "2600:3c03:e000:123::", + "prefix": 64, + "region": "us-east", + "route_target": "2600:3c03::f03c:92ff:fe1a:fb4c" + }, + { + "range": "2600:3c04:e001:456::", + "prefix": 64, + "region": "ca-central", + "route_target": "2600:3c04::f03c:92ff:fe1a:fb68" + } + ], + "page": 1, + "pages": 1, + "results": 2 +} diff --git a/discovery/linode/testdata/us-east/v4/account/events.json b/discovery/linode/testdata/us-east/v4/account/events.json new file mode 100644 index 0000000000..ca302e4fd0 --- /dev/null +++ b/discovery/linode/testdata/us-east/v4/account/events.json @@ -0,0 +1,6 @@ +{ + "data": [], + "results": 0, + "pages": 1, + "page": 1 +} diff --git a/discovery/linode/testdata/us-east/v4/linode/instances.json b/discovery/linode/testdata/us-east/v4/linode/instances.json new file mode 100644 index 0000000000..5e9a8f5abe --- /dev/null +++ b/discovery/linode/testdata/us-east/v4/linode/instances.json @@ -0,0 +1,97 @@ +{ + "data": [ + { + "id": 26838044, + "label": "prometheus-linode-sd-exporter-1", + "group": "", + "status": "running", + "created": "2021-05-12T04:23:44", + "updated": "2021-05-12T04:23:44", + "type": "g6-standard-2", + "ipv4": [ + "45.33.82.151", + "96.126.108.16", + "192.168.170.51", + "192.168.201.25" + ], + "ipv6": "2600:3c03::f03c:92ff:fe1a:1382/128", + "image": "linode/arch", + "region": "us-east", + "specs": { + "disk": 81920, + "memory": 4096, + "vcpus": 2, + "gpus": 0, + "transfer": 4000 + }, + "alerts": { + "cpu": 180, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + }, + { + "id": 26837992, + "label": "prometheus-linode-sd-exporter-4", + "group": "", + "status": "running", + "created": "2021-05-12T04:22:06", + "updated": "2021-05-12T04:22:06", + "type": "g6-nanode-1", + "ipv4": [ + "66.228.47.103", + "172.104.18.104", + "192.168.148.94" + ], + "ipv6": "2600:3c03::f03c:92ff:fe1a:fb4c/128", + "image": "linode/ubuntu20.04", + "region": "us-east", + "specs": { + "disk": 25600, + "memory": 1024, + "vcpus": 1, + "gpus": 0, + "transfer": 1000 + }, + "alerts": { + "cpu": 90, + "network_in": 10, + "network_out": 10, + "transfer_quota": 80, + "io": 10000 + }, + "backups": { + "enabled": false, + "schedule": { + "day": null, + "window": null + }, + "last_successful": null + }, + "hypervisor": "kvm", + "watchdog_enabled": true, + "tags": [ + "monitoring" + ] + } + ], + "page": 1, + "pages": 1, + "results": 2 +} + diff --git a/discovery/linode/testdata/us-east/v4/networking/ips.json b/discovery/linode/testdata/us-east/v4/networking/ips.json new file mode 100644 index 0000000000..388cf59659 --- /dev/null +++ b/discovery/linode/testdata/us-east/v4/networking/ips.json @@ -0,0 +1,106 @@ +{ + "page": 1, + "pages": 1, + "results": 9, + "data": [ + { + "address": "66.228.47.103", + "gateway": "66.228.47.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li328-103.members.linode.com", + "linode_id": 26837992, + "region": "us-east" + }, + { + "address": "172.104.18.104", + "gateway": "172.104.18.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li1832-104.members.linode.com", + "linode_id": 26837992, + "region": "us-east" + }, + { + "address": "192.168.148.94", + "gateway": null, + "subnet_mask": "255.255.128.0", + "prefix": 17, + "type": "ipv4", + "public": false, + "rdns": null, + "linode_id": 26837992, + "region": "us-east" + }, + { + "address": "192.168.170.51", + "gateway": null, + "subnet_mask": "255.255.128.0", + "prefix": 17, + "type": "ipv4", + "public": false, + "rdns": null, + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "96.126.108.16", + "gateway": "96.126.108.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li365-16.members.linode.com", + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "45.33.82.151", + "gateway": "45.33.82.1", + "subnet_mask": "255.255.255.0", + "prefix": 24, + "type": "ipv4", + "public": true, + "rdns": "li1028-151.members.linode.com", + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "192.168.201.25", + "gateway": null, + "subnet_mask": "255.255.128.0", + "prefix": 17, + "type": "ipv4", + "public": false, + "rdns": null, + "linode_id": 26838044, + "region": "us-east" + }, + { + "address": "2600:3c03::f03c:92ff:fe1a:fb4c", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26837992, + "region": "us-east", + "public": true + }, + { + "address": "2600:3c03::f03c:92ff:fe1a:1382", + "gateway": "fe80::1", + "subnet_mask": "ffff:ffff:ffff:ffff::", + "prefix": 64, + "type": "ipv6", + "rdns": null, + "linode_id": 26838044, + "region": "us-east", + "public": true + } + ] +} diff --git a/discovery/linode/testdata/us-east/v4/networking/ipv6/ranges.json b/discovery/linode/testdata/us-east/v4/networking/ipv6/ranges.json new file mode 100644 index 0000000000..34b2ae1cdd --- /dev/null +++ b/discovery/linode/testdata/us-east/v4/networking/ipv6/ranges.json @@ -0,0 +1,13 @@ +{ + "data": [ + { + "range": "2600:3c03:e000:123::", + "prefix": 64, + "region": "us-east", + "route_target": "2600:3c03::f03c:92ff:fe1a:fb4c" + } + ], + "page": 1, + "pages": 1, + "results": 1 +} diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index d751a4084e..010a454661 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -2449,11 +2449,15 @@ The following meta labels are available on targets during [relabeling](#relabel_ * `__meta_linode_private_ipv4`: the private IPv4 of the linode instance * `__meta_linode_public_ipv4`: the public IPv4 of the linode instance * `__meta_linode_public_ipv6`: the public IPv6 of the linode instance +* `__meta_linode_private_ipv4_rdns`: the reverse DNS for the first private IPv4 of the linode instance +* `__meta_linode_public_ipv4_rdns`: the reverse DNS for the first public IPv4 of the linode instance +* `__meta_linode_public_ipv6_rdns`: the reverse DNS for the first public IPv6 of the linode instance * `__meta_linode_region`: the region of the linode instance * `__meta_linode_type`: the type of the linode instance * `__meta_linode_status`: the status of the linode instance * `__meta_linode_tags`: a list of tags of the linode instance joined by the tag separator * `__meta_linode_group`: the display group a linode instance is a member of +* `__meta_linode_gpus`: the number of GPU's of the linode instance * `__meta_linode_hypervisor`: the virtualization software powering the linode instance * `__meta_linode_backups`: the backup service status of the linode instance * `__meta_linode_specs_disk_bytes`: the amount of storage space the linode instance has access to @@ -2461,6 +2465,7 @@ The following meta labels are available on targets during [relabeling](#relabel_ * `__meta_linode_specs_vcpus`: the number of VCPUS this linode has access to * `__meta_linode_specs_transfer_bytes`: the amount of network transfer the linode instance is allotted each month * `__meta_linode_extra_ips`: a list of all extra IPv4 addresses assigned to the linode instance joined by the tag separator +* `__meta_linode_ipv6_ranges`: a list of IPv6 ranges with mask assigned to the linode instance joined by the tag separator ```yaml # Authentication information used to authenticate to the API server. @@ -2491,6 +2496,9 @@ authorization: oauth2: [ ] +# Optional region to filter on. +[ region: ] + # Optional proxy URL. [ proxy_url: ] # Comma-separated string that can contain IPs, CIDR notation, domain names diff --git a/documentation/examples/prometheus-linode.yml b/documentation/examples/prometheus-linode.yml index 993b6a5c12..fe1a740028 100644 --- a/documentation/examples/prometheus-linode.yml +++ b/documentation/examples/prometheus-linode.yml @@ -12,6 +12,7 @@ scrape_configs: linode_sd_configs: - authorization: credentials: "" + region: "us-east" relabel_configs: # Only scrape targets that have a tag 'monitoring'. - source_labels: [__meta_linode_tags] From dc7d3fbc3c9f4066ec3ecc5b3cb5e61293ab499c Mon Sep 17 00:00:00 2001 From: Sven Dewit Date: Fri, 5 Apr 2024 11:28:58 +0200 Subject: [PATCH 214/253] fix: scrape_config/interval relabelling is not experimental any more Signed-off-by: Sven Dewit --- docs/configuration/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 010a454661..51eb84ae19 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -3236,7 +3236,7 @@ are set to the scheme and metrics path of the target respectively. The `__param_ label is set to the value of the first passed URL parameter called ``. The `__scrape_interval__` and `__scrape_timeout__` labels are set to the target's -interval and timeout. This is **experimental** and could change in the future. +interval and timeout. Additional labels prefixed with `__meta_` may be available during the relabeling phase. They are set by the service discovery mechanism that provided From bbfc72b4e2ac06e109c151fa792bd31da8b0bd4b Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Fri, 5 Apr 2024 10:19:07 -0400 Subject: [PATCH 215/253] support unregistering discovery manager metrics (#13896) Signed-off-by: David Ashpole --- discovery/manager.go | 7 +++++++ discovery/manager_test.go | 25 +++++++++++++++++++++++-- discovery/metrics.go | 9 +++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/discovery/manager.go b/discovery/manager.go index e3a2635575..f14071af30 100644 --- a/discovery/manager.go +++ b/discovery/manager.go @@ -169,6 +169,13 @@ func (m *Manager) Providers() []*Provider { return m.providers } +// UnregisterMetrics unregisters manager metrics. It does not unregister +// service discovery or refresh metrics, whose lifecycle is managed independent +// of the discovery Manager. +func (m *Manager) UnregisterMetrics() { + m.metrics.Unregister(m.registerer) +} + // Run starts the background processing. func (m *Manager) Run() error { go m.sender() diff --git a/discovery/manager_test.go b/discovery/manager_test.go index 8f2345911e..656d7c3c66 100644 --- a/discovery/manager_test.go +++ b/discovery/manager_test.go @@ -36,11 +36,11 @@ func TestMain(m *testing.M) { testutil.TolerantVerifyLeak(m) } -func NewTestMetrics(t *testing.T, reg prometheus.Registerer) (*RefreshMetricsManager, map[string]DiscovererMetrics) { +func NewTestMetrics(t *testing.T, reg prometheus.Registerer) (RefreshMetricsManager, map[string]DiscovererMetrics) { refreshMetrics := NewRefreshMetrics(reg) sdMetrics, err := RegisterSDMetrics(reg, refreshMetrics) require.NoError(t, err) - return &refreshMetrics, sdMetrics + return refreshMetrics, sdMetrics } // TestTargetUpdatesOrder checks that the target updates are received in the expected order. @@ -1541,3 +1541,24 @@ func (t *testDiscoverer) update(tgs []*targetgroup.Group) { <-t.ready t.up <- tgs } + +func TestUnregisterMetrics(t *testing.T) { + reg := prometheus.NewRegistry() + // Check that all metrics can be unregistered, allowing a second manager to be created. + for i := 0; i < 2; i++ { + ctx, cancel := context.WithCancel(context.Background()) + + refreshMetrics, sdMetrics := NewTestMetrics(t, reg) + + discoveryManager := NewManager(ctx, log.NewNopLogger(), reg, sdMetrics) + // discoveryManager will be nil if there was an error configuring metrics. + require.NotNil(t, discoveryManager) + // Unregister all metrics. + discoveryManager.UnregisterMetrics() + for _, sdMetric := range sdMetrics { + sdMetric.Unregister() + } + refreshMetrics.Unregister() + cancel() + } +} diff --git a/discovery/metrics.go b/discovery/metrics.go index a77b86d274..e738331a18 100644 --- a/discovery/metrics.go +++ b/discovery/metrics.go @@ -99,3 +99,12 @@ func NewManagerMetrics(registerer prometheus.Registerer, sdManagerName string) ( return m, nil } + +// Unregister unregisters all metrics. +func (m *Metrics) Unregister(registerer prometheus.Registerer) { + registerer.Unregister(m.FailedConfigs) + registerer.Unregister(m.DiscoveredTargets) + registerer.Unregister(m.ReceivedUpdates) + registerer.Unregister(m.DelayedUpdates) + registerer.Unregister(m.SentUpdates) +} From 8e04ab6dd4eb3fc3a2c67f974f07f8ac2b852fa8 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 16 Jan 2024 17:49:43 +0000 Subject: [PATCH 216/253] promql: refactor: extract generateGroupingLabels function Signed-off-by: Bryan Boreham --- promql/engine.go | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 2f7dcb222e..56a7774c68 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2691,19 +2691,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par group, ok := result[groupingKey] // Add a new group if it doesn't exist. if !ok { - var m labels.Labels - enh.resetBuilder(metric) - switch { - case without: - enh.lb.Del(grouping...) - enh.lb.Del(labels.MetricName) - m = enh.lb.Labels() - case len(grouping) > 0: - enh.lb.Keep(grouping...) - m = enh.lb.Labels() - default: - m = labels.EmptyLabels() - } + m := generateGroupingLabels(enh, metric, without, grouping) newAgg := &groupedAggregation{ labels: m, floatValue: s.F, @@ -2969,6 +2957,21 @@ func generateGroupingKey(metric labels.Labels, grouping []string, without bool, return metric.HashForLabels(buf, grouping...) } +func generateGroupingLabels(enh *EvalNodeHelper, metric labels.Labels, without bool, grouping []string) labels.Labels { + enh.resetBuilder(metric) + switch { + case without: + enh.lb.Del(grouping...) + enh.lb.Del(labels.MetricName) + return enh.lb.Labels() + case len(grouping) > 0: + enh.lb.Keep(grouping...) + return enh.lb.Labels() + default: + return labels.EmptyLabels() + } +} + // btos returns 1 if b is true, 0 otherwise. func btos(b bool) float64 { if b { From 29244fb84173313479e5c0603c793f66d9959e46 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 16 Jan 2024 16:22:34 +0000 Subject: [PATCH 217/253] promql: refactor: extract count_values implementation The existing aggregation function is very long and covers very different cases. `aggregationCountValues` is just for `count_values`, which differs from other aggregations in that it outputs as many series per group as there are values in the input. Remove the top-level switch on string parameter type; use the same `Op` check there as elswehere. Pull checking parameters out to caller, where it is only executed once. Signed-off-by: Bryan Boreham --- promql/engine.go | 99 +++++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 56a7774c68..9074912d66 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1352,9 +1352,18 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio unwrapParenExpr(&e.Param) param := unwrapStepInvariantExpr(e.Param) unwrapParenExpr(¶m) - if s, ok := param.(*parser.StringLiteral); ok { - return ev.rangeEval(initSeries, func(v []parser.Value, sh [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, annotations.Annotations) { - return ev.aggregation(e, sortedGrouping, s.Val, v[0].(Vector), sh[0], enh) + + if e.Op == parser.COUNT_VALUES { + valueLabel := param.(*parser.StringLiteral) + if !model.LabelName(valueLabel.Val).IsValid() { + ev.errorf("invalid label name %q", valueLabel) + } + if !e.Without { + sortedGrouping = append(sortedGrouping, valueLabel.Val) + slices.Sort(sortedGrouping) + } + return ev.rangeEval(nil, func(v []parser.Value, _ [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, annotations.Annotations) { + return ev.aggregationCountValues(e, sortedGrouping, valueLabel.Val, v[0].(Vector), enh) }, e.Expr) } @@ -2649,44 +2658,10 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par if op == parser.QUANTILE { q = param.(float64) } - var valueLabel string - var recomputeGroupingKey bool - if op == parser.COUNT_VALUES { - valueLabel = param.(string) - if !model.LabelName(valueLabel).IsValid() { - ev.errorf("invalid label name %q", valueLabel) - } - if !without { - // We're changing the grouping labels so we have to ensure they're still sorted - // and we have to flag to recompute the grouping key. Considering the count_values() - // operator is less frequently used than other aggregations, we're fine having to - // re-compute the grouping key on each step for this case. - grouping = append(grouping, valueLabel) - slices.Sort(grouping) - recomputeGroupingKey = true - } - } - var buf []byte for si, s := range vec { metric := s.Metric - - if op == parser.COUNT_VALUES { - enh.resetBuilder(metric) - enh.lb.Set(valueLabel, strconv.FormatFloat(s.F, 'f', -1, 64)) - metric = enh.lb.Labels() - - // We've changed the metric so we have to recompute the grouping key. - recomputeGroupingKey = true - } - - // We can use the pre-computed grouping key unless grouping labels have changed. - var groupingKey uint64 - if !recomputeGroupingKey { - groupingKey = seriesHelper[si].groupingKey - } else { - groupingKey, buf = generateGroupingKey(metric, grouping, without, buf) - } + groupingKey := seriesHelper[si].groupingKey group, ok := result[groupingKey] // Add a new group if it doesn't exist. @@ -2807,7 +2782,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par group.floatValue = s.F } - case parser.COUNT, parser.COUNT_VALUES: + case parser.COUNT: group.groupCount++ case parser.STDVAR, parser.STDDEV: @@ -2879,7 +2854,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par aggr.floatValue = aggr.floatMean } - case parser.COUNT, parser.COUNT_VALUES: + case parser.COUNT: aggr.floatValue = float64(aggr.groupCount) case parser.STDVAR: @@ -2942,6 +2917,50 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par return enh.Out, annos } +// aggregationK evaluates count_values on vec. +// Outputs as many series per group as there are values in the input. +func (ev *evaluator) aggregationCountValues(e *parser.AggregateExpr, grouping []string, valueLabel string, vec Vector, enh *EvalNodeHelper) (Vector, annotations.Annotations) { + result := map[uint64]*groupedAggregation{} + orderedResult := []*groupedAggregation{} + + var buf []byte + for _, s := range vec { + enh.resetBuilder(s.Metric) + enh.lb.Set(valueLabel, strconv.FormatFloat(s.F, 'f', -1, 64)) + metric := enh.lb.Labels() + + // Considering the count_values() + // operator is less frequently used than other aggregations, we're fine having to + // re-compute the grouping key on each step for this case. + var groupingKey uint64 + groupingKey, buf = generateGroupingKey(metric, grouping, e.Without, buf) + + group, ok := result[groupingKey] + // Add a new group if it doesn't exist. + if !ok { + newAgg := &groupedAggregation{ + labels: generateGroupingLabels(enh, metric, e.Without, grouping), + groupCount: 1, + } + + result[groupingKey] = newAgg + orderedResult = append(orderedResult, newAgg) + continue + } + + group.groupCount++ + } + + // Construct the result Vector from the aggregated groups. + for _, aggr := range orderedResult { + enh.Out = append(enh.Out, Sample{ + Metric: aggr.labels, + F: float64(aggr.groupCount), + }) + } + return enh.Out, nil +} + // groupingKey builds and returns the grouping key for the given metric and // grouping labels. func generateGroupingKey(metric labels.Labels, grouping []string, without bool, buf []byte) (uint64, []byte) { From e5f667537c94dbd1e5ad70d766c0c27ea5cb8830 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 17 Jan 2024 10:57:02 +0000 Subject: [PATCH 218/253] promql: refactor: initialize aggregation before storing in map This seems more consistent to me. Signed-off-by: Bryan Boreham --- promql/engine.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 9074912d66..0a2c5ff3fc 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2686,9 +2686,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par newAgg.groupCount = 0 } - result[groupingKey] = newAgg - orderedResult = append(orderedResult, newAgg) - inputVecLen := int64(len(vec)) resultSize := k switch { @@ -2699,22 +2696,25 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par } switch op { case parser.STDVAR, parser.STDDEV: - result[groupingKey].floatValue = 0 + newAgg.floatValue = 0 case parser.TOPK, parser.QUANTILE: - result[groupingKey].heap = make(vectorByValueHeap, 1, resultSize) - result[groupingKey].heap[0] = Sample{ + newAgg.heap = make(vectorByValueHeap, 1, resultSize) + newAgg.heap[0] = Sample{ F: s.F, Metric: s.Metric, } case parser.BOTTOMK: - result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 1, resultSize) - result[groupingKey].reverseHeap[0] = Sample{ + newAgg.reverseHeap = make(vectorByReverseValueHeap, 1, resultSize) + newAgg.reverseHeap[0] = Sample{ F: s.F, Metric: s.Metric, } case parser.GROUP: - result[groupingKey].floatValue = 1 + newAgg.floatValue = 1 } + + result[groupingKey] = newAgg + orderedResult = append(orderedResult, newAgg) continue } From 5f10d17cef1a042ea7c9cd99026a502f7ae7c80e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 27 Feb 2024 06:38:49 +0000 Subject: [PATCH 219/253] promql: refactor: split out aggregations over range The new function `rangeEvalAgg` is mostly a copy of `rangeEval`, but without `initSeries` which we don't need and inlining the callback to `aggregation()`. Signed-off-by: Bryan Boreham --- promql/engine.go | 180 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 167 insertions(+), 13 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 0a2c5ff3fc..91c5e9e249 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1291,6 +1291,172 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) return mat, warnings } +func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping []string) (Matrix, annotations.Annotations) { + numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 + matrixes := make([]Matrix, 2) + origMatrixes := make([]Matrix, 2) + originalNumSamples := ev.currentSamples + + var warnings annotations.Annotations + for i, e := range []parser.Expr{aggExpr.Param, aggExpr.Expr} { + // Functions will take string arguments from the expressions, not the values. + if e != nil && e.Type() != parser.ValueTypeString { + // ev.currentSamples will be updated to the correct value within the ev.eval call. + val, ws := ev.eval(e) + warnings.Merge(ws) + matrixes[i] = val.(Matrix) + + // Keep a copy of the original point slices so that they + // can be returned to the pool. + origMatrixes[i] = make(Matrix, len(matrixes[i])) + copy(origMatrixes[i], matrixes[i]) + } + } + + vectors := make([]Vector, 2) // Input vectors for the function. + args := make([]parser.Value, 2) // Argument to function. + biggestLen := len(matrixes[1]) + enh := &EvalNodeHelper{Out: make(Vector, 0, biggestLen)} + type seriesAndTimestamp struct { + Series + ts int64 + } + seriess := make(map[uint64]seriesAndTimestamp, biggestLen) // Output series by series hash. + tempNumSamples := ev.currentSamples + + seriesHelpers := make([][]EvalSeriesHelper, 2) + bufHelpers := make([][]EvalSeriesHelper, 2) + // Prepare a function to initialise series helpers with the grouping key. + buf := make([]byte, 0, 1024) + + seriesHelpers[1] = make([]EvalSeriesHelper, len(matrixes[1])) + bufHelpers[1] = make([]EvalSeriesHelper, len(matrixes[1])) + + for si, series := range matrixes[1] { + seriesHelpers[1][si].groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) + } + + for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { + if err := contextDone(ev.ctx, "expression evaluation"); err != nil { + ev.error(err) + } + // Reset number of samples in memory after each timestamp. + ev.currentSamples = tempNumSamples + // Gather input vectors for this timestamp. + for i := range []parser.Expr{aggExpr.Param, aggExpr.Expr} { + vectors[i] = vectors[i][:0] + bufHelpers[i] = bufHelpers[i][:0] + + for si, series := range matrixes[i] { + switch { + case len(series.Floats) > 0 && series.Floats[0].T == ts: + vectors[i] = append(vectors[i], Sample{Metric: series.Metric, F: series.Floats[0].F, T: ts}) + // Move input vectors forward so we don't have to re-scan the same + // past points at the next step. + matrixes[i][si].Floats = series.Floats[1:] + case len(series.Histograms) > 0 && series.Histograms[0].T == ts: + vectors[i] = append(vectors[i], Sample{Metric: series.Metric, H: series.Histograms[0].H, T: ts}) + matrixes[i][si].Histograms = series.Histograms[1:] + default: + continue + } + if seriesHelpers[i] != nil { + bufHelpers[i] = append(bufHelpers[i], seriesHelpers[i][si]) + } + ev.currentSamples++ + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) + } + } + args[i] = vectors[i] + ev.samplesStats.UpdatePeak(ev.currentSamples) + } + + // Make the function call. + enh.Ts = ts + var param float64 + if aggExpr.Param != nil { + param = args[0].(Vector)[0].F + } + result, ws := ev.aggregation(aggExpr, sortedGrouping, param, args[1].(Vector), bufHelpers[1], enh) + + enh.Out = result[:0] // Reuse result vector. + warnings.Merge(ws) + + vecNumSamples := result.TotalSamples() + ev.currentSamples += vecNumSamples + // When we reset currentSamples to tempNumSamples during the next iteration of the loop it also + // needs to include the samples from the result here, as they're still in memory. + tempNumSamples += vecNumSamples + ev.samplesStats.UpdatePeak(ev.currentSamples) + + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) + } + ev.samplesStats.UpdatePeak(ev.currentSamples) + + // If this could be an instant query, shortcut so as not to change sort order. + if ev.endTimestamp == ev.startTimestamp { + if result.ContainsSameLabelset() { + ev.errorf("vector cannot contain metrics with the same labelset") + } + mat := make(Matrix, len(result)) + for i, s := range result { + if s.H == nil { + mat[i] = Series{Metric: s.Metric, Floats: []FPoint{{T: ts, F: s.F}}} + } else { + mat[i] = Series{Metric: s.Metric, Histograms: []HPoint{{T: ts, H: s.H}}} + } + } + ev.currentSamples = originalNumSamples + mat.TotalSamples() + ev.samplesStats.UpdatePeak(ev.currentSamples) + return mat, warnings + } + + // Add samples in output vector to output series. + for _, sample := range result { + h := sample.Metric.Hash() + ss, ok := seriess[h] + if ok { + if ss.ts == ts { // If we've seen this output series before at this timestamp, it's a duplicate. + ev.errorf("vector cannot contain metrics with the same labelset") + } + ss.ts = ts + } else { + ss = seriesAndTimestamp{Series{Metric: sample.Metric}, ts} + } + if sample.H == nil { + if ss.Floats == nil { + ss.Floats = getFPointSlice(numSteps) + } + ss.Floats = append(ss.Floats, FPoint{T: ts, F: sample.F}) + } else { + if ss.Histograms == nil { + ss.Histograms = getHPointSlice(numSteps) + } + ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: sample.H}) + } + seriess[h] = ss + } + } + + // Reuse the original point slices. + for _, m := range origMatrixes { + for _, s := range m { + putFPointSlice(s.Floats) + putHPointSlice(s.Histograms) + } + } + // Assemble the output matrix. By the time we get here we know we don't have too many samples. + mat := make(Matrix, 0, len(seriess)) + for _, ss := range seriess { + mat = append(mat, ss.Series) + } + ev.currentSamples = originalNumSamples + mat.TotalSamples() + ev.samplesStats.UpdatePeak(ev.currentSamples) + return mat, warnings +} + // evalSubquery evaluates given SubqueryExpr and returns an equivalent // evaluated MatrixSelector in its place. Note that the Name and LabelMatchers are not set. func (ev *evaluator) evalSubquery(subq *parser.SubqueryExpr) (*parser.MatrixSelector, int, annotations.Annotations) { @@ -1343,12 +1509,6 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio sortedGrouping := e.Grouping slices.Sort(sortedGrouping) - // Prepare a function to initialise series helpers with the grouping key. - buf := make([]byte, 0, 1024) - initSeries := func(series labels.Labels, h *EvalSeriesHelper) { - h.groupingKey, buf = generateGroupingKey(series, sortedGrouping, e.Without, buf) - } - unwrapParenExpr(&e.Param) param := unwrapStepInvariantExpr(e.Param) unwrapParenExpr(¶m) @@ -1367,13 +1527,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio }, e.Expr) } - return ev.rangeEval(initSeries, func(v []parser.Value, sh [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, annotations.Annotations) { - var param float64 - if e.Param != nil { - param = v[0].(Vector)[0].F - } - return ev.aggregation(e, sortedGrouping, param, v[1].(Vector), sh[1], enh) - }, e.Param, e.Expr) + return ev.rangeEvalAgg(e, sortedGrouping) case *parser.Call: call := FunctionCalls[e.Func.Name] From bd9bdccb22bb0ba99dd2da29de6d1d96d47fa0d0 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 27 Feb 2024 07:00:35 +0000 Subject: [PATCH 220/253] promql: refactor: simplify internal data structures Signed-off-by: Bryan Boreham --- promql/engine.go | 83 ++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 91c5e9e249..821a0e3698 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1293,29 +1293,27 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping []string) (Matrix, annotations.Annotations) { numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 - matrixes := make([]Matrix, 2) - origMatrixes := make([]Matrix, 2) originalNumSamples := ev.currentSamples - var warnings annotations.Annotations - for i, e := range []parser.Expr{aggExpr.Param, aggExpr.Expr} { - // Functions will take string arguments from the expressions, not the values. - if e != nil && e.Type() != parser.ValueTypeString { - // ev.currentSamples will be updated to the correct value within the ev.eval call. - val, ws := ev.eval(e) - warnings.Merge(ws) - matrixes[i] = val.(Matrix) - // Keep a copy of the original point slices so that they - // can be returned to the pool. - origMatrixes[i] = make(Matrix, len(matrixes[i])) - copy(origMatrixes[i], matrixes[i]) - } + // param is the number k for topk/bottomk. + var param float64 + if aggExpr.Param != nil { + val, ws := ev.eval(aggExpr.Param) + warnings.Merge(ws) + param = val.(Matrix)[0].Floats[0].F } + // Now fetch the data to be aggregated. + // ev.currentSamples will be updated to the correct value within the ev.eval call. + val, ws := ev.eval(aggExpr.Expr) + warnings.Merge(ws) + inputMatrix := val.(Matrix) - vectors := make([]Vector, 2) // Input vectors for the function. - args := make([]parser.Value, 2) // Argument to function. - biggestLen := len(matrixes[1]) + // Keep a copy of the original point slice so that it can be returned to the pool. + origMatrix := inputMatrix + + var vector Vector // Input vectors for the function. + biggestLen := len(inputMatrix) enh := &EvalNodeHelper{Out: make(Vector, 0, biggestLen)} type seriesAndTimestamp struct { Series @@ -1324,16 +1322,14 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping seriess := make(map[uint64]seriesAndTimestamp, biggestLen) // Output series by series hash. tempNumSamples := ev.currentSamples - seriesHelpers := make([][]EvalSeriesHelper, 2) - bufHelpers := make([][]EvalSeriesHelper, 2) - // Prepare a function to initialise series helpers with the grouping key. + // Initialise series helpers with the grouping key. buf := make([]byte, 0, 1024) - seriesHelpers[1] = make([]EvalSeriesHelper, len(matrixes[1])) - bufHelpers[1] = make([]EvalSeriesHelper, len(matrixes[1])) + seriesHelper := make([]EvalSeriesHelper, len(inputMatrix)) + bufHelper := make([]EvalSeriesHelper, len(inputMatrix)) - for si, series := range matrixes[1] { - seriesHelpers[1][si].groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) + for si, series := range inputMatrix { + seriesHelper[si].groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) } for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { @@ -1343,42 +1339,35 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // Reset number of samples in memory after each timestamp. ev.currentSamples = tempNumSamples // Gather input vectors for this timestamp. - for i := range []parser.Expr{aggExpr.Param, aggExpr.Expr} { - vectors[i] = vectors[i][:0] - bufHelpers[i] = bufHelpers[i][:0] + { + vector = vector[:0] + bufHelper = bufHelper[:0] - for si, series := range matrixes[i] { + for si, series := range inputMatrix { switch { case len(series.Floats) > 0 && series.Floats[0].T == ts: - vectors[i] = append(vectors[i], Sample{Metric: series.Metric, F: series.Floats[0].F, T: ts}) + vector = append(vector, Sample{Metric: series.Metric, F: series.Floats[0].F, T: ts}) // Move input vectors forward so we don't have to re-scan the same // past points at the next step. - matrixes[i][si].Floats = series.Floats[1:] + inputMatrix[si].Floats = series.Floats[1:] case len(series.Histograms) > 0 && series.Histograms[0].T == ts: - vectors[i] = append(vectors[i], Sample{Metric: series.Metric, H: series.Histograms[0].H, T: ts}) - matrixes[i][si].Histograms = series.Histograms[1:] + vector = append(vector, Sample{Metric: series.Metric, H: series.Histograms[0].H, T: ts}) + inputMatrix[si].Histograms = series.Histograms[1:] default: continue } - if seriesHelpers[i] != nil { - bufHelpers[i] = append(bufHelpers[i], seriesHelpers[i][si]) - } + bufHelper = append(bufHelper, seriesHelper[si]) ev.currentSamples++ if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } } - args[i] = vectors[i] ev.samplesStats.UpdatePeak(ev.currentSamples) } // Make the function call. enh.Ts = ts - var param float64 - if aggExpr.Param != nil { - param = args[0].(Vector)[0].F - } - result, ws := ev.aggregation(aggExpr, sortedGrouping, param, args[1].(Vector), bufHelpers[1], enh) + result, ws := ev.aggregation(aggExpr, sortedGrouping, param, vector, bufHelper, enh) enh.Out = result[:0] // Reuse result vector. warnings.Merge(ws) @@ -1440,12 +1429,10 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping } } - // Reuse the original point slices. - for _, m := range origMatrixes { - for _, s := range m { - putFPointSlice(s.Floats) - putHPointSlice(s.Histograms) - } + // Reuse the original point slice. + for _, s := range origMatrix { + putFPointSlice(s.Floats) + putHPointSlice(s.Histograms) } // Assemble the output matrix. By the time we get here we know we don't have too many samples. mat := make(Matrix, 0, len(seriess)) From 59548b8a0b8f7f4e35d9b1fcd43c26f6d7cd10f5 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 27 Feb 2024 08:19:01 +0000 Subject: [PATCH 221/253] promql: refactor: move collection of results into aggregation() We don't need to check for duplicates as aggregation cannot generate them. Signed-off-by: Bryan Boreham --- promql/engine.go | 73 ++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 821a0e3698..b73364bc87 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1292,7 +1292,6 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) } func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping []string) (Matrix, annotations.Annotations) { - numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 originalNumSamples := ev.currentSamples var warnings annotations.Annotations @@ -1315,11 +1314,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping var vector Vector // Input vectors for the function. biggestLen := len(inputMatrix) enh := &EvalNodeHelper{Out: make(Vector, 0, biggestLen)} - type seriesAndTimestamp struct { - Series - ts int64 - } - seriess := make(map[uint64]seriesAndTimestamp, biggestLen) // Output series by series hash. + seriess := make(map[uint64]Series, biggestLen) // Output series by series hash. tempNumSamples := ev.currentSamples // Initialise series helpers with the grouping key. @@ -1367,7 +1362,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // Make the function call. enh.Ts = ts - result, ws := ev.aggregation(aggExpr, sortedGrouping, param, vector, bufHelper, enh) + result, ws := ev.aggregation(aggExpr, sortedGrouping, param, vector, bufHelper, enh, seriess) enh.Out = result[:0] // Reuse result vector. warnings.Merge(ws) @@ -1386,9 +1381,6 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { - if result.ContainsSameLabelset() { - ev.errorf("vector cannot contain metrics with the same labelset") - } mat := make(Matrix, len(result)) for i, s := range result { if s.H == nil { @@ -1401,32 +1393,6 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping ev.samplesStats.UpdatePeak(ev.currentSamples) return mat, warnings } - - // Add samples in output vector to output series. - for _, sample := range result { - h := sample.Metric.Hash() - ss, ok := seriess[h] - if ok { - if ss.ts == ts { // If we've seen this output series before at this timestamp, it's a duplicate. - ev.errorf("vector cannot contain metrics with the same labelset") - } - ss.ts = ts - } else { - ss = seriesAndTimestamp{Series{Metric: sample.Metric}, ts} - } - if sample.H == nil { - if ss.Floats == nil { - ss.Floats = getFPointSlice(numSteps) - } - ss.Floats = append(ss.Floats, FPoint{T: ts, F: sample.F}) - } else { - if ss.Histograms == nil { - ss.Histograms = getHPointSlice(numSteps) - } - ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: sample.H}) - } - seriess[h] = ss - } } // Reuse the original point slice. @@ -1437,7 +1403,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // Assemble the output matrix. By the time we get here we know we don't have too many samples. mat := make(Matrix, 0, len(seriess)) for _, ss := range seriess { - mat = append(mat, ss.Series) + mat = append(mat, ss) } ev.currentSamples = originalNumSamples + mat.TotalSamples() ev.samplesStats.UpdatePeak(ev.currentSamples) @@ -2778,7 +2744,7 @@ type groupedAggregation struct { // aggregation evaluates an aggregation operation on a Vector. The provided grouping labels // must be sorted. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, vec Vector, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper) (Vector, annotations.Annotations) { +func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, vec Vector, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Vector, annotations.Annotations) { op := e.Op without := e.Without var annos annotations.Annotations @@ -3055,7 +3021,36 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par H: aggr.histogramValue, }) } - return enh.Out, annos + + ts := enh.Ts + // If this could be an instant query, shortcut so as not to change sort order. + if ev.endTimestamp == ev.startTimestamp { + return enh.Out, annos + } + + numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 + // Add samples in output vector to output series. + for _, sample := range enh.Out { + h := sample.Metric.Hash() + ss, ok := seriess[h] + if !ok { + ss = Series{Metric: sample.Metric} + } + if sample.H == nil { + if ss.Floats == nil { + ss.Floats = getFPointSlice(numSteps) + } + ss.Floats = append(ss.Floats, FPoint{T: ts, F: sample.F}) + } else { + if ss.Histograms == nil { + ss.Histograms = getHPointSlice(numSteps) + } + ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: sample.H}) + } + seriess[h] = ss + } + + return nil, annos } // aggregationK evaluates count_values on vec. From 3851b74db1923ac414a7a0b88a81c9b663efd1ab Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 29 Feb 2024 23:21:46 +0000 Subject: [PATCH 222/253] promql: aggregations: skip result vector in range queries Adjust test to match the lower count, since samples in the vector are no longer counted. Signed-off-by: Bryan Boreham --- promql/engine.go | 89 +++++++++++++++++-------------------------- promql/engine_test.go | 2 +- 2 files changed, 35 insertions(+), 56 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index b73364bc87..5757604b7a 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1367,18 +1367,6 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping enh.Out = result[:0] // Reuse result vector. warnings.Merge(ws) - vecNumSamples := result.TotalSamples() - ev.currentSamples += vecNumSamples - // When we reset currentSamples to tempNumSamples during the next iteration of the loop it also - // needs to include the samples from the result here, as they're still in memory. - tempNumSamples += vecNumSamples - ev.samplesStats.UpdatePeak(ev.currentSamples) - - if ev.currentSamples > ev.maxSamples { - ev.error(ErrTooManySamples(env)) - } - ev.samplesStats.UpdatePeak(ev.currentSamples) - // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { mat := make(Matrix, len(result)) @@ -1393,6 +1381,9 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping ev.samplesStats.UpdatePeak(ev.currentSamples) return mat, warnings } + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) + } } // Reuse the original point slice. @@ -2946,7 +2937,33 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par } } - // Construct the result Vector from the aggregated groups. + // Construct the result from the aggregated groups. + numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 + add := func(lbls labels.Labels, f float64, h *histogram.FloatHistogram) { + // If this could be an instant query, build a slice so the result is in consistent order. + if ev.endTimestamp == ev.startTimestamp { + enh.Out = append(enh.Out, Sample{Metric: lbls, F: f, H: h}) + } else { + // Otherwise the results are added into seriess elements. + hash := lbls.Hash() + ss, ok := seriess[hash] + if !ok { + ss = Series{Metric: lbls} + } + if h == nil { + if ss.Floats == nil { + ss.Floats = getFPointSlice(numSteps) + } + ss.Floats = append(ss.Floats, FPoint{T: enh.Ts, F: f}) + } else { + if ss.Histograms == nil { + ss.Histograms = getHPointSlice(numSteps) + } + ss.Histograms = append(ss.Histograms, HPoint{T: enh.Ts, H: h}) + } + seriess[hash] = ss + } + } for _, aggr := range orderedResult { switch op { case parser.AVG: @@ -2976,10 +2993,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par sort.Sort(sort.Reverse(aggr.heap)) } for _, v := range aggr.heap { - enh.Out = append(enh.Out, Sample{ - Metric: v.Metric, - F: v.F, - }) + add(v.Metric, v.F, nil) } continue // Bypass default append. @@ -2989,10 +3003,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par sort.Sort(sort.Reverse(aggr.reverseHeap)) } for _, v := range aggr.reverseHeap { - enh.Out = append(enh.Out, Sample{ - Metric: v.Metric, - F: v.F, - }) + add(v.Metric, v.F, nil) } continue // Bypass default append. @@ -3015,42 +3026,10 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par // For other aggregations, we already have the right value. } - enh.Out = append(enh.Out, Sample{ - Metric: aggr.labels, - F: aggr.floatValue, - H: aggr.histogramValue, - }) + add(aggr.labels, aggr.floatValue, aggr.histogramValue) } - ts := enh.Ts - // If this could be an instant query, shortcut so as not to change sort order. - if ev.endTimestamp == ev.startTimestamp { - return enh.Out, annos - } - - numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 - // Add samples in output vector to output series. - for _, sample := range enh.Out { - h := sample.Metric.Hash() - ss, ok := seriess[h] - if !ok { - ss = Series{Metric: sample.Metric} - } - if sample.H == nil { - if ss.Floats == nil { - ss.Floats = getFPointSlice(numSteps) - } - ss.Floats = append(ss.Floats, FPoint{T: ts, F: sample.F}) - } else { - if ss.Histograms == nil { - ss.Histograms = getHPointSlice(numSteps) - } - ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: sample.H}) - } - seriess[h] = ss - } - - return nil, annos + return enh.Out, annos } // aggregationK evaluates count_values on vec. diff --git a/promql/engine_test.go b/promql/engine_test.go index 13731efd45..0202c15ae1 100644 --- a/promql/engine_test.go +++ b/promql/engine_test.go @@ -966,7 +966,7 @@ load 10s { Query: "sum by (b) (max_over_time(metricWith3SampleEvery10Seconds[60s] @ 30))", Start: time.Unix(201, 0), - PeakSamples: 8, + PeakSamples: 7, TotalSamples: 12, // @ modifier force the evaluation to at 30 seconds - So it brings 4 datapoints (0, 10, 20, 30 seconds) * 3 series TotalSamplesPerStep: stats.TotalSamplesPerStep{ 201000: 12, From c9b6c4c55ae89f9ab4b4f232247eae67d4062c40 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 29 Feb 2024 23:39:29 +0000 Subject: [PATCH 223/253] promql: aggregations: output directly to matrix for instant queries Signed-off-by: Bryan Boreham --- promql/engine.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 5757604b7a..2e5f620e32 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1313,7 +1313,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping var vector Vector // Input vectors for the function. biggestLen := len(inputMatrix) - enh := &EvalNodeHelper{Out: make(Vector, 0, biggestLen)} + enh := &EvalNodeHelper{} seriess := make(map[uint64]Series, biggestLen) // Output series by series hash. tempNumSamples := ev.currentSamples @@ -1364,22 +1364,13 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping enh.Ts = ts result, ws := ev.aggregation(aggExpr, sortedGrouping, param, vector, bufHelper, enh, seriess) - enh.Out = result[:0] // Reuse result vector. warnings.Merge(ws) // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { - mat := make(Matrix, len(result)) - for i, s := range result { - if s.H == nil { - mat[i] = Series{Metric: s.Metric, Floats: []FPoint{{T: ts, F: s.F}}} - } else { - mat[i] = Series{Metric: s.Metric, Histograms: []HPoint{{T: ts, H: s.H}}} - } - } - ev.currentSamples = originalNumSamples + mat.TotalSamples() + ev.currentSamples = originalNumSamples + result.TotalSamples() ev.samplesStats.UpdatePeak(ev.currentSamples) - return mat, warnings + return result, warnings } if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) @@ -2735,7 +2726,7 @@ type groupedAggregation struct { // aggregation evaluates an aggregation operation on a Vector. The provided grouping labels // must be sorted. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, vec Vector, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Vector, annotations.Annotations) { +func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, vec Vector, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { op := e.Op without := e.Without var annos annotations.Annotations @@ -2749,7 +2740,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par } k = int64(f) if k < 1 { - return Vector{}, annos + return nil, annos } } var q float64 @@ -2939,10 +2930,19 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par // Construct the result from the aggregated groups. numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 + var mat Matrix + if ev.endTimestamp == ev.startTimestamp { + mat = make(Matrix, 0, len(orderedResult)) + } + add := func(lbls labels.Labels, f float64, h *histogram.FloatHistogram) { - // If this could be an instant query, build a slice so the result is in consistent order. + // If this could be an instant query, add directly to the matrix so the result is in consistent order. if ev.endTimestamp == ev.startTimestamp { - enh.Out = append(enh.Out, Sample{Metric: lbls, F: f, H: h}) + if h == nil { + mat = append(mat, Series{Metric: lbls, Floats: []FPoint{{T: enh.Ts, F: f}}}) + } else { + mat = append(mat, Series{Metric: lbls, Histograms: []HPoint{{T: enh.Ts, H: h}}}) + } } else { // Otherwise the results are added into seriess elements. hash := lbls.Hash() @@ -3029,7 +3029,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par add(aggr.labels, aggr.floatValue, aggr.histogramValue) } - return enh.Out, annos + return mat, annos } // aggregationK evaluates count_values on vec. From b3bda7df4b7d1e5e47edb0bb3b7ea9d3057fefdc Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 1 Mar 2024 16:02:54 +0000 Subject: [PATCH 224/253] promql: aggregations: skip copying input to a Vector We can work directly from the inputMatrix on each timestep. Signed-off-by: Bryan Boreham --- promql/engine.go | 55 ++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 2e5f620e32..5fb1d849df 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1311,7 +1311,6 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // Keep a copy of the original point slice so that it can be returned to the pool. origMatrix := inputMatrix - var vector Vector // Input vectors for the function. biggestLen := len(inputMatrix) enh := &EvalNodeHelper{} seriess := make(map[uint64]Series, biggestLen) // Output series by series hash. @@ -1321,7 +1320,6 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping buf := make([]byte, 0, 1024) seriesHelper := make([]EvalSeriesHelper, len(inputMatrix)) - bufHelper := make([]EvalSeriesHelper, len(inputMatrix)) for si, series := range inputMatrix { seriesHelper[si].groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) @@ -1333,36 +1331,10 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping } // Reset number of samples in memory after each timestamp. ev.currentSamples = tempNumSamples - // Gather input vectors for this timestamp. - { - vector = vector[:0] - bufHelper = bufHelper[:0] - - for si, series := range inputMatrix { - switch { - case len(series.Floats) > 0 && series.Floats[0].T == ts: - vector = append(vector, Sample{Metric: series.Metric, F: series.Floats[0].F, T: ts}) - // Move input vectors forward so we don't have to re-scan the same - // past points at the next step. - inputMatrix[si].Floats = series.Floats[1:] - case len(series.Histograms) > 0 && series.Histograms[0].T == ts: - vector = append(vector, Sample{Metric: series.Metric, H: series.Histograms[0].H, T: ts}) - inputMatrix[si].Histograms = series.Histograms[1:] - default: - continue - } - bufHelper = append(bufHelper, seriesHelper[si]) - ev.currentSamples++ - if ev.currentSamples > ev.maxSamples { - ev.error(ErrTooManySamples(env)) - } - } - ev.samplesStats.UpdatePeak(ev.currentSamples) - } // Make the function call. enh.Ts = ts - result, ws := ev.aggregation(aggExpr, sortedGrouping, param, vector, bufHelper, enh, seriess) + result, ws := ev.aggregation(aggExpr, sortedGrouping, param, inputMatrix, seriesHelper, enh, seriess) warnings.Merge(ws) @@ -2726,7 +2698,7 @@ type groupedAggregation struct { // aggregation evaluates an aggregation operation on a Vector. The provided grouping labels // must be sorted. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, vec Vector, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { +func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, inputMatrix Matrix, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { op := e.Op without := e.Without var annos annotations.Annotations @@ -2748,7 +2720,26 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par q = param.(float64) } - for si, s := range vec { + for si, series := range inputMatrix { + var s Sample + + switch { + case len(series.Floats) > 0 && series.Floats[0].T == enh.Ts: + s = Sample{Metric: series.Metric, F: series.Floats[0].F, T: enh.Ts} + // Move input vectors forward so we don't have to re-scan the same + // past points at the next step. + inputMatrix[si].Floats = series.Floats[1:] + case len(series.Histograms) > 0 && series.Histograms[0].T == enh.Ts: + s = Sample{Metric: series.Metric, H: series.Histograms[0].H, T: enh.Ts} + inputMatrix[si].Histograms = series.Histograms[1:] + default: + continue + } + ev.currentSamples++ + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) + } + metric := s.Metric groupingKey := seriesHelper[si].groupingKey @@ -2775,7 +2766,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par newAgg.groupCount = 0 } - inputVecLen := int64(len(vec)) + inputVecLen := int64(len(inputMatrix)) resultSize := k switch { case k > inputVecLen: From cb6c4b3092ce7e42a2fe08011c5ad283ff17c64e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 1 Mar 2024 16:01:20 +0000 Subject: [PATCH 225/253] promql: simplify k/q parameter to topk/bottomk/quantile Pass it as a float64 not as interface{}. Make k a simple int, since that is the parameter to make(). Pull invalid quantile warning out of the loop. Signed-off-by: Bryan Boreham --- promql/engine.go | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 5fb1d849df..35dc52942c 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1295,7 +1295,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping originalNumSamples := ev.currentSamples var warnings annotations.Annotations - // param is the number k for topk/bottomk. + // param is the number k for topk/bottomk, or q for quantile. var param float64 if aggExpr.Param != nil { val, ws := ev.eval(aggExpr.Param) @@ -2698,26 +2698,29 @@ type groupedAggregation struct { // aggregation evaluates an aggregation operation on a Vector. The provided grouping labels // must be sorted. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, param interface{}, inputMatrix Matrix, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { +func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, q float64, inputMatrix Matrix, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { op := e.Op without := e.Without var annos annotations.Annotations result := map[uint64]*groupedAggregation{} orderedResult := []*groupedAggregation{} - var k int64 + k := 1 if op == parser.TOPK || op == parser.BOTTOMK { - f := param.(float64) - if !convertibleToInt64(f) { - ev.errorf("Scalar value %v overflows int64", f) + if !convertibleToInt64(q) { + ev.errorf("Scalar value %v overflows int64", q) + } + k = int(q) + if k > len(inputMatrix) { + k = len(inputMatrix) } - k = int64(f) if k < 1 { return nil, annos } } - var q float64 if op == parser.QUANTILE { - q = param.(float64) + if math.IsNaN(q) || q < 0 || q > 1 { + annos.Add(annotations.NewInvalidQuantileWarning(q, e.Param.PositionRange())) + } } for si, series := range inputMatrix { @@ -2766,25 +2769,17 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par newAgg.groupCount = 0 } - inputVecLen := int64(len(inputMatrix)) - resultSize := k - switch { - case k > inputVecLen: - resultSize = inputVecLen - case k == 0: - resultSize = 1 - } switch op { case parser.STDVAR, parser.STDDEV: newAgg.floatValue = 0 case parser.TOPK, parser.QUANTILE: - newAgg.heap = make(vectorByValueHeap, 1, resultSize) + newAgg.heap = make(vectorByValueHeap, 1, k) newAgg.heap[0] = Sample{ F: s.F, Metric: s.Metric, } case parser.BOTTOMK: - newAgg.reverseHeap = make(vectorByReverseValueHeap, 1, resultSize) + newAgg.reverseHeap = make(vectorByReverseValueHeap, 1, k) newAgg.reverseHeap[0] = Sample{ F: s.F, Metric: s.Metric, @@ -2876,7 +2871,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par case parser.TOPK: // We build a heap of up to k elements, with the smallest element at heap[0]. switch { - case int64(len(group.heap)) < k: + case len(group.heap) < k: heap.Push(&group.heap, &Sample{ F: s.F, Metric: s.Metric, @@ -2895,7 +2890,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par case parser.BOTTOMK: // We build a heap of up to k elements, with the biggest element at heap[0]. switch { - case int64(len(group.reverseHeap)) < k: + case len(group.reverseHeap) < k: heap.Push(&group.reverseHeap, &Sample{ F: s.F, Metric: s.Metric, @@ -2999,9 +2994,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, par continue // Bypass default append. case parser.QUANTILE: - if math.IsNaN(q) || q < 0 || q > 1 { - annos.Add(annotations.NewInvalidQuantileWarning(q, e.Param.PositionRange())) - } aggr.floatValue = quantile(q, aggr.heap) case parser.SUM: From 53a3138eeb54eeb7331c300cebd2d0122c8ba796 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 2 Mar 2024 12:52:35 +0000 Subject: [PATCH 226/253] promql aggregations: pre-generate mapping from inputs to outputs So we don't have to re-create it on every time step. Signed-off-by: Bryan Boreham --- promql/engine.go | 77 ++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 35dc52942c..140c0a0e49 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1067,8 +1067,6 @@ func (ev *evaluator) Eval(expr parser.Expr) (v parser.Value, ws annotations.Anno // EvalSeriesHelper stores extra information about a series. type EvalSeriesHelper struct { - // The grouping key used by aggregation. - groupingKey uint64 // Used to map left-hand to right-hand in binary operations. signature string } @@ -1316,13 +1314,25 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping seriess := make(map[uint64]Series, biggestLen) // Output series by series hash. tempNumSamples := ev.currentSamples - // Initialise series helpers with the grouping key. + // Create a mapping from input series to output groups. buf := make([]byte, 0, 1024) - - seriesHelper := make([]EvalSeriesHelper, len(inputMatrix)) + groupToResultIndex := make(map[uint64]int) + seriesToResult := make([]int, len(inputMatrix)) + orderedResult := make([]*groupedAggregation, 0, 16) for si, series := range inputMatrix { - seriesHelper[si].groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) + var groupingKey uint64 + groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) + index, ok := groupToResultIndex[groupingKey] + // Add a new group if it doesn't exist. + if !ok { + m := generateGroupingLabels(enh, series.Metric, aggExpr.Without, sortedGrouping) + newAgg := &groupedAggregation{labels: m} + index = len(orderedResult) + groupToResultIndex[groupingKey] = index + orderedResult = append(orderedResult, newAgg) + } + seriesToResult[si] = index } for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { @@ -1334,7 +1344,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // Make the function call. enh.Ts = ts - result, ws := ev.aggregation(aggExpr, sortedGrouping, param, inputMatrix, seriesHelper, enh, seriess) + result, ws := ev.aggregation(aggExpr, param, inputMatrix, seriesToResult, orderedResult, enh, seriess) warnings.Merge(ws) @@ -2698,12 +2708,10 @@ type groupedAggregation struct { // aggregation evaluates an aggregation operation on a Vector. The provided grouping labels // must be sorted. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, q float64, inputMatrix Matrix, seriesHelper []EvalSeriesHelper, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { +func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { op := e.Op - without := e.Without var annos annotations.Annotations - result := map[uint64]*groupedAggregation{} - orderedResult := []*groupedAggregation{} + seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. k := 1 if op == parser.TOPK || op == parser.BOTTOMK { if !convertibleToInt64(q) { @@ -2743,53 +2751,47 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, q f ev.error(ErrTooManySamples(env)) } - metric := s.Metric - groupingKey := seriesHelper[si].groupingKey - - group, ok := result[groupingKey] - // Add a new group if it doesn't exist. - if !ok { - m := generateGroupingLabels(enh, metric, without, grouping) - newAgg := &groupedAggregation{ - labels: m, + group := orderedResult[seriesToResult[si]] + // Initialize this group if it's the first time we've seen it. + if !seen[seriesToResult[si]] { + *group = groupedAggregation{ + labels: group.labels, floatValue: s.F, floatMean: s.F, groupCount: 1, } switch { case s.H == nil: - newAgg.hasFloat = true + group.hasFloat = true case op == parser.SUM: - newAgg.histogramValue = s.H.Copy() - newAgg.hasHistogram = true + group.histogramValue = s.H.Copy() + group.hasHistogram = true case op == parser.AVG: - newAgg.histogramMean = s.H.Copy() - newAgg.hasHistogram = true + group.histogramMean = s.H.Copy() + group.hasHistogram = true case op == parser.STDVAR || op == parser.STDDEV: - newAgg.groupCount = 0 + group.groupCount = 0 } switch op { case parser.STDVAR, parser.STDDEV: - newAgg.floatValue = 0 + group.floatValue = 0 case parser.TOPK, parser.QUANTILE: - newAgg.heap = make(vectorByValueHeap, 1, k) - newAgg.heap[0] = Sample{ + group.heap = make(vectorByValueHeap, 1, k) + group.heap[0] = Sample{ F: s.F, Metric: s.Metric, } case parser.BOTTOMK: - newAgg.reverseHeap = make(vectorByReverseValueHeap, 1, k) - newAgg.reverseHeap[0] = Sample{ + group.reverseHeap = make(vectorByReverseValueHeap, 1, k) + group.reverseHeap[0] = Sample{ F: s.F, Metric: s.Metric, } case parser.GROUP: - newAgg.floatValue = 1 + group.floatValue = 1 } - - result[groupingKey] = newAgg - orderedResult = append(orderedResult, newAgg) + seen[seriesToResult[si]] = true continue } @@ -2950,7 +2952,10 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, grouping []string, q f seriess[hash] = ss } } - for _, aggr := range orderedResult { + for ri, aggr := range orderedResult { + if !seen[ri] { + continue + } switch op { case parser.AVG: if aggr.hasFloat && aggr.hasHistogram { From eb41e770b79fe3824a342efbab4fc169364706ef Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 3 Mar 2024 16:52:43 +0000 Subject: [PATCH 227/253] promql: refactor: extract function addToSeries Signed-off-by: Bryan Boreham --- promql/engine.go | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 140c0a0e49..f915c3480e 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1257,17 +1257,7 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) } else { ss = seriesAndTimestamp{Series{Metric: sample.Metric}, ts} } - if sample.H == nil { - if ss.Floats == nil { - ss.Floats = getFPointSlice(numSteps) - } - ss.Floats = append(ss.Floats, FPoint{T: ts, F: sample.F}) - } else { - if ss.Histograms == nil { - ss.Histograms = getHPointSlice(numSteps) - } - ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: sample.H}) - } + addToSeries(&ss.Series, enh.Ts, sample.F, sample.H, numSteps) seriess[h] = ss } } @@ -2938,17 +2928,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix if !ok { ss = Series{Metric: lbls} } - if h == nil { - if ss.Floats == nil { - ss.Floats = getFPointSlice(numSteps) - } - ss.Floats = append(ss.Floats, FPoint{T: enh.Ts, F: f}) - } else { - if ss.Histograms == nil { - ss.Histograms = getHPointSlice(numSteps) - } - ss.Histograms = append(ss.Histograms, HPoint{T: enh.Ts, H: h}) - } + addToSeries(&ss, enh.Ts, f, h, numSteps) seriess[hash] = ss } } @@ -3064,6 +3044,20 @@ func (ev *evaluator) aggregationCountValues(e *parser.AggregateExpr, grouping [] return enh.Out, nil } +func addToSeries(ss *Series, ts int64, f float64, h *histogram.FloatHistogram, numSteps int) { + if h == nil { + if ss.Floats == nil { + ss.Floats = getFPointSlice(numSteps) + } + ss.Floats = append(ss.Floats, FPoint{T: ts, F: f}) + } else { + if ss.Histograms == nil { + ss.Histograms = getHPointSlice(numSteps) + } + ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: h}) + } +} + // groupingKey builds and returns the grouping key for the given metric and // grouping labels. func generateGroupingKey(metric labels.Labels, grouping []string, without bool, buf []byte) (uint64, []byte) { From 602eb69edfe87f90e8a1a2844168c946f83aa3f6 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 5 Apr 2024 11:37:55 +0100 Subject: [PATCH 228/253] promql: refactor: extract function nextSample With sub-function nextValues which we shall use shortly. Signed-off-by: Bryan Boreham --- promql/engine.go | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index f915c3480e..9e0a6b17c4 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2721,25 +2721,11 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix } } - for si, series := range inputMatrix { - var s Sample - - switch { - case len(series.Floats) > 0 && series.Floats[0].T == enh.Ts: - s = Sample{Metric: series.Metric, F: series.Floats[0].F, T: enh.Ts} - // Move input vectors forward so we don't have to re-scan the same - // past points at the next step. - inputMatrix[si].Floats = series.Floats[1:] - case len(series.Histograms) > 0 && series.Histograms[0].T == enh.Ts: - s = Sample{Metric: series.Metric, H: series.Histograms[0].H, T: enh.Ts} - inputMatrix[si].Histograms = series.Histograms[1:] - default: + for si := range inputMatrix { + s, ok := ev.nextSample(enh.Ts, inputMatrix, si) + if !ok { continue } - ev.currentSamples++ - if ev.currentSamples > ev.maxSamples { - ev.error(ErrTooManySamples(env)) - } group := orderedResult[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. @@ -3058,6 +3044,29 @@ func addToSeries(ss *Series, ts int64, f float64, h *histogram.FloatHistogram, n } } +func (ev *evaluator) nextValues(ts int64, series *Series) (f float64, h *histogram.FloatHistogram, b bool) { + switch { + case len(series.Floats) > 0 && series.Floats[0].T == ts: + f = series.Floats[0].F + series.Floats = series.Floats[1:] // Move input vectors forward + case len(series.Histograms) > 0 && series.Histograms[0].T == ts: + h = series.Histograms[0].H + series.Histograms = series.Histograms[1:] + default: + return f, h, false + } + return f, h, true +} + +func (ev *evaluator) nextSample(ts int64, inputMatrix Matrix, si int) (Sample, bool) { + f, h, ok := ev.nextValues(ts, &inputMatrix[si]) + ev.currentSamples++ + if ev.currentSamples > ev.maxSamples { + ev.error(ErrTooManySamples(env)) + } + return Sample{Metric: inputMatrix[si].Metric, F: f, H: h, T: ts}, ok +} + // groupingKey builds and returns the grouping key for the given metric and // grouping labels. func generateGroupingKey(metric labels.Labels, grouping []string, without bool, buf []byte) (uint64, []byte) { From 74eed67ef6c41ea252e3208f7db6ac52e9b941d8 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 5 Apr 2024 11:56:04 +0100 Subject: [PATCH 229/253] promql: refactor: pull fetching input data out of rangeEvalAgg This is a cleaner split of responsibilities. We now check the sample count after calling rangeEvalAgg. Changed re-use of samples to use `Clone` and `defer`. Signed-off-by: Bryan Boreham --- promql/engine.go | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 9e0a6b17c4..770550dac1 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1279,29 +1279,19 @@ func (ev *evaluator) rangeEval(prepSeries func(labels.Labels, *EvalSeriesHelper) return mat, warnings } -func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping []string) (Matrix, annotations.Annotations) { - originalNumSamples := ev.currentSamples +func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping []string, inputMatrix Matrix, param float64) (Matrix, annotations.Annotations) { + // Keep a copy of the original point slice so that it can be returned to the pool. + origMatrix := slices.Clone(inputMatrix) + defer func() { + for _, s := range origMatrix { + putFPointSlice(s.Floats) + putHPointSlice(s.Histograms) + } + }() + var warnings annotations.Annotations - // param is the number k for topk/bottomk, or q for quantile. - var param float64 - if aggExpr.Param != nil { - val, ws := ev.eval(aggExpr.Param) - warnings.Merge(ws) - param = val.(Matrix)[0].Floats[0].F - } - // Now fetch the data to be aggregated. - // ev.currentSamples will be updated to the correct value within the ev.eval call. - val, ws := ev.eval(aggExpr.Expr) - warnings.Merge(ws) - inputMatrix := val.(Matrix) - - // Keep a copy of the original point slice so that it can be returned to the pool. - origMatrix := inputMatrix - - biggestLen := len(inputMatrix) enh := &EvalNodeHelper{} - seriess := make(map[uint64]Series, biggestLen) // Output series by series hash. tempNumSamples := ev.currentSamples // Create a mapping from input series to output groups. @@ -1325,6 +1315,8 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping seriesToResult[si] = index } + seriess := make(map[uint64]Series, len(inputMatrix)) // Output series by series hash. + for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { if err := contextDone(ev.ctx, "expression evaluation"); err != nil { ev.error(err) @@ -1340,8 +1332,6 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { - ev.currentSamples = originalNumSamples + result.TotalSamples() - ev.samplesStats.UpdatePeak(ev.currentSamples) return result, warnings } if ev.currentSamples > ev.maxSamples { @@ -1349,18 +1339,11 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping } } - // Reuse the original point slice. - for _, s := range origMatrix { - putFPointSlice(s.Floats) - putHPointSlice(s.Histograms) - } // Assemble the output matrix. By the time we get here we know we don't have too many samples. mat := make(Matrix, 0, len(seriess)) for _, ss := range seriess { mat = append(mat, ss) } - ev.currentSamples = originalNumSamples + mat.TotalSamples() - ev.samplesStats.UpdatePeak(ev.currentSamples) return mat, warnings } @@ -1434,7 +1417,26 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, annotations.Annotatio }, e.Expr) } - return ev.rangeEvalAgg(e, sortedGrouping) + var warnings annotations.Annotations + originalNumSamples := ev.currentSamples + // param is the number k for topk/bottomk, or q for quantile. + var fParam float64 + if param != nil { + val, ws := ev.eval(param) + warnings.Merge(ws) + fParam = val.(Matrix)[0].Floats[0].F + } + // Now fetch the data to be aggregated. + val, ws := ev.eval(e.Expr) + warnings.Merge(ws) + inputMatrix := val.(Matrix) + + result, ws := ev.rangeEvalAgg(e, sortedGrouping, inputMatrix, fParam) + warnings.Merge(ws) + ev.currentSamples = originalNumSamples + result.TotalSamples() + ev.samplesStats.UpdatePeak(ev.currentSamples) + + return result, warnings case *parser.Call: call := FunctionCalls[e.Func.Name] From 2f03acbafc08dd83cc8a5c3d94b2f071bb34f809 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 5 Apr 2024 12:22:44 +0100 Subject: [PATCH 230/253] promql: refactor: split topk/bottomk from sum/avg/etc They aggregate results in different ways. topk/bottomk don't consider histograms so can simplify data collection. Signed-off-by: Bryan Boreham --- promql/engine.go | 294 ++++++++++++++++++++++++++++------------------- 1 file changed, 174 insertions(+), 120 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 770550dac1..22428e12c7 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1299,6 +1299,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping groupToResultIndex := make(map[uint64]int) seriesToResult := make([]int, len(inputMatrix)) orderedResult := make([]*groupedAggregation, 0, 16) + var result Matrix for si, series := range inputMatrix { var groupingKey uint64 @@ -1306,8 +1307,11 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping index, ok := groupToResultIndex[groupingKey] // Add a new group if it doesn't exist. if !ok { - m := generateGroupingLabels(enh, series.Metric, aggExpr.Without, sortedGrouping) - newAgg := &groupedAggregation{labels: m} + if aggExpr.Op != parser.TOPK && aggExpr.Op != parser.BOTTOMK { + m := generateGroupingLabels(enh, series.Metric, aggExpr.Without, sortedGrouping) + result = append(result, Series{Metric: m}) + } + newAgg := &groupedAggregation{} index = len(orderedResult) groupToResultIndex[groupingKey] = index orderedResult = append(orderedResult, newAgg) @@ -1315,7 +1319,11 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping seriesToResult[si] = index } - seriess := make(map[uint64]Series, len(inputMatrix)) // Output series by series hash. + var seriess map[uint64]Series + switch aggExpr.Op { + case parser.TOPK, parser.BOTTOMK: + seriess = make(map[uint64]Series, len(inputMatrix)) // Output series by series hash. + } for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { if err := contextDone(ev.ctx, "expression evaluation"); err != nil { @@ -1326,25 +1334,44 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping // Make the function call. enh.Ts = ts - result, ws := ev.aggregation(aggExpr, param, inputMatrix, seriesToResult, orderedResult, enh, seriess) + var ws annotations.Annotations + switch aggExpr.Op { + case parser.TOPK, parser.BOTTOMK: + result, ws = ev.aggregationK(aggExpr, param, inputMatrix, seriesToResult, orderedResult, enh, seriess) + // If this could be an instant query, shortcut so as not to change sort order. + if ev.endTimestamp == ev.startTimestamp { + return result, ws + } + default: + ws = ev.aggregation(aggExpr, param, inputMatrix, result, seriesToResult, orderedResult, enh) + } warnings.Merge(ws) - // If this could be an instant query, shortcut so as not to change sort order. - if ev.endTimestamp == ev.startTimestamp { - return result, warnings - } if ev.currentSamples > ev.maxSamples { ev.error(ErrTooManySamples(env)) } } // Assemble the output matrix. By the time we get here we know we don't have too many samples. - mat := make(Matrix, 0, len(seriess)) - for _, ss := range seriess { - mat = append(mat, ss) + switch aggExpr.Op { + case parser.TOPK, parser.BOTTOMK: + result = make(Matrix, 0, len(seriess)) + for _, ss := range seriess { + result = append(result, ss) + } + default: + // Remove empty result rows. + dst := 0 + for _, series := range result { + if len(series.Floats) > 0 || len(series.Histograms) > 0 { + result[dst] = series + dst++ + } + } + result = result[:dst] } - return mat, warnings + return result, warnings } // evalSubquery evaluates given SubqueryExpr and returns an equivalent @@ -2698,25 +2725,14 @@ type groupedAggregation struct { reverseHeap vectorByReverseValueHeap } -// aggregation evaluates an aggregation operation on a Vector. The provided grouping labels -// must be sorted. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { +// aggregation evaluates sum, avg, count, stdvar, stddev or quantile at one timestep on inputMatrix. +// These functions produce one output series for each group specified in the expression, with just the labels from `by(...)`. +// outputMatrix should be already populated with grouping labels; groups is one-to-one with outputMatrix. +// seriesToResult maps inputMatrix indexes to outputMatrix indexes. +func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix, outputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper) annotations.Annotations { op := e.Op var annos annotations.Annotations seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. - k := 1 - if op == parser.TOPK || op == parser.BOTTOMK { - if !convertibleToInt64(q) { - ev.errorf("Scalar value %v overflows int64", q) - } - k = int(q) - if k > len(inputMatrix) { - k = len(inputMatrix) - } - if k < 1 { - return nil, annos - } - } if op == parser.QUANTILE { if math.IsNaN(q) || q < 0 || q > 1 { annos.Add(annotations.NewInvalidQuantileWarning(q, e.Param.PositionRange())) @@ -2733,7 +2749,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix // Initialize this group if it's the first time we've seen it. if !seen[seriesToResult[si]] { *group = groupedAggregation{ - labels: group.labels, floatValue: s.F, floatMean: s.F, groupCount: 1, @@ -2754,18 +2769,12 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix switch op { case parser.STDVAR, parser.STDDEV: group.floatValue = 0 - case parser.TOPK, parser.QUANTILE: - group.heap = make(vectorByValueHeap, 1, k) + case parser.QUANTILE: + group.heap = make(vectorByValueHeap, 1) group.heap[0] = Sample{ F: s.F, Metric: s.Metric, } - case parser.BOTTOMK: - group.reverseHeap = make(vectorByReverseValueHeap, 1, k) - group.reverseHeap[0] = Sample{ - F: s.F, - Metric: s.Metric, - } case parser.GROUP: group.floatValue = 1 } @@ -2848,44 +2857,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix group.floatValue += delta * (s.F - group.floatMean) } - case parser.TOPK: - // We build a heap of up to k elements, with the smallest element at heap[0]. - switch { - case len(group.heap) < k: - heap.Push(&group.heap, &Sample{ - F: s.F, - Metric: s.Metric, - }) - 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. - group.heap[0] = Sample{ - F: s.F, - Metric: s.Metric, - } - if k > 1 { - heap.Fix(&group.heap, 0) // Maintain the heap invariant. - } - } - - case parser.BOTTOMK: - // We build a heap of up to k elements, with the biggest element at heap[0]. - switch { - case len(group.reverseHeap) < k: - heap.Push(&group.reverseHeap, &Sample{ - F: s.F, - Metric: s.Metric, - }) - case group.reverseHeap[0].F > s.F || (math.IsNaN(group.reverseHeap[0].F) && !math.IsNaN(s.F)): - // This new element is smaller than the previous biggest element - overwrite that. - group.reverseHeap[0] = Sample{ - F: s.F, - Metric: s.Metric, - } - if k > 1 { - heap.Fix(&group.reverseHeap, 0) // Maintain the heap invariant. - } - } - case parser.QUANTILE: group.heap = append(group.heap, s) @@ -2894,32 +2865,9 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix } } - // Construct the result from the aggregated groups. + // Construct the output matrix from the aggregated groups. numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 - var mat Matrix - if ev.endTimestamp == ev.startTimestamp { - mat = make(Matrix, 0, len(orderedResult)) - } - add := func(lbls labels.Labels, f float64, h *histogram.FloatHistogram) { - // If this could be an instant query, add directly to the matrix so the result is in consistent order. - if ev.endTimestamp == ev.startTimestamp { - if h == nil { - mat = append(mat, Series{Metric: lbls, Floats: []FPoint{{T: enh.Ts, F: f}}}) - } else { - mat = append(mat, Series{Metric: lbls, Histograms: []HPoint{{T: enh.Ts, H: h}}}) - } - } else { - // Otherwise the results are added into seriess elements. - hash := lbls.Hash() - ss, ok := seriess[hash] - if !ok { - ss = Series{Metric: lbls} - } - addToSeries(&ss, enh.Ts, f, h, numSteps) - seriess[hash] = ss - } - } for ri, aggr := range orderedResult { if !seen[ri] { continue @@ -2946,26 +2894,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix case parser.STDDEV: aggr.floatValue = math.Sqrt(aggr.floatValue / float64(aggr.groupCount)) - case parser.TOPK: - // The heap keeps the lowest value on top, so reverse it. - if len(aggr.heap) > 1 { - sort.Sort(sort.Reverse(aggr.heap)) - } - for _, v := range aggr.heap { - add(v.Metric, v.F, nil) - } - continue // Bypass default append. - - case parser.BOTTOMK: - // The heap keeps the highest value on top, so reverse it. - if len(aggr.reverseHeap) > 1 { - sort.Sort(sort.Reverse(aggr.reverseHeap)) - } - for _, v := range aggr.reverseHeap { - add(v.Metric, v.F, nil) - } - continue // Bypass default append. - case parser.QUANTILE: aggr.floatValue = quantile(q, aggr.heap) @@ -2982,7 +2910,133 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix // For other aggregations, we already have the right value. } - add(aggr.labels, aggr.floatValue, aggr.histogramValue) + ss := &outputMatrix[ri] + addToSeries(ss, enh.Ts, aggr.floatValue, aggr.histogramValue, numSteps) + } + + return annos +} + +// aggregationK evaluates topk or bottomk at one timestep on inputMatrix. +// Output that has the same labels as the input, but just k of them per group. +// seriesToResult maps inputMatrix indexes to groups indexes. +// For an instant query, returns a Matrix in descending order for topk or ascending for bottomk. +// For a range query, aggregates output in the seriess map. +func (ev *evaluator) aggregationK(e *parser.AggregateExpr, q float64, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { + op := e.Op + var annos annotations.Annotations + seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. + if !convertibleToInt64(q) { + ev.errorf("Scalar value %v overflows int64", q) + } + k := int(q) + if k > len(inputMatrix) { + k = len(inputMatrix) + } + if k < 1 { + return nil, annos + } + + for si := range inputMatrix { + s, ok := ev.nextSample(enh.Ts, inputMatrix, si) + if !ok { + continue + } + + group := orderedResult[seriesToResult[si]] + // Initialize this group if it's the first time we've seen it. + if !seen[seriesToResult[si]] { + *group = groupedAggregation{} + + switch op { + case parser.TOPK: + group.heap = make(vectorByValueHeap, 1, k) + group.heap[0] = s + case parser.BOTTOMK: + group.reverseHeap = make(vectorByReverseValueHeap, 1, k) + group.reverseHeap[0] = s + } + seen[seriesToResult[si]] = true + continue + } + + switch op { + case parser.TOPK: + // We build a heap of up to k elements, with the smallest element at heap[0]. + switch { + case 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. + group.heap[0] = s + if k > 1 { + heap.Fix(&group.heap, 0) // Maintain the heap invariant. + } + } + + case parser.BOTTOMK: + // We build a heap of up to k elements, with the biggest element at heap[0]. + switch { + case len(group.reverseHeap) < k: + heap.Push(&group.reverseHeap, &s) + case group.reverseHeap[0].F > s.F || (math.IsNaN(group.reverseHeap[0].F) && !math.IsNaN(s.F)): + // This new element is smaller than the previous biggest element - overwrite that. + group.reverseHeap[0] = s + if k > 1 { + heap.Fix(&group.reverseHeap, 0) // Maintain the heap invariant. + } + } + + default: + panic(fmt.Errorf("expected aggregation operator but got %q", op)) + } + } + + // Construct the result from the aggregated groups. + numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 + var mat Matrix + if ev.endTimestamp == ev.startTimestamp { + mat = make(Matrix, 0, len(orderedResult)) + } + + add := func(lbls labels.Labels, f float64) { + // If this could be an instant query, add directly to the matrix so the result is in consistent order. + if ev.endTimestamp == ev.startTimestamp { + mat = append(mat, Series{Metric: lbls, Floats: []FPoint{{T: enh.Ts, F: f}}}) + } else { + // Otherwise the results are added into seriess elements. + hash := lbls.Hash() + ss, ok := seriess[hash] + if !ok { + ss = Series{Metric: lbls} + } + addToSeries(&ss, enh.Ts, f, nil, numSteps) + seriess[hash] = ss + } + } + for ri, aggr := range orderedResult { + if !seen[ri] { + continue + } + switch op { + case parser.TOPK: + // The heap keeps the lowest value on top, so reverse it. + if len(aggr.heap) > 1 { + sort.Sort(sort.Reverse(aggr.heap)) + } + for _, v := range aggr.heap { + add(v.Metric, v.F) + } + + case parser.BOTTOMK: + // The heap keeps the highest value on top, so reverse it. + if len(aggr.reverseHeap) > 1 { + sort.Sort(sort.Reverse(aggr.reverseHeap)) + } + for _, v := range aggr.reverseHeap { + add(v.Metric, v.F) + } + } } return mat, annos From 526ce4ee7ad8cd2802590596801f2be8821faa63 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 4 Mar 2024 21:05:00 +0000 Subject: [PATCH 231/253] promql: simplify data collection in aggregations We don't need a Sample, just the float and histogram values. Signed-off-by: Bryan Boreham --- promql/engine.go | 49 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 22428e12c7..a38cdf218e 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2740,7 +2740,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix } for si := range inputMatrix { - s, ok := ev.nextSample(enh.Ts, inputMatrix, si) + f, h, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) if !ok { continue } @@ -2749,18 +2749,18 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix // Initialize this group if it's the first time we've seen it. if !seen[seriesToResult[si]] { *group = groupedAggregation{ - floatValue: s.F, - floatMean: s.F, + floatValue: f, + floatMean: f, groupCount: 1, } switch { - case s.H == nil: + case h == nil: group.hasFloat = true case op == parser.SUM: - group.histogramValue = s.H.Copy() + group.histogramValue = h.Copy() group.hasHistogram = true case op == parser.AVG: - group.histogramMean = s.H.Copy() + group.histogramMean = h.Copy() group.hasHistogram = true case op == parser.STDVAR || op == parser.STDDEV: group.groupCount = 0 @@ -2771,10 +2771,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix group.floatValue = 0 case parser.QUANTILE: group.heap = make(vectorByValueHeap, 1) - group.heap[0] = Sample{ - F: s.F, - Metric: s.Metric, - } + group.heap[0] = Sample{F: f} case parser.GROUP: group.floatValue = 1 } @@ -2784,25 +2781,25 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix switch op { case parser.SUM: - if s.H != nil { + if h != nil { group.hasHistogram = true if group.histogramValue != nil { - group.histogramValue.Add(s.H) + group.histogramValue.Add(h) } // Otherwise the aggregation contained floats // previously and will be invalid anyway. No // point in copying the histogram in that case. } else { group.hasFloat = true - group.floatValue += s.F + group.floatValue += f } case parser.AVG: group.groupCount++ - if s.H != nil { + if h != nil { group.hasHistogram = true if group.histogramMean != nil { - left := s.H.Copy().Div(float64(group.groupCount)) + left := h.Copy().Div(float64(group.groupCount)) right := group.histogramMean.Copy().Div(float64(group.groupCount)) toAdd := left.Sub(right) group.histogramMean.Add(toAdd) @@ -2813,13 +2810,13 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix } else { group.hasFloat = true if math.IsInf(group.floatMean, 0) { - if math.IsInf(s.F, 0) && (group.floatMean > 0) == (s.F > 0) { + if math.IsInf(f, 0) && (group.floatMean > 0) == (f > 0) { // The `floatMean` and `s.F` values are `Inf` of the same sign. They // can't be subtracted, but the value of `floatMean` is correct // already. break } - if !math.IsInf(s.F, 0) && !math.IsNaN(s.F) { + if !math.IsInf(f, 0) && !math.IsNaN(f) { // At this stage, the mean is an infinite. If the added // value is neither an Inf or a Nan, we can keep that mean // value. @@ -2830,35 +2827,35 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix } } // Divide each side of the `-` by `group.groupCount` to avoid float64 overflows. - group.floatMean += s.F/float64(group.groupCount) - group.floatMean/float64(group.groupCount) + group.floatMean += f/float64(group.groupCount) - group.floatMean/float64(group.groupCount) } case parser.GROUP: // Do nothing. Required to avoid the panic in `default:` below. case parser.MAX: - if group.floatValue < s.F || math.IsNaN(group.floatValue) { - group.floatValue = s.F + if group.floatValue < f || math.IsNaN(group.floatValue) { + group.floatValue = f } case parser.MIN: - if group.floatValue > s.F || math.IsNaN(group.floatValue) { - group.floatValue = s.F + if group.floatValue > f || math.IsNaN(group.floatValue) { + group.floatValue = f } case parser.COUNT: group.groupCount++ case parser.STDVAR, parser.STDDEV: - if s.H == nil { // Ignore native histograms. + if h == nil { // Ignore native histograms. group.groupCount++ - delta := s.F - group.floatMean + delta := f - group.floatMean group.floatMean += delta / float64(group.groupCount) - group.floatValue += delta * (s.F - group.floatMean) + group.floatValue += delta * (f - group.floatMean) } case parser.QUANTILE: - group.heap = append(group.heap, s) + group.heap = append(group.heap, Sample{F: f}) default: panic(fmt.Errorf("expected aggregation operator but got %q", op)) From 4584f67e1706b5fa15bc4436c158fec701ae9402 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 9 Mar 2024 11:31:46 +0000 Subject: [PATCH 232/253] promql: inline nextSample function Move Sample out of loop to reduce allocations, otherwise it escapes to the heap. Signed-off-by: Bryan Boreham --- promql/engine.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index a38cdf218e..592114db2b 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2921,6 +2921,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix // For a range query, aggregates output in the seriess map. func (ev *evaluator) aggregationK(e *parser.AggregateExpr, q float64, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { op := e.Op + var s Sample var annos annotations.Annotations seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. if !convertibleToInt64(q) { @@ -2935,10 +2936,11 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, q float64, inputMatri } for si := range inputMatrix { - s, ok := ev.nextSample(enh.Ts, inputMatrix, si) + f, _, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) if !ok { continue } + s = Sample{Metric: inputMatrix[si].Metric, F: f} group := orderedResult[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. @@ -3111,15 +3113,6 @@ func (ev *evaluator) nextValues(ts int64, series *Series) (f float64, h *histogr return f, h, true } -func (ev *evaluator) nextSample(ts int64, inputMatrix Matrix, si int) (Sample, bool) { - f, h, ok := ev.nextValues(ts, &inputMatrix[si]) - ev.currentSamples++ - if ev.currentSamples > ev.maxSamples { - ev.error(ErrTooManySamples(env)) - } - return Sample{Metric: inputMatrix[si].Metric, F: f, H: h, T: ts}, ok -} - // groupingKey builds and returns the grouping key for the given metric and // grouping labels. func generateGroupingKey(metric labels.Labels, grouping []string, without bool, buf []byte) (uint64, []byte) { From 185290a0d2f5908665a7d59710850ce2fdf59cf2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 8 Mar 2024 17:53:19 +0000 Subject: [PATCH 233/253] promql: pull checking of q and k out of loop Signed-off-by: Bryan Boreham --- promql/engine.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 592114db2b..0dd33a7f94 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1319,10 +1319,25 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping seriesToResult[si] = index } + var k int var seriess map[uint64]Series switch aggExpr.Op { case parser.TOPK, parser.BOTTOMK: + if !convertibleToInt64(param) { + ev.errorf("Scalar value %v overflows int64", param) + } + k = int(param) + if k > len(inputMatrix) { + k = len(inputMatrix) + } + if k < 1 { + return nil, warnings + } seriess = make(map[uint64]Series, len(inputMatrix)) // Output series by series hash. + case parser.QUANTILE: + if math.IsNaN(param) || param < 0 || param > 1 { + warnings.Add(annotations.NewInvalidQuantileWarning(param, aggExpr.Param.PositionRange())) + } } for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { @@ -1337,7 +1352,7 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping var ws annotations.Annotations switch aggExpr.Op { case parser.TOPK, parser.BOTTOMK: - result, ws = ev.aggregationK(aggExpr, param, inputMatrix, seriesToResult, orderedResult, enh, seriess) + result, ws = ev.aggregationK(aggExpr, k, inputMatrix, seriesToResult, orderedResult, enh, seriess) // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { return result, ws @@ -2733,11 +2748,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix op := e.Op var annos annotations.Annotations seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. - if op == parser.QUANTILE { - if math.IsNaN(q) || q < 0 || q > 1 { - annos.Add(annotations.NewInvalidQuantileWarning(q, e.Param.PositionRange())) - } - } for si := range inputMatrix { f, h, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) @@ -2919,21 +2929,11 @@ 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. // For a range query, aggregates output in the seriess map. -func (ev *evaluator) aggregationK(e *parser.AggregateExpr, q float64, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { +func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { op := e.Op var s Sample var annos annotations.Annotations seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. - if !convertibleToInt64(q) { - ev.errorf("Scalar value %v overflows int64", q) - } - k := int(q) - if k > len(inputMatrix) { - k = len(inputMatrix) - } - if k < 1 { - return nil, annos - } for si := range inputMatrix { f, _, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) From 2cf3c9de8f3fc0d88b42c13b072c7d3516de37e9 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 5 Apr 2024 14:39:29 +0100 Subject: [PATCH 234/253] promql: store labels per-group only for count_values This saves memory in other kinds of aggregation. We don't need `orderedResult` in `aggregationCountValues`; the ordering is not guaranteed. Signed-off-by: Bryan Boreham --- promql/engine.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 0dd33a7f94..b81617a1d1 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2730,7 +2730,6 @@ func vectorElemBinop(op parser.ItemType, lhs, rhs float64, hlhs, hrhs *histogram type groupedAggregation struct { hasFloat bool // Has at least 1 float64 sample aggregated. hasHistogram bool // Has at least 1 histogram sample aggregated. - labels labels.Labels floatValue float64 histogramValue *histogram.FloatHistogram floatMean float64 @@ -3044,8 +3043,11 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma // aggregationK evaluates count_values on vec. // Outputs as many series per group as there are values in the input. func (ev *evaluator) aggregationCountValues(e *parser.AggregateExpr, grouping []string, valueLabel string, vec Vector, enh *EvalNodeHelper) (Vector, annotations.Annotations) { - result := map[uint64]*groupedAggregation{} - orderedResult := []*groupedAggregation{} + type groupCount struct { + labels labels.Labels + count int + } + result := map[uint64]*groupCount{} var buf []byte for _, s := range vec { @@ -3062,24 +3064,21 @@ func (ev *evaluator) aggregationCountValues(e *parser.AggregateExpr, grouping [] group, ok := result[groupingKey] // Add a new group if it doesn't exist. if !ok { - newAgg := &groupedAggregation{ - labels: generateGroupingLabels(enh, metric, e.Without, grouping), - groupCount: 1, + result[groupingKey] = &groupCount{ + labels: generateGroupingLabels(enh, metric, e.Without, grouping), + count: 1, } - - result[groupingKey] = newAgg - orderedResult = append(orderedResult, newAgg) continue } - group.groupCount++ + group.count++ } // Construct the result Vector from the aggregated groups. - for _, aggr := range orderedResult { + for _, aggr := range result { enh.Out = append(enh.Out, Sample{ Metric: aggr.labels, - F: float64(aggr.groupCount), + F: float64(aggr.count), }) } return enh.Out, nil From 5e3914a27cfbd32f4d54177ae896ccb65fe9cc4e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 9 Mar 2024 10:23:31 +0000 Subject: [PATCH 235/253] promql: remove histogramMean from groupedAggregation Re-use histogramValue since we don't need them separately. Tidy up initialization. Signed-off-by: Bryan Boreham --- promql/engine.go | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index b81617a1d1..4230bff878 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2733,7 +2733,6 @@ type groupedAggregation struct { floatValue float64 histogramValue *histogram.FloatHistogram floatMean float64 - histogramMean *histogram.FloatHistogram groupCount int heap vectorByValueHeap reverseHeap vectorByReverseValueHeap @@ -2762,20 +2761,14 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix floatMean: f, groupCount: 1, } - switch { - case h == nil: - group.hasFloat = true - case op == parser.SUM: - group.histogramValue = h.Copy() - group.hasHistogram = true - case op == parser.AVG: - group.histogramMean = h.Copy() - group.hasHistogram = true - case op == parser.STDVAR || op == parser.STDDEV: - group.groupCount = 0 - } - switch op { + case parser.SUM, parser.AVG: + if h == nil { + group.hasFloat = true + } else { + group.histogramValue = h.Copy() + group.hasHistogram = true + } case parser.STDVAR, parser.STDDEV: group.floatValue = 0 case parser.QUANTILE: @@ -2807,11 +2800,11 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix group.groupCount++ if h != nil { group.hasHistogram = true - if group.histogramMean != nil { + if group.histogramValue != nil { left := h.Copy().Div(float64(group.groupCount)) - right := group.histogramMean.Copy().Div(float64(group.groupCount)) + right := group.histogramValue.Copy().Div(float64(group.groupCount)) toAdd := left.Sub(right) - group.histogramMean.Add(toAdd) + group.histogramValue.Add(toAdd) } // Otherwise the aggregation contained floats // previously and will be invalid anyway. No @@ -2886,7 +2879,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix continue } if aggr.hasHistogram { - aggr.histogramValue = aggr.histogramMean.Compact(0) + aggr.histogramValue = aggr.histogramValue.Compact(0) } else { aggr.floatValue = aggr.floatMean } From cfbeb6681bfb2a7d51e3ce3f6ef891097547bf10 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 9 Mar 2024 10:51:16 +0000 Subject: [PATCH 236/253] promql: re-use one heap for topk and bottomk Slightly ugly casting saves memory. Signed-off-by: Bryan Boreham --- promql/engine.go | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 4230bff878..2819b36d02 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2735,7 +2735,6 @@ type groupedAggregation struct { floatMean float64 groupCount int heap vectorByValueHeap - reverseHeap vectorByReverseValueHeap } // aggregation evaluates sum, avg, count, stdvar, stddev or quantile at one timestep on inputMatrix. @@ -2937,16 +2936,10 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma group := orderedResult[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. if !seen[seriesToResult[si]] { - *group = groupedAggregation{} - - switch op { - case parser.TOPK: - group.heap = make(vectorByValueHeap, 1, k) - group.heap[0] = s - case parser.BOTTOMK: - group.reverseHeap = make(vectorByReverseValueHeap, 1, k) - group.reverseHeap[0] = s + *group = groupedAggregation{ + heap: make(vectorByValueHeap, 1, k), } + group.heap[0] = s seen[seriesToResult[si]] = true continue } @@ -2968,13 +2961,13 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma case parser.BOTTOMK: // We build a heap of up to k elements, with the biggest element at heap[0]. switch { - case len(group.reverseHeap) < k: - heap.Push(&group.reverseHeap, &s) - case group.reverseHeap[0].F > s.F || (math.IsNaN(group.reverseHeap[0].F) && !math.IsNaN(s.F)): + case 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. - group.reverseHeap[0] = s + group.heap[0] = s if k > 1 { - heap.Fix(&group.reverseHeap, 0) // Maintain the heap invariant. + heap.Fix((*vectorByReverseValueHeap)(&group.heap), 0) // Maintain the heap invariant. } } @@ -3021,10 +3014,10 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma case parser.BOTTOMK: // The heap keeps the highest value on top, so reverse it. - if len(aggr.reverseHeap) > 1 { - sort.Sort(sort.Reverse(aggr.reverseHeap)) + if len(aggr.heap) > 1 { + sort.Sort(sort.Reverse((*vectorByReverseValueHeap)(&aggr.heap))) } - for _, v := range aggr.reverseHeap { + for _, v := range aggr.heap { add(v.Metric, v.F) } } From 7499d90913725e1d95f231a8584be34a10fafbce Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 9 Mar 2024 11:06:46 +0000 Subject: [PATCH 237/253] promql: remove pointer to aggregation groups Just allocate in one slice. Signed-off-by: Bryan Boreham --- promql/engine.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index 2819b36d02..bd4c7ed467 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1298,9 +1298,9 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping buf := make([]byte, 0, 1024) groupToResultIndex := make(map[uint64]int) seriesToResult := make([]int, len(inputMatrix)) - orderedResult := make([]*groupedAggregation, 0, 16) var result Matrix + groupCount := 0 for si, series := range inputMatrix { var groupingKey uint64 groupingKey, buf = generateGroupingKey(series.Metric, sortedGrouping, aggExpr.Without, buf) @@ -1311,13 +1311,13 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping m := generateGroupingLabels(enh, series.Metric, aggExpr.Without, sortedGrouping) result = append(result, Series{Metric: m}) } - newAgg := &groupedAggregation{} - index = len(orderedResult) + index = groupCount groupToResultIndex[groupingKey] = index - orderedResult = append(orderedResult, newAgg) + groupCount++ } seriesToResult[si] = index } + groups := make([]groupedAggregation, groupCount) var k int var seriess map[uint64]Series @@ -1352,13 +1352,13 @@ func (ev *evaluator) rangeEvalAgg(aggExpr *parser.AggregateExpr, sortedGrouping var ws annotations.Annotations switch aggExpr.Op { case parser.TOPK, parser.BOTTOMK: - result, ws = ev.aggregationK(aggExpr, k, inputMatrix, seriesToResult, orderedResult, enh, seriess) + result, ws = ev.aggregationK(aggExpr, k, inputMatrix, seriesToResult, groups, enh, seriess) // If this could be an instant query, shortcut so as not to change sort order. if ev.endTimestamp == ev.startTimestamp { return result, ws } default: - ws = ev.aggregation(aggExpr, param, inputMatrix, result, seriesToResult, orderedResult, enh) + ws = ev.aggregation(aggExpr, param, inputMatrix, result, seriesToResult, groups, enh) } warnings.Merge(ws) @@ -2741,10 +2741,10 @@ type groupedAggregation struct { // These functions produce one output series for each group specified in the expression, with just the labels from `by(...)`. // outputMatrix should be already populated with grouping labels; groups is one-to-one with outputMatrix. // seriesToResult maps inputMatrix indexes to outputMatrix indexes. -func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix, outputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper) annotations.Annotations { +func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix, outputMatrix Matrix, seriesToResult []int, groups []groupedAggregation, enh *EvalNodeHelper) annotations.Annotations { op := e.Op var annos annotations.Annotations - seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. + seen := make([]bool, len(groups)) // Which output groups were seen in the input at this timestamp. for si := range inputMatrix { f, h, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) @@ -2752,7 +2752,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix continue } - group := orderedResult[seriesToResult[si]] + group := &groups[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. if !seen[seriesToResult[si]] { *group = groupedAggregation{ @@ -2866,7 +2866,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix // Construct the output matrix from the aggregated groups. numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 - for ri, aggr := range orderedResult { + for ri, aggr := range groups { if !seen[ri] { continue } @@ -2920,11 +2920,11 @@ 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. // For a range query, aggregates output in the seriess map. -func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Matrix, seriesToResult []int, orderedResult []*groupedAggregation, enh *EvalNodeHelper, seriess map[uint64]Series) (Matrix, annotations.Annotations) { +func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, 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 - seen := make([]bool, len(orderedResult)) // Which output groups were seen in the input at this timestamp. + seen := make([]bool, len(groups)) // Which output groups were seen in the input at this timestamp. for si := range inputMatrix { f, _, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) @@ -2933,7 +2933,7 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma } s = Sample{Metric: inputMatrix[si].Metric, F: f} - group := orderedResult[seriesToResult[si]] + group := &groups[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. if !seen[seriesToResult[si]] { *group = groupedAggregation{ @@ -2980,7 +2980,7 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 var mat Matrix if ev.endTimestamp == ev.startTimestamp { - mat = make(Matrix, 0, len(orderedResult)) + mat = make(Matrix, 0, len(groups)) } add := func(lbls labels.Labels, f float64) { @@ -2998,7 +2998,7 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma seriess[hash] = ss } } - for ri, aggr := range orderedResult { + for ri, aggr := range groups { if !seen[ri] { continue } From 0ac927515b193abdc65575f8a71a1138a1debf80 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 9 Mar 2024 11:24:32 +0000 Subject: [PATCH 238/253] promql: move group-seen into group struct Save allocating an auxilliary array. Signed-off-by: Bryan Boreham --- promql/engine.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index bd4c7ed467..c23964ed82 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2728,6 +2728,7 @@ func vectorElemBinop(op parser.ItemType, lhs, rhs float64, hlhs, hrhs *histogram } type groupedAggregation struct { + seen bool // Was this output groups seen in the input at this timestamp. hasFloat bool // Has at least 1 float64 sample aggregated. hasHistogram bool // Has at least 1 histogram sample aggregated. floatValue float64 @@ -2744,7 +2745,9 @@ type groupedAggregation struct { func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix, outputMatrix Matrix, seriesToResult []int, groups []groupedAggregation, enh *EvalNodeHelper) annotations.Annotations { op := e.Op var annos annotations.Annotations - seen := make([]bool, len(groups)) // Which output groups were seen in the input at this timestamp. + for i := range groups { + groups[i].seen = false + } for si := range inputMatrix { f, h, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) @@ -2754,8 +2757,9 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix group := &groups[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. - if !seen[seriesToResult[si]] { + if !group.seen { *group = groupedAggregation{ + seen: true, floatValue: f, floatMean: f, groupCount: 1, @@ -2776,7 +2780,6 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix case parser.GROUP: group.floatValue = 1 } - seen[seriesToResult[si]] = true continue } @@ -2867,7 +2870,7 @@ func (ev *evaluator) aggregation(e *parser.AggregateExpr, q float64, inputMatrix numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 for ri, aggr := range groups { - if !seen[ri] { + if !aggr.seen { continue } switch op { @@ -2924,7 +2927,9 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma op := e.Op var s Sample var annos annotations.Annotations - seen := make([]bool, len(groups)) // Which output groups were seen in the input at this timestamp. + for i := range groups { + groups[i].seen = false + } for si := range inputMatrix { f, _, ok := ev.nextValues(enh.Ts, &inputMatrix[si]) @@ -2935,12 +2940,12 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma group := &groups[seriesToResult[si]] // Initialize this group if it's the first time we've seen it. - if !seen[seriesToResult[si]] { + if !group.seen { *group = groupedAggregation{ + seen: true, heap: make(vectorByValueHeap, 1, k), } group.heap[0] = s - seen[seriesToResult[si]] = true continue } @@ -2998,8 +3003,8 @@ func (ev *evaluator) aggregationK(e *parser.AggregateExpr, k int, inputMatrix Ma seriess[hash] = ss } } - for ri, aggr := range groups { - if !seen[ri] { + for _, aggr := range groups { + if !aggr.seen { continue } switch op { From 12961c6a373fe9d19f97a7bff9cac6587896eec2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 5 Apr 2024 15:40:07 +0100 Subject: [PATCH 239/253] promql: refactor: eliminate one 'else' Signed-off-by: Bryan Boreham --- promql/engine.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index c23964ed82..b8a8ea0959 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -3081,12 +3081,12 @@ func addToSeries(ss *Series, ts int64, f float64, h *histogram.FloatHistogram, n ss.Floats = getFPointSlice(numSteps) } ss.Floats = append(ss.Floats, FPoint{T: ts, F: f}) - } else { - if ss.Histograms == nil { - ss.Histograms = getHPointSlice(numSteps) - } - ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: h}) + return } + if ss.Histograms == nil { + ss.Histograms = getHPointSlice(numSteps) + } + ss.Histograms = append(ss.Histograms, HPoint{T: ts, H: h}) } func (ev *evaluator) nextValues(ts int64, series *Series) (f float64, h *histogram.FloatHistogram, b bool) { From c755fa99357b9e81e4a2979365865c63fe020710 Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Fri, 5 Apr 2024 16:00:52 +0000 Subject: [PATCH 240/253] support unregistering scrape manager metrics Signed-off-by: David Ashpole --- scrape/manager.go | 5 +++++ scrape/manager_test.go | 13 +++++++++++++ scrape/metrics.go | 29 ++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/scrape/manager.go b/scrape/manager.go index 3ad315a50a..e805fd43af 100644 --- a/scrape/manager.go +++ b/scrape/manager.go @@ -129,6 +129,11 @@ func (m *Manager) Run(tsets <-chan map[string][]*targetgroup.Group) error { } } +// UnregisterMetrics unregisters manager metrics. +func (m *Manager) UnregisterMetrics() { + m.metrics.Unregister() +} + func (m *Manager) reloader() { reloadIntervalDuration := m.opts.DiscoveryReloadInterval if reloadIntervalDuration < model.Duration(5*time.Second) { diff --git a/scrape/manager_test.go b/scrape/manager_test.go index f90fd0ce66..51af45f8cf 100644 --- a/scrape/manager_test.go +++ b/scrape/manager_test.go @@ -857,3 +857,16 @@ func getResultFloats(app *collectResultAppender, expectedMetricName string) (res } return result } + +func TestUnregisterMetrics(t *testing.T) { + reg := prometheus.NewRegistry() + // Check that all metrics can be unregistered, allowing a second manager to be created. + for i := 0; i < 2; i++ { + opts := Options{} + manager, err := NewManager(&opts, nil, nil, reg) + require.NotNil(t, manager) + require.NoError(t, err) + // Unregister all metrics. + manager.UnregisterMetrics() + } +} diff --git a/scrape/metrics.go b/scrape/metrics.go index 7082bc743b..b67d0686b6 100644 --- a/scrape/metrics.go +++ b/scrape/metrics.go @@ -20,6 +20,7 @@ import ( ) type scrapeMetrics struct { + reg prometheus.Registerer // Used by Manager. targetMetadataCache *MetadataMetricsCollector targetScrapePools prometheus.Counter @@ -54,7 +55,7 @@ type scrapeMetrics struct { } func newScrapeMetrics(reg prometheus.Registerer) (*scrapeMetrics, error) { - sm := &scrapeMetrics{} + sm := &scrapeMetrics{reg: reg} // Manager metrics. sm.targetMetadataCache = &MetadataMetricsCollector{ @@ -260,6 +261,32 @@ func (sm *scrapeMetrics) setTargetMetadataCacheGatherer(gatherer TargetsGatherer sm.targetMetadataCache.TargetsGatherer = gatherer } +// Unregister unregisters all metrics. +func (sm *scrapeMetrics) Unregister() { + sm.reg.Unregister(sm.targetMetadataCache) + sm.reg.Unregister(sm.targetScrapePools) + sm.reg.Unregister(sm.targetScrapePoolsFailed) + sm.reg.Unregister(sm.targetReloadIntervalLength) + sm.reg.Unregister(sm.targetScrapePoolReloads) + sm.reg.Unregister(sm.targetScrapePoolReloadsFailed) + sm.reg.Unregister(sm.targetSyncIntervalLength) + sm.reg.Unregister(sm.targetScrapePoolSyncsCounter) + sm.reg.Unregister(sm.targetScrapePoolExceededTargetLimit) + sm.reg.Unregister(sm.targetScrapePoolTargetLimit) + sm.reg.Unregister(sm.targetScrapePoolTargetsAdded) + sm.reg.Unregister(sm.targetSyncFailed) + sm.reg.Unregister(sm.targetScrapeExceededBodySizeLimit) + sm.reg.Unregister(sm.targetScrapeCacheFlushForced) + sm.reg.Unregister(sm.targetIntervalLength) + sm.reg.Unregister(sm.targetScrapeSampleLimit) + sm.reg.Unregister(sm.targetScrapeSampleDuplicate) + sm.reg.Unregister(sm.targetScrapeSampleOutOfOrder) + sm.reg.Unregister(sm.targetScrapeSampleOutOfBounds) + sm.reg.Unregister(sm.targetScrapeExemplarOutOfOrder) + sm.reg.Unregister(sm.targetScrapePoolExceededLabelLimits) + sm.reg.Unregister(sm.targetScrapeNativeHistogramBucketLimit) +} + type TargetsGatherer interface { TargetsActive() map[string][]*Target } From 277f04f0c44219bb4158b021c7038015410c9745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Sun, 7 Apr 2024 18:28:28 +0100 Subject: [PATCH 241/253] Stop compactions if there's a block to write (#13754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Stop compactions if there's a block to write db.Compact() checks if there's a block to write with HEAD chunks before calling db.compactBlocks(). This is to ensure that if we need to write a block then it happens ASAP, otherwise memory usage might keep growing. But what can also happen is that we don't need to write any block, we start db.compactBlocks(), compaction takes hours, and in the meantime HEAD needs to write out chunks to a block. This can be especially problematic if, for example, you run Thanos sidecar that's uploading block, which requires that compactions are disabled. Then you disable Thanos sidecar and re-enable compactions. When db.compactBlocks() is finally called it might have a huge number of blocks to compact, which might take a very long time, during which HEAD cannot write out chunks to a new block. In such case memory usage will keep growing until either: - compactions are finally finished and HEAD can write a block - we run out of memory and Prometheus gets OOM-killed This change adds a check for pending HEAD block writes inside db.compactBlocks(), so that we bail out early if there are still compactions to run, but we also need to write a new block. Also add a test for compactBlocks. --------- Signed-off-by: Łukasz Mierzwa Signed-off-by: Lukasz Mierzwa --- tsdb/db.go | 8 +++++++ tsdb/db_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/tsdb/db.go b/tsdb/db.go index 293ba646ea..5078f447c4 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -1365,6 +1365,14 @@ func (db *DB) compactHead(head *RangeHead) error { func (db *DB) compactBlocks() (err error) { // Check for compactions of multiple blocks. for { + // If we have a lot of blocks to compact the whole process might take + // long enough that we end up with a HEAD block that needs to be written. + // Check if that's the case and stop compactions early. + if db.head.compactable() { + level.Warn(db.logger).Log("msg", "aborting block compactions to persit the head block") + return nil + } + plan, err := db.compactor.Plan(db.dir) if err != nil { return fmt.Errorf("plan compaction: %w", err) diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 8b1ad106bf..ba60d83eaf 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -6986,3 +6986,63 @@ func requireEqualOOOSamples(t *testing.T, expectedSamples int, db *DB) { prom_testutil.ToFloat64(db.head.metrics.outOfOrderSamplesAppended.WithLabelValues(sampleMetricTypeFloat)), "number of ooo appended samples mismatch") } + +type mockCompactorFn struct { + planFn func() ([]string, error) + compactFn func() (ulid.ULID, error) + writeFn func() (ulid.ULID, error) +} + +func (c *mockCompactorFn) Plan(_ string) ([]string, error) { + return c.planFn() +} + +func (c *mockCompactorFn) Compact(_ string, _ []string, _ []*Block) (ulid.ULID, error) { + return c.compactFn() +} + +func (c *mockCompactorFn) Write(_ string, _ BlockReader, _, _ int64, _ *BlockMeta) (ulid.ULID, error) { + return c.writeFn() +} + +// Regression test for https://github.com/prometheus/prometheus/pull/13754 +func TestAbortBlockCompactions(t *testing.T) { + // Create a test DB + db := openTestDB(t, nil, nil) + defer func() { + require.NoError(t, db.Close()) + }() + // It should NOT be compactible at the beginning of the test + require.False(t, db.head.compactable(), "head should NOT be compactable") + + // Track the number of compactions run inside db.compactBlocks() + var compactions int + + // Use a mock compactor with custom Plan() implementation + db.compactor = &mockCompactorFn{ + planFn: func() ([]string, error) { + // On every Plan() run increment compactions. After 4 compactions + // update HEAD to make it compactible to force an exit from db.compactBlocks() loop. + compactions++ + if compactions > 3 { + chunkRange := db.head.chunkRange.Load() + db.head.minTime.Store(0) + db.head.maxTime.Store(chunkRange * 2) + require.True(t, db.head.compactable(), "head should be compactable") + } + // Our custom Plan() will always return something to compact. + return []string{"1", "2", "3"}, nil + }, + compactFn: func() (ulid.ULID, error) { + return ulid.ULID{}, nil + }, + writeFn: func() (ulid.ULID, error) { + return ulid.ULID{}, nil + }, + } + + err := db.Compact(context.Background()) + require.NoError(t, err) + require.True(t, db.head.compactable(), "head should be compactable") + require.Equal(t, 4, compactions, "expected 4 compactions to be completed") +} From c14a158d03e8a9c25dcc4b0c3bf153cf6486880f Mon Sep 17 00:00:00 2001 From: hanghuge Date: Sat, 6 Apr 2024 19:48:24 +0800 Subject: [PATCH 242/253] Signed-off-by: hanghuge Fix unavailable link Signed-off-by: hanghuge --- discovery/kubernetes/kubernetes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discovery/kubernetes/kubernetes.go b/discovery/kubernetes/kubernetes.go index 94058aa04e..a8b6f85899 100644 --- a/discovery/kubernetes/kubernetes.go +++ b/discovery/kubernetes/kubernetes.go @@ -311,7 +311,7 @@ func New(l log.Logger, metrics discovery.DiscovererMetrics, conf *SDConfig) (*Di } case conf.APIServer.URL == nil: // Use the Kubernetes provided pod service account - // as described in https://kubernetes.io/docs/admin/service-accounts-admin/ + // as described in https://kubernetes.io/docs/tasks/run-application/access-api-from-pod/#using-official-client-libraries kcfg, err = rest.InClusterConfig() if err != nil { return nil, err From 633224886a1c975dd3a8a8308a0b1d630048a21c Mon Sep 17 00:00:00 2001 From: Jonathan Halterman Date: Mon, 8 Apr 2024 08:34:14 -0700 Subject: [PATCH 243/253] Write out of order hint when initially creating meta file (#13894) Signed-off-by: Jonathan Halterman Signed-off-by: Jonathan Halterman Co-authored-by: Jesus Vazquez --- tsdb/compact.go | 11 +++++++---- tsdb/db.go | 14 +++----------- tsdb/db_test.go | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/tsdb/compact.go b/tsdb/compact.go index 113ef11b4c..e09039cf33 100644 --- a/tsdb/compact.go +++ b/tsdb/compact.go @@ -60,7 +60,7 @@ type Compactor interface { // Write persists a Block into a directory. // No Block is written when resulting Block has 0 samples, and returns empty ulid.ULID{}. - Write(dest string, b BlockReader, mint, maxt int64, parent *BlockMeta) (ulid.ULID, error) + Write(dest string, b BlockReader, mint, maxt int64, base *BlockMeta) (ulid.ULID, error) // Compact runs compaction against the provided directories. Must // only be called concurrently with results of Plan(). @@ -536,7 +536,7 @@ func (c *LeveledCompactor) CompactWithBlockPopulator(dest string, dirs []string, return uid, errs.Err() } -func (c *LeveledCompactor) Write(dest string, b BlockReader, mint, maxt int64, parent *BlockMeta) (ulid.ULID, error) { +func (c *LeveledCompactor) Write(dest string, b BlockReader, mint, maxt int64, base *BlockMeta) (ulid.ULID, error) { start := time.Now() uid := ulid.MustNew(ulid.Now(), rand.Reader) @@ -549,9 +549,12 @@ func (c *LeveledCompactor) Write(dest string, b BlockReader, mint, maxt int64, p meta.Compaction.Level = 1 meta.Compaction.Sources = []ulid.ULID{uid} - if parent != nil { + if base != nil { meta.Compaction.Parents = []BlockDesc{ - {ULID: parent.ULID, MinTime: parent.MinTime, MaxTime: parent.MaxTime}, + {ULID: base.ULID, MinTime: base.MinTime, MaxTime: base.MaxTime}, + } + if base.Compaction.FromOutOfOrder() { + meta.Compaction.SetOutOfOrder() } } diff --git a/tsdb/db.go b/tsdb/db.go index 5078f447c4..d675635d7a 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -1299,25 +1299,17 @@ func (db *DB) compactOOO(dest string, oooHead *OOOCompactionHead) (_ []ulid.ULID } }() + meta := &BlockMeta{} + meta.Compaction.SetOutOfOrder() for t := blockSize * (oooHeadMint / blockSize); t <= oooHeadMaxt; t += blockSize { mint, maxt := t, t+blockSize // Block intervals are half-open: [b.MinTime, b.MaxTime). Block intervals are always +1 than the total samples it includes. - uid, err := db.compactor.Write(dest, oooHead.CloneForTimeRange(mint, maxt-1), mint, maxt, nil) + uid, err := db.compactor.Write(dest, oooHead.CloneForTimeRange(mint, maxt-1), mint, maxt, meta) if err != nil { return nil, err } if uid.Compare(ulid.ULID{}) != 0 { ulids = append(ulids, uid) - blockDir := filepath.Join(dest, uid.String()) - meta, _, err := readMetaFile(blockDir) - if err != nil { - return ulids, fmt.Errorf("read meta: %w", err) - } - meta.Compaction.SetOutOfOrder() - _, err = writeMetaFile(db.logger, blockDir, meta) - if err != nil { - return ulids, fmt.Errorf("write meta: %w", err) - } } } diff --git a/tsdb/db_test.go b/tsdb/db_test.go index ba60d83eaf..71b2f05ac7 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -1441,7 +1441,7 @@ func (c *mockCompactorFailing) Write(dest string, _ BlockReader, _, _ int64, _ * c.blocks = append(c.blocks, block) // Now check that all expected blocks are actually persisted on disk. - // This way we make sure that the we have some blocks that are supposed to be removed. + // This way we make sure that we have some blocks that are supposed to be removed. var expectedBlocks []string for _, b := range c.blocks { expectedBlocks = append(expectedBlocks, filepath.Join(dest, b.Meta().ULID.String())) From d496687c8e7900e127f50ad940c9d8e580eaf212 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 8 Apr 2024 19:26:23 +0000 Subject: [PATCH 244/253] golangci-lint: enable usestdlibvars linter Signed-off-by: Matthieu MOREL --- .golangci.yml | 1 + cmd/promtool/main.go | 2 +- discovery/eureka/client.go | 2 +- discovery/hetzner/robot.go | 2 +- discovery/http/http.go | 2 +- discovery/marathon/marathon.go | 2 +- discovery/openstack/mock_test.go | 6 +++--- discovery/puppetdb/puppetdb.go | 2 +- discovery/triton/triton.go | 2 +- discovery/xds/client.go | 2 +- .../remote_storage_adapter/influxdb/client_test.go | 2 +- .../remote_storage_adapter/opentsdb/client.go | 2 +- model/labels/labels_test.go | 3 ++- notifier/notifier.go | 2 +- scrape/scrape.go | 2 +- storage/remote/client.go | 4 ++-- storage/remote/read_handler_test.go | 6 +++--- util/httputil/compression_test.go | 4 ++-- util/httputil/cors_test.go | 4 ++-- web/api/v1/api_test.go | 4 ++-- web/api/v1/errors_test.go | 2 +- web/federate_test.go | 6 +++--- web/web_test.go | 4 ++-- 23 files changed, 35 insertions(+), 33 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 42410aebf8..f350aed6dd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -26,6 +26,7 @@ linters: - testifylint - unconvert - unused + - usestdlibvars issues: max-same-issues: 0 diff --git a/cmd/promtool/main.go b/cmd/promtool/main.go index 47bf02c104..a62ae4fbf4 100644 --- a/cmd/promtool/main.go +++ b/cmd/promtool/main.go @@ -482,7 +482,7 @@ func CheckServerStatus(serverURL *url.URL, checkEndpoint string, roundTripper ht return err } - request, err := http.NewRequest("GET", config.Address, nil) + request, err := http.NewRequest(http.MethodGet, config.Address, nil) if err != nil { return err } diff --git a/discovery/eureka/client.go b/discovery/eureka/client.go index a833415a53..52e8ce7b48 100644 --- a/discovery/eureka/client.go +++ b/discovery/eureka/client.go @@ -81,7 +81,7 @@ const appListPath string = "/apps" func fetchApps(ctx context.Context, server string, client *http.Client) (*Applications, error) { url := fmt.Sprintf("%s%s", server, appListPath) - request, err := http.NewRequest("GET", url, nil) + request, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } diff --git a/discovery/hetzner/robot.go b/discovery/hetzner/robot.go index 1d8aa9302f..2cf6006f80 100644 --- a/discovery/hetzner/robot.go +++ b/discovery/hetzner/robot.go @@ -70,7 +70,7 @@ func newRobotDiscovery(conf *SDConfig, _ log.Logger) (*robotDiscovery, error) { } func (d *robotDiscovery) refresh(context.Context) ([]*targetgroup.Group, error) { - req, err := http.NewRequest("GET", d.endpoint+"/server", nil) + req, err := http.NewRequest(http.MethodGet, d.endpoint+"/server", nil) if err != nil { return nil, err } diff --git a/discovery/http/http.go b/discovery/http/http.go index 8dd21ec9e4..ff76fd7627 100644 --- a/discovery/http/http.go +++ b/discovery/http/http.go @@ -150,7 +150,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger, clientOpts []config.HTTPCli } func (d *Discovery) Refresh(ctx context.Context) ([]*targetgroup.Group, error) { - req, err := http.NewRequest("GET", d.url, nil) + req, err := http.NewRequest(http.MethodGet, d.url, nil) if err != nil { return nil, err } diff --git a/discovery/marathon/marathon.go b/discovery/marathon/marathon.go index ecad108e4a..f833af47e7 100644 --- a/discovery/marathon/marathon.go +++ b/discovery/marathon/marathon.go @@ -339,7 +339,7 @@ type appListClient func(ctx context.Context, client *http.Client, url string) (* // fetchApps requests a list of applications from a marathon server. func fetchApps(ctx context.Context, client *http.Client, url string) (*appList, error) { - request, err := http.NewRequest("GET", url, nil) + request, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } diff --git a/discovery/openstack/mock_test.go b/discovery/openstack/mock_test.go index 4aa871e11f..b1267db90e 100644 --- a/discovery/openstack/mock_test.go +++ b/discovery/openstack/mock_test.go @@ -239,7 +239,7 @@ const hypervisorListBody = ` // HandleHypervisorListSuccessfully mocks os-hypervisors detail call. func (m *SDMock) HandleHypervisorListSuccessfully() { m.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { - testMethod(m.t, r, "GET") + testMethod(m.t, r, http.MethodGet) testHeader(m.t, r, "X-Auth-Token", tokenID) w.Header().Add("Content-Type", "application/json") @@ -536,7 +536,7 @@ const serverListBody = ` // HandleServerListSuccessfully mocks server detail call. func (m *SDMock) HandleServerListSuccessfully() { m.Mux.HandleFunc("/servers/detail", func(w http.ResponseWriter, r *http.Request) { - testMethod(m.t, r, "GET") + testMethod(m.t, r, http.MethodGet) testHeader(m.t, r, "X-Auth-Token", tokenID) w.Header().Add("Content-Type", "application/json") @@ -575,7 +575,7 @@ const listOutput = ` // HandleFloatingIPListSuccessfully mocks floating ips call. func (m *SDMock) HandleFloatingIPListSuccessfully() { m.Mux.HandleFunc("/os-floating-ips", func(w http.ResponseWriter, r *http.Request) { - testMethod(m.t, r, "GET") + testMethod(m.t, r, http.MethodGet) testHeader(m.t, r, "X-Auth-Token", tokenID) w.Header().Add("Content-Type", "application/json") diff --git a/discovery/puppetdb/puppetdb.go b/discovery/puppetdb/puppetdb.go index 3f9ad1f113..8c9ccde0a4 100644 --- a/discovery/puppetdb/puppetdb.go +++ b/discovery/puppetdb/puppetdb.go @@ -189,7 +189,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { return nil, err } - req, err := http.NewRequest("POST", d.url, bytes.NewBuffer(bodyBytes)) + req, err := http.NewRequest(http.MethodPost, d.url, bytes.NewBuffer(bodyBytes)) if err != nil { return nil, err } diff --git a/discovery/triton/triton.go b/discovery/triton/triton.go index e56b7951b6..675149f2a3 100644 --- a/discovery/triton/triton.go +++ b/discovery/triton/triton.go @@ -211,7 +211,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { endpoint = fmt.Sprintf("%s?groups=%s", endpoint, groups) } - req, err := http.NewRequest("GET", endpoint, nil) + req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { return nil, err } diff --git a/discovery/xds/client.go b/discovery/xds/client.go index 9844c6d7ed..027ceb2715 100644 --- a/discovery/xds/client.go +++ b/discovery/xds/client.go @@ -179,7 +179,7 @@ func (rc *HTTPResourceClient) Fetch(ctx context.Context) (*v3.DiscoveryResponse, return nil, err } - request, err := http.NewRequest("POST", rc.endpoint, bytes.NewBuffer(reqBody)) + request, err := http.NewRequest(http.MethodPost, rc.endpoint, bytes.NewBuffer(reqBody)) if err != nil { return nil, err } diff --git a/documentation/examples/remote_storage/remote_storage_adapter/influxdb/client_test.go b/documentation/examples/remote_storage/remote_storage_adapter/influxdb/client_test.go index cb56514e4b..a738c01dcd 100644 --- a/documentation/examples/remote_storage/remote_storage_adapter/influxdb/client_test.go +++ b/documentation/examples/remote_storage/remote_storage_adapter/influxdb/client_test.go @@ -74,7 +74,7 @@ testmetric,test_label=test_label_value2 value=5.1234 123456789123 server := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "POST", r.Method, "Unexpected method.") + require.Equal(t, http.MethodPost, r.Method, "Unexpected method.") require.Equal(t, "/write", r.URL.Path, "Unexpected path.") b, err := io.ReadAll(r.Body) require.NoError(t, err, "Error reading body.") diff --git a/documentation/examples/remote_storage/remote_storage_adapter/opentsdb/client.go b/documentation/examples/remote_storage/remote_storage_adapter/opentsdb/client.go index 0fa7c5a4b7..abb1d0b7d3 100644 --- a/documentation/examples/remote_storage/remote_storage_adapter/opentsdb/client.go +++ b/documentation/examples/remote_storage/remote_storage_adapter/opentsdb/client.go @@ -105,7 +105,7 @@ func (c *Client) Write(samples model.Samples) error { ctx, cancel := context.WithTimeout(context.Background(), c.timeout) defer cancel() - req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(buf)) + req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewBuffer(buf)) if err != nil { return err } diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index 5ec7764ca9..3d6e7659f4 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -16,6 +16,7 @@ package labels import ( "encoding/json" "fmt" + "net/http" "strings" "testing" @@ -810,7 +811,7 @@ var benchmarkLabels = []Label{ {"job", "node"}, {"instance", "123.123.1.211:9090"}, {"path", "/api/v1/namespaces//deployments/"}, - {"method", "GET"}, + {"method", http.MethodGet}, {"namespace", "system"}, {"status", "500"}, {"prometheus", "prometheus-core-1"}, diff --git a/notifier/notifier.go b/notifier/notifier.go index d1832402f7..53d3c04198 100644 --- a/notifier/notifier.go +++ b/notifier/notifier.go @@ -590,7 +590,7 @@ func labelsToOpenAPILabelSet(modelLabelSet labels.Labels) models.LabelSet { } func (n *Manager) sendOne(ctx context.Context, c *http.Client, url string, b []byte) error { - req, err := http.NewRequest("POST", url, bytes.NewReader(b)) + req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(b)) if err != nil { return err } diff --git a/scrape/scrape.go b/scrape/scrape.go index 734c248130..4bbeab57a7 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -726,7 +726,7 @@ var UserAgent = fmt.Sprintf("Prometheus/%s", version.Version) func (s *targetScraper) scrape(ctx context.Context) (*http.Response, error) { if s.req == nil { - req, err := http.NewRequest("GET", s.URL().String(), nil) + req, err := http.NewRequest(http.MethodGet, s.URL().String(), nil) if err != nil { return nil, err } diff --git a/storage/remote/client.go b/storage/remote/client.go index 5ba0f7117f..140194ec71 100644 --- a/storage/remote/client.go +++ b/storage/remote/client.go @@ -199,7 +199,7 @@ type RecoverableError struct { // Store sends a batch of samples to the HTTP endpoint, the request is the proto marshalled // and encoded bytes from codec.go. func (c *Client) Store(ctx context.Context, req []byte, attempt int) error { - httpReq, err := http.NewRequest("POST", c.urlString, bytes.NewReader(req)) + httpReq, err := http.NewRequest(http.MethodPost, c.urlString, bytes.NewReader(req)) if err != nil { // Errors from NewRequest are from unparsable URLs, so are not // recoverable. @@ -290,7 +290,7 @@ func (c *Client) Read(ctx context.Context, query *prompb.Query) (*prompb.QueryRe } compressed := snappy.Encode(nil, data) - httpReq, err := http.NewRequest("POST", c.urlString, bytes.NewReader(compressed)) + httpReq, err := http.NewRequest(http.MethodPost, c.urlString, bytes.NewReader(compressed)) if err != nil { return nil, fmt.Errorf("unable to create request: %w", err) } diff --git a/storage/remote/read_handler_test.go b/storage/remote/read_handler_test.go index e83a0cb21a..e8e0ecb8df 100644 --- a/storage/remote/read_handler_test.go +++ b/storage/remote/read_handler_test.go @@ -75,7 +75,7 @@ func TestSampledReadEndpoint(t *testing.T) { require.NoError(t, err) compressed := snappy.Encode(nil, data) - request, err := http.NewRequest("POST", "", bytes.NewBuffer(compressed)) + request, err := http.NewRequest(http.MethodPost, "", bytes.NewBuffer(compressed)) require.NoError(t, err) recorder := httptest.NewRecorder() @@ -170,7 +170,7 @@ func BenchmarkStreamReadEndpoint(b *testing.B) { for i := 0; i < b.N; i++ { compressed := snappy.Encode(nil, data) - request, err := http.NewRequest("POST", "", bytes.NewBuffer(compressed)) + request, err := http.NewRequest(http.MethodPost, "", bytes.NewBuffer(compressed)) require.NoError(b, err) recorder := httptest.NewRecorder() @@ -268,7 +268,7 @@ func TestStreamReadEndpoint(t *testing.T) { require.NoError(t, err) compressed := snappy.Encode(nil, data) - request, err := http.NewRequest("POST", "", bytes.NewBuffer(compressed)) + request, err := http.NewRequest(http.MethodPost, "", bytes.NewBuffer(compressed)) require.NoError(t, err) recorder := httptest.NewRecorder() diff --git a/util/httputil/compression_test.go b/util/httputil/compression_test.go index 2db6810bd7..e166c7de79 100644 --- a/util/httputil/compression_test.go +++ b/util/httputil/compression_test.go @@ -85,7 +85,7 @@ func TestCompressionHandler_Gzip(t *testing.T) { }, } - req, _ := http.NewRequest("GET", server.URL+"/foo_endpoint", nil) + req, _ := http.NewRequest(http.MethodGet, server.URL+"/foo_endpoint", nil) req.Header.Set(acceptEncodingHeader, gzipEncoding) resp, err := client.Do(req) @@ -120,7 +120,7 @@ func TestCompressionHandler_Deflate(t *testing.T) { }, } - req, _ := http.NewRequest("GET", server.URL+"/foo_endpoint", nil) + req, _ := http.NewRequest(http.MethodGet, server.URL+"/foo_endpoint", nil) req.Header.Set(acceptEncodingHeader, deflateEncoding) resp, err := client.Do(req) diff --git a/util/httputil/cors_test.go b/util/httputil/cors_test.go index cfa2400405..657443ece0 100644 --- a/util/httputil/cors_test.go +++ b/util/httputil/cors_test.go @@ -41,7 +41,7 @@ func TestCORSHandler(t *testing.T) { dummyOrigin := "https://foo.com" // OPTIONS with legit origin - req, err := http.NewRequest("OPTIONS", server.URL+"/any_path", nil) + req, err := http.NewRequest(http.MethodOptions, server.URL+"/any_path", nil) require.NoError(t, err, "could not create request") req.Header.Set("Origin", dummyOrigin) @@ -53,7 +53,7 @@ func TestCORSHandler(t *testing.T) { require.Equal(t, dummyOrigin, AccessControlAllowOrigin, "expected Access-Control-Allow-Origin header") // OPTIONS with bad origin - req, err = http.NewRequest("OPTIONS", server.URL+"/any_path", nil) + req, err = http.NewRequest(http.MethodOptions, server.URL+"/any_path", nil) require.NoError(t, err, "could not create request") req.Header.Set("Origin", "https://not-foo.com") diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index 4158e544ef..c383993815 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -3354,7 +3354,7 @@ func TestParseTimeParam(t *testing.T) { } for _, test := range tests { - req, err := http.NewRequest("GET", "localhost:42/foo?"+test.paramName+"="+test.paramValue, nil) + req, err := http.NewRequest(http.MethodGet, "localhost:42/foo?"+test.paramName+"="+test.paramValue, nil) require.NoError(t, err) result := test.result @@ -3491,7 +3491,7 @@ func TestOptionsMethod(t *testing.T) { s := httptest.NewServer(r) defer s.Close() - req, err := http.NewRequest("OPTIONS", s.URL+"/any_path", nil) + req, err := http.NewRequest(http.MethodOptions, s.URL+"/any_path", nil) require.NoError(t, err, "Error creating OPTIONS request") client := &http.Client{} resp, err := client.Do(req) diff --git a/web/api/v1/errors_test.go b/web/api/v1/errors_test.go index b6ec7d4e1f..e76a1a3d35 100644 --- a/web/api/v1/errors_test.go +++ b/web/api/v1/errors_test.go @@ -89,7 +89,7 @@ func TestApiStatusCodes(t *testing.T) { r := createPrometheusAPI(q) rec := httptest.NewRecorder() - req := httptest.NewRequest("GET", "/api/v1/query?query=up", nil) + req := httptest.NewRequest(http.MethodGet, "/api/v1/query?query=up", nil) r.ServeHTTP(rec, req) diff --git a/web/federate_test.go b/web/federate_test.go index 16637f60a3..f201210ec0 100644 --- a/web/federate_test.go +++ b/web/federate_test.go @@ -224,7 +224,7 @@ func TestFederation(t *testing.T) { for name, scenario := range scenarios { t.Run(name, func(t *testing.T) { h.config.GlobalConfig.ExternalLabels = scenario.externalLabels - req := httptest.NewRequest("GET", "http://example.org/federate?"+scenario.params, nil) + req := httptest.NewRequest(http.MethodGet, "http://example.org/federate?"+scenario.params, nil) res := httptest.NewRecorder() h.federation(res, req) @@ -265,7 +265,7 @@ func TestFederation_NotReady(t *testing.T) { }, } - req := httptest.NewRequest("GET", "http://example.org/federate?"+scenario.params, nil) + req := httptest.NewRequest(http.MethodGet, "http://example.org/federate?"+scenario.params, nil) res := httptest.NewRecorder() h.federation(res, req) @@ -381,7 +381,7 @@ func TestFederationWithNativeHistograms(t *testing.T) { }, } - req := httptest.NewRequest("GET", "http://example.org/federate?match[]=test_metric", nil) + req := httptest.NewRequest(http.MethodGet, "http://example.org/federate?match[]=test_metric", nil) req.Header.Add("Accept", `application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited,application/openmetrics-text;version=1.0.0;q=0.8,application/openmetrics-text;version=0.0.1;q=0.75,text/plain;version=0.0.4;q=0.5,*/*;q=0.1`) res := httptest.NewRecorder() diff --git a/web/web_test.go b/web/web_test.go index 62bdb2ae31..e1fa66fa8b 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -311,7 +311,7 @@ func TestDebugHandler(t *testing.T) { w := httptest.NewRecorder() - req, err := http.NewRequest("GET", tc.url, nil) + req, err := http.NewRequest(http.MethodGet, tc.url, nil) require.NoError(t, err) @@ -335,7 +335,7 @@ func TestHTTPMetrics(t *testing.T) { t.Helper() w := httptest.NewRecorder() - req, err := http.NewRequest("GET", "/-/ready", nil) + req, err := http.NewRequest(http.MethodGet, "/-/ready", nil) require.NoError(t, err) handler.router.ServeHTTP(w, req) From f07f4f293ff51ab64df23d99225b4cd6aba566ca Mon Sep 17 00:00:00 2001 From: beorn7 Date: Thu, 4 Apr 2024 20:31:33 +0200 Subject: [PATCH 245/253] List Prometheus v3 coordinators in MAINTAINERS.md The Prometheus v3 coordinators are full members of the Prometheus GH org, a status that our governance specifies for maintainers. As discussed, it appears best to formalize maintainership by listing the coordinators in the MAINTAINERS.md file of prometheus/prometheus. Signed-off-by: beorn7 --- MAINTAINERS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 630bbdd527..d9a7d0f783 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -30,3 +30,13 @@ size of this repository, the natural changes in focus of maintainers over time, and nuances of where particular features live, this list will always be incomplete and out of date. However the listed maintainer(s) should be able to direct a PR/question to the right person. + +v3 release coordinators: +* Alex Greenbank ( / @alexgreenbank) +* Carrie Edwards ( / @carrieedwards) +* Fiona Liao ( / @fionaliao) +* Jan Fajerski ( / @jan--f) +* Jesús Vázquez ( / @jesusvazquez) +* Nico Pazos ( / @npazosmendez) +* Owen Williams ( / @ywwg) +* Tom Braack ( / @sh0rez) From b4c0ab52c3e9b940ab803581ddae9b3d9a452337 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 9 Apr 2024 11:06:33 +0100 Subject: [PATCH 246/253] Cut release 2.51.2 Signed-off-by: Bryan Boreham --- CHANGELOG.md | 6 ++++++ VERSION | 2 +- 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 +- web/ui/react-app/package.json | 4 ++-- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 046d3ea60a..eee024f1df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2.51.2 / 2024-04-09 + +Bugfix release. + +[BUGFIX] Notifier: could hang when using relabeling on alerts #13861 + ## 2.51.1 / 2024-03-27 Bugfix release. diff --git a/VERSION b/VERSION index 8e00e241f3..587b583f91 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.51.1 +2.51.2 diff --git a/web/ui/module/codemirror-promql/package.json b/web/ui/module/codemirror-promql/package.json index c364e05584..1e50b43b53 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.51.1", + "version": "0.51.2", "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.51.1", + "@prometheus-io/lezer-promql": "0.51.2", "lru-cache": "^7.18.3" }, "devDependencies": { diff --git a/web/ui/module/lezer-promql/package.json b/web/ui/module/lezer-promql/package.json index f5ea66602f..494458a47a 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.51.1", + "version": "0.51.2", "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 fdb348d669..ecdbf18a11 100644 --- a/web/ui/package-lock.json +++ b/web/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "prometheus-io", - "version": "0.51.1", + "version": "0.51.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prometheus-io", - "version": "0.51.1", + "version": "0.51.2", "workspaces": [ "react-app", "module/*" @@ -30,10 +30,10 @@ }, "module/codemirror-promql": { "name": "@prometheus-io/codemirror-promql", - "version": "0.51.1", + "version": "0.51.2", "license": "Apache-2.0", "dependencies": { - "@prometheus-io/lezer-promql": "0.51.1", + "@prometheus-io/lezer-promql": "0.51.2", "lru-cache": "^7.18.3" }, "devDependencies": { @@ -69,7 +69,7 @@ }, "module/lezer-promql": { "name": "@prometheus-io/lezer-promql", - "version": "0.51.1", + "version": "0.51.2", "license": "Apache-2.0", "devDependencies": { "@lezer/generator": "^1.5.1", @@ -19233,7 +19233,7 @@ }, "react-app": { "name": "@prometheus-io/app", - "version": "0.51.1", + "version": "0.51.2", "dependencies": { "@codemirror/autocomplete": "^6.11.1", "@codemirror/commands": "^6.3.2", @@ -19251,7 +19251,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.51.1", + "@prometheus-io/codemirror-promql": "0.51.2", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", diff --git a/web/ui/package.json b/web/ui/package.json index 0772aad7de..9c58f592c1 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -28,5 +28,5 @@ "ts-jest": "^29.1.1", "typescript": "^4.9.5" }, - "version": "0.51.1" + "version": "0.51.2" } diff --git a/web/ui/react-app/package.json b/web/ui/react-app/package.json index b47c9180a3..bd600720e2 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.51.1", + "version": "0.51.2", "private": true, "dependencies": { "@codemirror/autocomplete": "^6.11.1", @@ -19,7 +19,7 @@ "@lezer/lr": "^1.3.14", "@nexucis/fuzzy": "^0.4.1", "@nexucis/kvsearch": "^0.8.1", - "@prometheus-io/codemirror-promql": "0.51.1", + "@prometheus-io/codemirror-promql": "0.51.2", "bootstrap": "^4.6.2", "css.escape": "^1.5.1", "downshift": "^7.6.2", From 6f595c6762d253c0ef7574b93f9795a6e3e40c81 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Thu, 11 Apr 2024 10:27:54 +0200 Subject: [PATCH 247/253] golangci-lint: enable whitespace linter (#13905) Signed-off-by: Matthieu MOREL --- .golangci.yml | 1 + cmd/promtool/rules_test.go | 1 - discovery/eureka/eureka.go | 1 - discovery/hetzner/robot.go | 1 - discovery/marathon/marathon.go | 3 --- discovery/moby/nodes.go | 1 - discovery/scaleway/instance.go | 1 - discovery/zookeeper/zookeeper.go | 1 - promql/functions.go | 2 -- promql/parser/parse.go | 1 - promql/test.go | 1 - rules/manager_test.go | 3 --- scrape/manager.go | 1 - scrape/manager_test.go | 1 - scrape/target_test.go | 1 - storage/merge_test.go | 1 - storage/remote/queue_manager_test.go | 1 - storage/remote/write_handler.go | 1 - tsdb/block_test.go | 1 - tsdb/chunkenc/histogram_meta.go | 1 - tsdb/db.go | 1 - tsdb/head_append.go | 1 - tsdb/head_test.go | 3 --- tsdb/head_wal.go | 1 - tsdb/index/index.go | 1 - tsdb/querier.go | 1 - tsdb/wlog/watcher.go | 1 - 27 files changed, 1 insertion(+), 33 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f350aed6dd..a85a76cdf1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -27,6 +27,7 @@ linters: - unconvert - unused - usestdlibvars + - whitespace issues: max-same-issues: 0 diff --git a/cmd/promtool/rules_test.go b/cmd/promtool/rules_test.go index 75aad67864..d55fb0c896 100644 --- a/cmd/promtool/rules_test.go +++ b/cmd/promtool/rules_test.go @@ -78,7 +78,6 @@ func TestBackfillRuleIntegration(t *testing.T) { // Execute the test more than once to simulate running the rule importer twice with the same data. // We expect duplicate blocks with the same series are created when run more than once. for i := 0; i < tt.runcount; i++ { - ruleImporter, err := newTestRuleImporter(ctx, start, tmpDir, tt.samples, tt.maxBlockDuration) require.NoError(t, err) path1 := filepath.Join(tmpDir, "test.file") diff --git a/discovery/eureka/eureka.go b/discovery/eureka/eureka.go index deed89f6f6..779c081aee 100644 --- a/discovery/eureka/eureka.go +++ b/discovery/eureka/eureka.go @@ -228,7 +228,6 @@ func targetsForApp(app *Application) []model.LabelSet { } targets = append(targets, target) - } return targets } diff --git a/discovery/hetzner/robot.go b/discovery/hetzner/robot.go index 2cf6006f80..b862c33f5b 100644 --- a/discovery/hetzner/robot.go +++ b/discovery/hetzner/robot.go @@ -122,7 +122,6 @@ func (d *robotDiscovery) refresh(context.Context) ([]*targetgroup.Group, error) labels[hetznerLabelPublicIPv6Network] = model.LabelValue(fmt.Sprintf("%s/%s", subnet.IP, subnet.Mask)) break } - } targets[i] = labels } diff --git a/discovery/marathon/marathon.go b/discovery/marathon/marathon.go index f833af47e7..3e9e15967f 100644 --- a/discovery/marathon/marathon.go +++ b/discovery/marathon/marathon.go @@ -453,7 +453,6 @@ func targetsForApp(app *app) []model.LabelSet { // Gather info about the app's 'tasks'. Each instance (container) is considered a task // and can be reachable at one or more host:port endpoints. for _, t := range app.Tasks { - // There are no labels to gather if only Ports is defined. (eg. with host networking) // Ports can only be gathered from the Task (not from the app) and are guaranteed // to be the same across all tasks. If we haven't gathered any ports by now, @@ -464,7 +463,6 @@ func targetsForApp(app *app) []model.LabelSet { // Iterate over the ports we gathered using one of the methods above. for i, port := range ports { - // A zero port here means that either the portMapping has a zero port defined, // or there is a portDefinition with requirePorts set to false. This means the port // is auto-generated by Mesos and needs to be looked up in the task. @@ -516,7 +514,6 @@ func extractPortMapping(portMappings []portMapping, containerNet bool) ([]uint32 labels := make([]map[string]string, len(portMappings)) for i := 0; i < len(portMappings); i++ { - labels[i] = portMappings[i].Labels if containerNet { diff --git a/discovery/moby/nodes.go b/discovery/moby/nodes.go index 85092f9071..a7c5551c02 100644 --- a/discovery/moby/nodes.go +++ b/discovery/moby/nodes.go @@ -80,7 +80,6 @@ func (d *Discovery) refreshNodes(ctx context.Context) ([]*targetgroup.Group, err labels[model.AddressLabel] = model.LabelValue(addr) tg.Targets = append(tg.Targets, labels) - } return []*targetgroup.Group{tg}, nil } diff --git a/discovery/scaleway/instance.go b/discovery/scaleway/instance.go index 67311216d0..9dd786c804 100644 --- a/discovery/scaleway/instance.go +++ b/discovery/scaleway/instance.go @@ -190,7 +190,6 @@ func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, targets = append(targets, labels) } - } return []*targetgroup.Group{{Source: "scaleway", Targets: targets}}, nil diff --git a/discovery/zookeeper/zookeeper.go b/discovery/zookeeper/zookeeper.go index 7d87615271..303c7ca6d0 100644 --- a/discovery/zookeeper/zookeeper.go +++ b/discovery/zookeeper/zookeeper.go @@ -291,7 +291,6 @@ func parseServersetMember(data []byte, path string) (model.LabelSet, error) { endpoint.Host) labels[serversetEndpointLabelPrefix+"_port_"+cleanName] = model.LabelValue( fmt.Sprintf("%d", endpoint.Port)) - } labels[serversetStatusLabel] = model.LabelValue(member.Status) diff --git a/promql/functions.go b/promql/functions.go index 0cfbcc3452..2e15a14672 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -342,7 +342,6 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode // Run the smoothing operation. var x, y float64 for i := 1; i < l; i++ { - // Scale the raw value against the smoothing factor. x = sf * samples.Floats[i].F @@ -1240,7 +1239,6 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev enh.signatureToMetricWithBuckets[string(enh.lblBuf)] = mb } mb.buckets = append(mb.buckets, bucket{upperBound, sample.F}) - } // Now deal with the histograms. diff --git a/promql/parser/parse.go b/promql/parser/parse.go index eca4396524..2679336d6c 100644 --- a/promql/parser/parse.go +++ b/promql/parser/parse.go @@ -258,7 +258,6 @@ func ParseSeriesDesc(input string) (labels labels.Labels, values []SequenceValue labels = result.labels values = result.values - } if len(p.parseErrors) != 0 { diff --git a/promql/test.go b/promql/test.go index 2a9a4a2b81..1cdfe8d311 100644 --- a/promql/test.go +++ b/promql/test.go @@ -567,7 +567,6 @@ func (ev *evalCmd) compareResult(result parser.Value) error { return fmt.Errorf("expected histogram value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.H, actual.H, formatSeriesResult(s)) } } - } for hash := range ev.expected { diff --git a/rules/manager_test.go b/rules/manager_test.go index 4215ca4e43..50ab6b861f 100644 --- a/rules/manager_test.go +++ b/rules/manager_test.go @@ -336,7 +336,6 @@ func TestForStateAddSamples(t *testing.T) { for _, aa := range rule.ActiveAlerts() { require.Zero(t, aa.Labels.Get(model.MetricNameLabel), "%s label set on active alert: %s", model.MetricNameLabel, aa.Labels) } - } } @@ -1824,7 +1823,6 @@ func TestDependencyMapUpdatesOnGroupUpdate(t *testing.T) { } else { require.Equal(t, orig[h], depMap) } - } // Groups will be recreated when updated. @@ -1962,7 +1960,6 @@ func TestAsyncRuleEvaluation(t *testing.T) { require.Less(t, time.Since(start).Seconds(), (time.Duration(ruleCount) * artificialDelay).Seconds()) // Each rule produces one vector. require.EqualValues(t, ruleCount, testutil.ToFloat64(group.metrics.GroupSamples)) - } }) diff --git a/scrape/manager.go b/scrape/manager.go index e805fd43af..a7a8b828e5 100644 --- a/scrape/manager.go +++ b/scrape/manager.go @@ -185,7 +185,6 @@ func (m *Manager) reload() { sp.Sync(groups) wg.Done() }(m.scrapePools[setName], groups) - } m.mtxScrape.Unlock() wg.Wait() diff --git a/scrape/manager_test.go b/scrape/manager_test.go index 51af45f8cf..c8d9bd6980 100644 --- a/scrape/manager_test.go +++ b/scrape/manager_test.go @@ -583,7 +583,6 @@ func TestManagerTargetsUpdates(t *testing.T) { tgSent := make(map[string][]*targetgroup.Group) for x := 0; x < 10; x++ { - tgSent[strconv.Itoa(x)] = []*targetgroup.Group{ { Source: strconv.Itoa(x), diff --git a/scrape/target_test.go b/scrape/target_test.go index 413fbc1b81..f91e31050a 100644 --- a/scrape/target_test.go +++ b/scrape/target_test.go @@ -592,7 +592,6 @@ func TestMaxSchemaAppender(t *testing.T) { _, err = app.AppendHistogram(0, lbls, ts, nil, fh) require.Equal(t, c.expectSchema, fh.Schema) require.NoError(t, err) - } else { h := c.h.Copy() _, err = app.AppendHistogram(0, lbls, ts, h, nil) diff --git a/storage/merge_test.go b/storage/merge_test.go index c3a4725aa0..0e63affbb9 100644 --- a/storage/merge_test.go +++ b/storage/merge_test.go @@ -377,7 +377,6 @@ func TestMergeChunkQuerierWithNoVerticalChunkSeriesMerger(t *testing.T) { actChks, actErr := ExpandChunks(actualSeries.Iterator(nil)) require.Equal(t, expErr, actErr) require.Equal(t, expChks, actChks) - } require.NoError(t, merged.Err()) require.False(t, tc.expected.Next(), "Expected Next() to be false") diff --git a/storage/remote/queue_manager_test.go b/storage/remote/queue_manager_test.go index 028120c05c..e32a3ace05 100644 --- a/storage/remote/queue_manager_test.go +++ b/storage/remote/queue_manager_test.go @@ -845,7 +845,6 @@ func (c *TestWriteClient) Store(_ context.Context, req []byte, _ int) error { } else { c.receivedHistograms[seriesName] = append(c.receivedHistograms[seriesName], histogram) } - } } if c.withWaitGroup { diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index d0d96b09d5..bb6b8423a2 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -135,7 +135,6 @@ func (h *writeHandler) write(ctx context.Context, req *prompb.WriteRequest) (err } return err } - } for _, ep := range ts.Exemplars { diff --git a/tsdb/block_test.go b/tsdb/block_test.go index 21e20a61c8..6d15d1838b 100644 --- a/tsdb/block_test.go +++ b/tsdb/block_test.go @@ -459,7 +459,6 @@ func TestLabelNamesWithMatchers(t *testing.T) { "unique", fmt.Sprintf("value%d", i), ), []chunks.Sample{sample{100, 0, nil, nil}})) } - } blockDir := createBlock(t, tmpdir, seriesEntries) diff --git a/tsdb/chunkenc/histogram_meta.go b/tsdb/chunkenc/histogram_meta.go index 70f129b953..9aae485a83 100644 --- a/tsdb/chunkenc/histogram_meta.go +++ b/tsdb/chunkenc/histogram_meta.go @@ -73,7 +73,6 @@ func readHistogramChunkLayoutSpans(b *bstreamReader) ([]histogram.Span, error) { return nil, err } for i := 0; i < int(num); i++ { - length, err := readVarbitUint(b) if err != nil { return nil, err diff --git a/tsdb/db.go b/tsdb/db.go index d675635d7a..22292ab16e 100644 --- a/tsdb/db.go +++ b/tsdb/db.go @@ -1766,7 +1766,6 @@ func OverlappingBlocks(bm []BlockMeta) Overlaps { // Fetch the critical overlapped time range foreach overlap groups. overlapGroups := Overlaps{} for _, overlap := range overlaps { - minRange := TimeRange{Min: 0, Max: math.MaxInt64} for _, b := range overlap { if minRange.Max > b.MaxTime { diff --git a/tsdb/head_append.go b/tsdb/head_append.go index 23c2c0fbd7..efd573b410 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -1275,7 +1275,6 @@ func (s *memSeries) appendPreprocessor(t int64, e chunkenc.Encoding, o chunkOpts // encoding. So we cut a new chunk with the expected encoding. c = s.cutNewHeadChunk(t, e, o.chunkRange) chunkCreated = true - } numSamples := c.chunk.NumSamples() diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 750c8a11e5..d9631b3b91 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -1215,7 +1215,6 @@ func TestHeadDeleteSimple(t *testing.T) { for _, smpl := range smplsAll { _, err := app.Append(0, lblsDefault, smpl.t, smpl.f) require.NoError(t, err) - } require.NoError(t, app.Commit()) @@ -1229,7 +1228,6 @@ func TestHeadDeleteSimple(t *testing.T) { for _, smpl := range c.addSamples { _, err := app.Append(0, lblsDefault, smpl.t, smpl.f) require.NoError(t, err) - } require.NoError(t, app.Commit()) @@ -3851,7 +3849,6 @@ func TestChunkSnapshot(t *testing.T) { } { // Additional data to only include in WAL and m-mapped chunks and not snapshot. This mimics having an old snapshot on disk. - // Add more samples. app := head.Appender(context.Background()) for i := 1; i <= numSeries; i++ { diff --git a/tsdb/head_wal.go b/tsdb/head_wal.go index dd836a537c..076768f4ef 100644 --- a/tsdb/head_wal.go +++ b/tsdb/head_wal.go @@ -1323,7 +1323,6 @@ func DeleteChunkSnapshots(dir string, maxIndex, maxOffset int) error { errs.Add(err) } } - } return errs.Err() } diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 7ab890b99e..89c2041a76 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -1528,7 +1528,6 @@ func (r *Reader) LabelValues(ctx context.Context, name string, matchers ...*labe values = append(values, k) } return values, nil - } e, ok := r.postings[name] if !ok { diff --git a/tsdb/querier.go b/tsdb/querier.go index 2ee7f5153b..8ebedfe52d 100644 --- a/tsdb/querier.go +++ b/tsdb/querier.go @@ -844,7 +844,6 @@ func (p *populateWithDelChunkSeriesIterator) Next() bool { return true } } - } return false } diff --git a/tsdb/wlog/watcher.go b/tsdb/wlog/watcher.go index b924944689..8ebd9249aa 100644 --- a/tsdb/wlog/watcher.go +++ b/tsdb/wlog/watcher.go @@ -213,7 +213,6 @@ func (w *Watcher) setMetrics() { w.samplesSentPreTailing = w.metrics.samplesSentPreTailing.WithLabelValues(w.name) w.currentSegmentMetric = w.metrics.currentSegment.WithLabelValues(w.name) w.notificationsSkipped = w.metrics.notificationsSkipped.WithLabelValues(w.name) - } } From 3b8fe00767d7d951aee612ef4b4a6eae379e6223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giedrius=20Statkevi=C4=8Dius?= Date: Thu, 11 Apr 2024 11:30:05 +0300 Subject: [PATCH 248/253] tsdb/wlog: unregister metrics on WL close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanos can create and destroy TSDBs dynamically, and once a TSDB disappears its files are deleted. Calculating the size of the WAL then fails with errors like: ``` msg: "Failed to calculate size of "wal" dir", "err": "lstat /tsdbdir/wal: no such file or directory", "caller": "wlog.go:271" ``` Signed-off-by: Giedrius Statkevičius --- tsdb/wlog/wlog.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tsdb/wlog/wlog.go b/tsdb/wlog/wlog.go index 577057fd4f..668fbb5fbc 100644 --- a/tsdb/wlog/wlog.go +++ b/tsdb/wlog/wlog.go @@ -228,10 +228,28 @@ type wlMetrics struct { currentSegment prometheus.Gauge writesFailed prometheus.Counter walFileSize prometheus.GaugeFunc + + r prometheus.Registerer +} + +func (w *wlMetrics) Unregister() { + if w.r == nil { + return + } + w.r.Unregister(w.fsyncDuration) + w.r.Unregister(w.pageFlushes) + w.r.Unregister(w.pageCompletions) + w.r.Unregister(w.truncateFail) + w.r.Unregister(w.truncateTotal) + w.r.Unregister(w.currentSegment) + w.r.Unregister(w.writesFailed) + w.r.Unregister(w.walFileSize) } func newWLMetrics(w *WL, r prometheus.Registerer) *wlMetrics { - m := &wlMetrics{} + m := &wlMetrics{ + r: r, + } m.fsyncDuration = prometheus.NewSummary(prometheus.SummaryOpts{ Name: "fsync_duration_seconds", @@ -877,6 +895,8 @@ func (w *WL) Close() (err error) { if err := w.segment.Close(); err != nil { level.Error(w.logger).Log("msg", "close previous segment", "err", err) } + + w.metrics.Unregister() w.closed = true return nil } From 612de026da8d68f0708899a33bf9e646a8ac1d62 Mon Sep 17 00:00:00 2001 From: Neeraj Gartia <80708727+NeerajGartia21@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:23:28 +0530 Subject: [PATCH 249/253] Adds Inf and NaN as Numbers to Histogram in Promql Testing Framework (#13916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit includes Inf and NaN as numbers to histogram --------- Signed-off-by: Neeraj Gartia Signed-off-by: Björn Rabenstein Co-authored-by: Björn Rabenstein --- promql/parser/lex.go | 14 ++++++++++---- promql/parser/lex_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/promql/parser/lex.go b/promql/parser/lex.go index 641bedcfcc..4e3de2a668 100644 --- a/promql/parser/lex.go +++ b/promql/parser/lex.go @@ -519,7 +519,7 @@ func lexHistogram(l *Lexer) stateFn { return lexHistogram case r == '-': l.emit(SUB) - return lexNumber + return lexHistogram case r == 'x': l.emit(TIMES) return lexNumber @@ -568,10 +568,16 @@ Loop: return lexHistogram } l.errorf("missing `:` for histogram descriptor") - } else { - l.errorf("bad histogram descriptor found: %q", word) + break Loop } - + // Current word is Inf or NaN. + if desc, ok := key[strings.ToLower(word)]; ok { + if desc == NUMBER { + l.emit(desc) + return lexHistogram + } + } + l.errorf("bad histogram descriptor found: %q", word) break Loop } } diff --git a/promql/parser/lex_test.go b/promql/parser/lex_test.go index 4a29351b06..f48c457c0c 100644 --- a/promql/parser/lex_test.go +++ b/promql/parser/lex_test.go @@ -561,6 +561,35 @@ var tests = []struct { }, seriesDesc: true, }, + { // Series with sum as -Inf and count as NaN. + input: `{} {{buckets: [5 10 7] sum:Inf count:NaN}}`, + expected: []Item{ + {LEFT_BRACE, 0, `{`}, + {RIGHT_BRACE, 1, `}`}, + {SPACE, 2, ` `}, + {OPEN_HIST, 3, `{{`}, + {BUCKETS_DESC, 5, `buckets`}, + {COLON, 12, `:`}, + {SPACE, 13, ` `}, + {LEFT_BRACKET, 14, `[`}, + {NUMBER, 15, `5`}, + {SPACE, 16, ` `}, + {NUMBER, 17, `10`}, + {SPACE, 19, ` `}, + {NUMBER, 20, `7`}, + {RIGHT_BRACKET, 21, `]`}, + {SPACE, 22, ` `}, + {SUM_DESC, 23, `sum`}, + {COLON, 26, `:`}, + {NUMBER, 27, `Inf`}, + {SPACE, 30, ` `}, + {COUNT_DESC, 31, `count`}, + {COLON, 36, `:`}, + {NUMBER, 37, `NaN`}, + {CLOSE_HIST, 40, `}}`}, + }, + seriesDesc: true, + }, }, }, { From 4a6f8704efcabfe9ee0f74eab58d4c11579547be Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sat, 13 Apr 2024 06:59:54 -0400 Subject: [PATCH 250/253] parser: remake generated_parser output (#13923) In a previous PR, the generated parser was created using an old version of goyacc. Also adds -l to disable line directives, which fixes debug processing and reduces diffs at the expense of making it more difficult to reason about the generated output. Signed-off-by: Owen Williams --- Makefile | 2 +- promql/parser/generated_parser.y.go | 76 ++++++++++++++--------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index d78813068e..61e8f4377c 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ ifeq (, $(shell command -v goyacc 2> /dev/null)) @echo "goyacc not installed so skipping" @echo "To install: go install golang.org/x/tools/cmd/goyacc@v0.6.0" else - goyacc -o promql/parser/generated_parser.y.go promql/parser/generated_parser.y + goyacc -l -o promql/parser/generated_parser.y.go promql/parser/generated_parser.y endif .PHONY: test diff --git a/promql/parser/generated_parser.y.go b/promql/parser/generated_parser.y.go index 4fc4196e1a..3075b9b1b1 100644 --- a/promql/parser/generated_parser.y.go +++ b/promql/parser/generated_parser.y.go @@ -225,7 +225,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyInitialStackSize = 16 -var yyExca = [...]int{ +var yyExca = [...]int16{ -1, 1, 1, -1, -2, 0, @@ -376,7 +376,7 @@ const yyPrivate = 57344 const yyLast = 742 -var yyAct = [...]int{ +var yyAct = [...]int16{ 151, 322, 320, 268, 327, 148, 221, 37, 187, 144, 281, 280, 152, 113, 77, 173, 104, 102, 101, 6, 128, 223, 105, 193, 155, 194, 195, 196, 339, 262, @@ -454,7 +454,7 @@ var yyAct = [...]int{ 0, 98, } -var yyPact = [...]int{ +var yyPact = [...]int16{ 17, 153, 541, 541, 385, 500, -1000, -1000, -1000, 146, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -492,7 +492,7 @@ var yyPact = [...]int{ -1000, -1000, } -var yyPgo = [...]int{ +var yyPgo = [...]int16{ 0, 353, 13, 352, 6, 15, 350, 263, 349, 347, 344, 209, 265, 343, 14, 342, 10, 11, 341, 337, 8, 336, 3, 4, 333, 2, 1, 0, 332, 12, @@ -501,7 +501,7 @@ var yyPgo = [...]int{ 290, 249, 9, 271, 270, 268, } -var yyR1 = [...]int{ +var yyR1 = [...]int8{ 0, 54, 54, 54, 54, 54, 54, 54, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 32, 32, 32, 32, 33, 33, 35, 35, 35, 35, @@ -528,7 +528,7 @@ var yyR1 = [...]int{ 17, 17, } -var yyR2 = [...]int{ +var yyR2 = [...]int8{ 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, @@ -555,7 +555,7 @@ var yyR2 = [...]int{ 0, 1, } -var yyChk = [...]int{ +var yyChk = [...]int16{ -1000, -54, 88, 89, 90, 91, 2, 10, -12, -7, -11, 60, 61, 75, 62, 63, 64, 12, 45, 46, 49, 65, 18, 66, 79, 67, 68, 69, 70, 71, @@ -593,7 +593,7 @@ var yyChk = [...]int{ 21, -27, } -var yyDef = [...]int{ +var yyDef = [...]int16{ 0, -2, 125, 125, 0, 0, 7, 6, 1, 125, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, @@ -631,11 +631,11 @@ var yyDef = [...]int{ 166, 168, } -var yyTok1 = [...]int{ +var yyTok1 = [...]int8{ 1, } -var yyTok2 = [...]int{ +var yyTok2 = [...]int8{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -648,7 +648,7 @@ var yyTok2 = [...]int{ 92, } -var yyTok3 = [...]int{ +var yyTok3 = [...]int8{ 0, } @@ -728,9 +728,9 @@ func yyErrorMessage(state, lookAhead int) string { expected := make([]int, 0, 4) // Look for shiftable tokens. - base := yyPact[state] + base := int(yyPact[state]) for tok := TOKSTART; tok-1 < len(yyToknames); tok++ { - if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok { + if n := base + tok; n >= 0 && n < yyLast && int(yyChk[int(yyAct[n])]) == tok { if len(expected) == cap(expected) { return res } @@ -740,13 +740,13 @@ func yyErrorMessage(state, lookAhead int) string { if yyDef[state] == -2 { i := 0 - for yyExca[i] != -1 || yyExca[i+1] != state { + for yyExca[i] != -1 || int(yyExca[i+1]) != state { i += 2 } // Look for tokens that we accept or reduce. for i += 2; yyExca[i] >= 0; i += 2 { - tok := yyExca[i] + tok := int(yyExca[i]) if tok < TOKSTART || yyExca[i+1] == 0 { continue } @@ -777,30 +777,30 @@ func yylex1(lex yyLexer, lval *yySymType) (char, token int) { token = 0 char = lex.Lex(lval) if char <= 0 { - token = yyTok1[0] + token = int(yyTok1[0]) goto out } if char < len(yyTok1) { - token = yyTok1[char] + token = int(yyTok1[char]) goto out } if char >= yyPrivate { if char < yyPrivate+len(yyTok2) { - token = yyTok2[char-yyPrivate] + token = int(yyTok2[char-yyPrivate]) goto out } } for i := 0; i < len(yyTok3); i += 2 { - token = yyTok3[i+0] + token = int(yyTok3[i+0]) if token == char { - token = yyTok3[i+1] + token = int(yyTok3[i+1]) goto out } } out: if token == 0 { - token = yyTok2[1] /* unknown char */ + token = int(yyTok2[1]) /* unknown char */ } if yyDebug >= 3 { __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) @@ -855,7 +855,7 @@ yystack: yyS[yyp].yys = yystate yynewstate: - yyn = yyPact[yystate] + yyn = int(yyPact[yystate]) if yyn <= yyFlag { goto yydefault /* simple state */ } @@ -866,8 +866,8 @@ yynewstate: if yyn < 0 || yyn >= yyLast { goto yydefault } - yyn = yyAct[yyn] - if yyChk[yyn] == yytoken { /* valid shift */ + yyn = int(yyAct[yyn]) + if int(yyChk[yyn]) == yytoken { /* valid shift */ yyrcvr.char = -1 yytoken = -1 yyVAL = yyrcvr.lval @@ -880,7 +880,7 @@ yynewstate: yydefault: /* default state action */ - yyn = yyDef[yystate] + yyn = int(yyDef[yystate]) if yyn == -2 { if yyrcvr.char < 0 { yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) @@ -889,18 +889,18 @@ yydefault: /* look through exception table */ xi := 0 for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + if yyExca[xi+0] == -1 && int(yyExca[xi+1]) == yystate { break } xi += 2 } for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] + yyn = int(yyExca[xi+0]) if yyn < 0 || yyn == yytoken { break } } - yyn = yyExca[xi+1] + yyn = int(yyExca[xi+1]) if yyn < 0 { goto ret0 } @@ -922,10 +922,10 @@ yydefault: /* find a state where "error" is a legal shift action */ for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode + yyn = int(yyPact[yyS[yyp].yys]) + yyErrCode if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { + yystate = int(yyAct[yyn]) /* simulate a shift of "error" */ + if int(yyChk[yystate]) == yyErrCode { goto yystack } } @@ -961,7 +961,7 @@ yydefault: yypt := yyp _ = yypt // guard against "declared and not used" - yyp -= yyR2[yyn] + yyp -= int(yyR2[yyn]) // yyp is now the index of $0. Perform the default action. Iff the // reduced production is ε, $1 is possibly out of range. if yyp+1 >= len(yyS) { @@ -972,16 +972,16 @@ yydefault: yyVAL = yyS[yyp+1] /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] + yyn = int(yyR1[yyn]) + yyg := int(yyPgo[yyn]) yyj := yyg + yyS[yyp].yys + 1 if yyj >= yyLast { - yystate = yyAct[yyg] + yystate = int(yyAct[yyg]) } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] + yystate = int(yyAct[yyj]) + if int(yyChk[yystate]) != -yyn { + yystate = int(yyAct[yyg]) } } // dummy call; replaced with literal code From 7704cde4ea3b993dbd0a780ac873e7158a7bb3fc Mon Sep 17 00:00:00 2001 From: Simon Pasquier Date: Fri, 12 Apr 2024 16:40:08 +0200 Subject: [PATCH 251/253] discovery(k8s): add metadata labels to endpointslices This commit adds 2 new metadata labels for the endpointslice role: * `__meta_kubernetes_endpointslice_endpoint_node_name` * `__meta_kubernetes_endpointslice_endpoint_zone` The latter is only present when the `discovery.k8s.io/v1` API group is available. I also updated the configuration doc and added an entry for the `__meta_kubernetes_endpointslice_endpoint_hostname` label which was missing. Signed-off-by: Simon Pasquier --- discovery/kubernetes/endpointslice.go | 10 ++++ discovery/kubernetes/endpointslice_adaptor.go | 9 ++++ discovery/kubernetes/endpointslice_test.go | 54 +++++++++++++++++++ docs/configuration/configuration.md | 11 ++-- 4 files changed, 80 insertions(+), 4 deletions(-) diff --git a/discovery/kubernetes/endpointslice.go b/discovery/kubernetes/endpointslice.go index 116f02076f..7a70255c12 100644 --- a/discovery/kubernetes/endpointslice.go +++ b/discovery/kubernetes/endpointslice.go @@ -265,7 +265,9 @@ const ( endpointSliceEndpointConditionsReadyLabel = metaLabelPrefix + "endpointslice_endpoint_conditions_ready" endpointSliceEndpointConditionsServingLabel = metaLabelPrefix + "endpointslice_endpoint_conditions_serving" endpointSliceEndpointConditionsTerminatingLabel = metaLabelPrefix + "endpointslice_endpoint_conditions_terminating" + endpointSliceEndpointZoneLabel = metaLabelPrefix + "endpointslice_endpoint_zone" endpointSliceEndpointHostnameLabel = metaLabelPrefix + "endpointslice_endpoint_hostname" + endpointSliceEndpointNodenameLabel = metaLabelPrefix + "endpointslice_endpoint_node_name" endpointSliceAddressTargetKindLabel = metaLabelPrefix + "endpointslice_address_target_kind" endpointSliceAddressTargetNameLabel = metaLabelPrefix + "endpointslice_address_target_name" endpointSliceEndpointTopologyLabelPrefix = metaLabelPrefix + "endpointslice_endpoint_topology_" @@ -338,6 +340,14 @@ func (e *EndpointSlice) buildEndpointSlice(eps endpointSliceAdaptor) *targetgrou target[model.LabelName(endpointSliceAddressTargetNameLabel)] = lv(ep.targetRef().Name) } + if ep.nodename() != nil { + target[endpointSliceEndpointNodenameLabel] = lv(*ep.nodename()) + } + + if ep.zone() != nil { + target[model.LabelName(endpointSliceEndpointZoneLabel)] = lv(*ep.zone()) + } + for k, v := range ep.topology() { ln := strutil.SanitizeLabelName(k) target[model.LabelName(endpointSliceEndpointTopologyLabelPrefix+ln)] = lv(v) diff --git a/discovery/kubernetes/endpointslice_adaptor.go b/discovery/kubernetes/endpointslice_adaptor.go index 6bd5f40b7a..edd64fcb32 100644 --- a/discovery/kubernetes/endpointslice_adaptor.go +++ b/discovery/kubernetes/endpointslice_adaptor.go @@ -44,6 +44,7 @@ type endpointSliceEndpointAdaptor interface { addresses() []string hostname() *string nodename() *string + zone() *string conditions() endpointSliceEndpointConditionsAdaptor targetRef() *corev1.ObjectReference topology() map[string]string @@ -181,6 +182,10 @@ func (e *endpointSliceEndpointAdaptorV1) nodename() *string { return e.endpoint.NodeName } +func (e *endpointSliceEndpointAdaptorV1) zone() *string { + return e.endpoint.Zone +} + func (e *endpointSliceEndpointAdaptorV1) conditions() endpointSliceEndpointConditionsAdaptor { return newEndpointSliceEndpointConditionsAdaptorFromV1(e.endpoint.Conditions) } @@ -233,6 +238,10 @@ func (e *endpointSliceEndpointAdaptorV1beta1) nodename() *string { return e.endpoint.NodeName } +func (e *endpointSliceEndpointAdaptorV1beta1) zone() *string { + return nil +} + func (e *endpointSliceEndpointAdaptorV1beta1) conditions() endpointSliceEndpointConditionsAdaptor { return newEndpointSliceEndpointConditionsAdaptorFromV1beta1(e.endpoint.Conditions) } diff --git a/discovery/kubernetes/endpointslice_test.go b/discovery/kubernetes/endpointslice_test.go index a6579b9543..6ef83081be 100644 --- a/discovery/kubernetes/endpointslice_test.go +++ b/discovery/kubernetes/endpointslice_test.go @@ -80,6 +80,7 @@ func makeEndpointSliceV1() *v1.EndpointSlice { DeprecatedTopology: map[string]string{ "topology": "value", }, + Zone: strptr("us-east-1a"), }, { Addresses: []string{"2.3.4.5"}, Conditions: v1.EndpointConditions{ @@ -87,6 +88,7 @@ func makeEndpointSliceV1() *v1.EndpointSlice { Serving: boolptr(true), Terminating: boolptr(false), }, + Zone: strptr("us-east-1b"), }, { Addresses: []string{"3.4.5.6"}, Conditions: v1.EndpointConditions{ @@ -94,6 +96,7 @@ func makeEndpointSliceV1() *v1.EndpointSlice { Serving: boolptr(true), Terminating: boolptr(true), }, + Zone: strptr("us-east-1c"), }, { Addresses: []string{"4.5.6.7"}, Conditions: v1.EndpointConditions{ @@ -105,6 +108,7 @@ func makeEndpointSliceV1() *v1.EndpointSlice { Kind: "Node", Name: "barbaz", }, + Zone: strptr("us-east-1a"), }, }, } @@ -185,8 +189,10 @@ func TestEndpointSliceDiscoveryBeforeRun(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -197,6 +203,7 @@ func TestEndpointSliceDiscoveryBeforeRun(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -207,6 +214,7 @@ func TestEndpointSliceDiscoveryBeforeRun(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -219,6 +227,7 @@ func TestEndpointSliceDiscoveryBeforeRun(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -452,8 +461,10 @@ func TestEndpointSliceDiscoveryDelete(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -464,6 +475,7 @@ func TestEndpointSliceDiscoveryDelete(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -474,6 +486,7 @@ func TestEndpointSliceDiscoveryDelete(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -486,6 +499,7 @@ func TestEndpointSliceDiscoveryDelete(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -552,8 +566,10 @@ func TestEndpointSliceDiscoveryUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -564,6 +580,7 @@ func TestEndpointSliceDiscoveryUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -574,6 +591,7 @@ func TestEndpointSliceDiscoveryUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -586,6 +604,7 @@ func TestEndpointSliceDiscoveryUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -641,8 +660,10 @@ func TestEndpointSliceDiscoveryEmptyEndpoints(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -653,6 +674,7 @@ func TestEndpointSliceDiscoveryEmptyEndpoints(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -663,6 +685,7 @@ func TestEndpointSliceDiscoveryEmptyEndpoints(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -675,6 +698,7 @@ func TestEndpointSliceDiscoveryEmptyEndpoints(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -725,8 +749,10 @@ func TestEndpointSliceDiscoveryWithService(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -737,6 +763,7 @@ func TestEndpointSliceDiscoveryWithService(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -747,6 +774,7 @@ func TestEndpointSliceDiscoveryWithService(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -759,6 +787,7 @@ func TestEndpointSliceDiscoveryWithService(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -825,8 +854,10 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -837,6 +868,7 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_name": "testport", "__meta_kubernetes_endpointslice_port_protocol": "TCP", @@ -847,6 +879,7 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_name": "testport", "__meta_kubernetes_endpointslice_port_protocol": "TCP", @@ -859,6 +892,7 @@ func TestEndpointSliceDiscoveryWithServiceUpdate(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -915,8 +949,10 @@ func TestEndpointsSlicesDiscoveryWithNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -930,6 +966,7 @@ func TestEndpointsSlicesDiscoveryWithNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -940,6 +977,7 @@ func TestEndpointsSlicesDiscoveryWithNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -952,6 +990,7 @@ func TestEndpointsSlicesDiscoveryWithNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1015,8 +1054,10 @@ func TestEndpointsSlicesDiscoveryWithUpdatedNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1030,6 +1071,7 @@ func TestEndpointsSlicesDiscoveryWithUpdatedNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1040,6 +1082,7 @@ func TestEndpointsSlicesDiscoveryWithUpdatedNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1052,6 +1095,7 @@ func TestEndpointsSlicesDiscoveryWithUpdatedNodeMetadata(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1161,8 +1205,10 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1173,6 +1219,7 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_name": "testport", "__meta_kubernetes_endpointslice_port_protocol": "TCP", @@ -1183,6 +1230,7 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_name": "testport", "__meta_kubernetes_endpointslice_port_protocol": "TCP", @@ -1195,6 +1243,7 @@ func TestEndpointSliceDiscoveryNamespaces(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1309,8 +1358,10 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", "__meta_kubernetes_endpointslice_endpoint_hostname": "testendpoint1", + "__meta_kubernetes_endpointslice_endpoint_node_name": "foobar", "__meta_kubernetes_endpointslice_endpoint_topology_present_topology": "true", "__meta_kubernetes_endpointslice_endpoint_topology_topology": "value", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", @@ -1321,6 +1372,7 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1b", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_name": "testport", "__meta_kubernetes_endpointslice_port_protocol": "TCP", @@ -1331,6 +1383,7 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "false", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "true", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1c", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_name": "testport", "__meta_kubernetes_endpointslice_port_protocol": "TCP", @@ -1343,6 +1396,7 @@ func TestEndpointSliceDiscoveryOwnNamespace(t *testing.T) { "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true", "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false", + "__meta_kubernetes_endpointslice_endpoint_zone": "us-east-1a", "__meta_kubernetes_endpointslice_port": "9000", "__meta_kubernetes_endpointslice_port_app_protocol": "http", "__meta_kubernetes_endpointslice_port_name": "testport", diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 51eb84ae19..2f2e07a0c2 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -2118,11 +2118,14 @@ Available meta labels: * `__meta_kubernetes_endpointslice_address_target_kind`: Kind of the referenced object. * `__meta_kubernetes_endpointslice_address_target_name`: Name of referenced object. * `__meta_kubernetes_endpointslice_address_type`: The ip protocol family of the address of the target. - * `__meta_kubernetes_endpointslice_endpoint_conditions_ready`: Set to `true` or `false` for the referenced endpoint's ready state. - * `__meta_kubernetes_endpointslice_endpoint_conditions_serving`: Set to `true` or `false` for the referenced endpoint's serving state. - * `__meta_kubernetes_endpointslice_endpoint_conditions_terminating`: Set to `true` or `false` for the referenced endpoint's terminating state. - * `__meta_kubernetes_endpointslice_endpoint_topology_kubernetes_io_hostname`: Name of the node hosting the referenced endpoint. + * `__meta_kubernetes_endpointslice_endpoint_conditions_ready`: Set to `true` or `false` for the referenced endpoint's ready state. + * `__meta_kubernetes_endpointslice_endpoint_conditions_serving`: Set to `true` or `false` for the referenced endpoint's serving state. + * `__meta_kubernetes_endpointslice_endpoint_conditions_terminating`: Set to `true` or `false` for the referenced endpoint's terminating state. + * `__meta_kubernetes_endpointslice_endpoint_topology_kubernetes_io_hostname`: Name of the node hosting the referenced endpoint. * `__meta_kubernetes_endpointslice_endpoint_topology_present_kubernetes_io_hostname`: Flag that shows if the referenced object has a kubernetes.io/hostname annotation. + * `__meta_kubernetes_endpointslice_endpoint_hostname`: Hostname of the referenced endpoint. + * `__meta_kubernetes_endpointslice_endpoint_node_name`: Name of the Node hosting the referenced endpoint. + * `__meta_kubernetes_endpointslice_endpoint_zone`: Zone the referenced endpoint exists in (only available when using the `discovery.k8s.io/v1` API group). * `__meta_kubernetes_endpointslice_port`: Port of the referenced endpoint. * `__meta_kubernetes_endpointslice_port_name`: Named port of the referenced endpoint. * `__meta_kubernetes_endpointslice_port_protocol`: Protocol of the referenced endpoint. From bdf490726aa39a9449c48fdfc3cddd8269cee7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giedrius=20Statkevi=C4=8Dius?= Date: Thu, 18 Apr 2024 11:11:37 +0300 Subject: [PATCH 252/253] tsdb/wlog: add test for metrics unregistering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Giedrius Statkevičius --- tsdb/wlog/wlog_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tsdb/wlog/wlog_test.go b/tsdb/wlog/wlog_test.go index 7d96920117..165d2758f0 100644 --- a/tsdb/wlog/wlog_test.go +++ b/tsdb/wlog/wlog_test.go @@ -23,6 +23,8 @@ import ( "path/filepath" "testing" + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" client_testutil "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" "go.uber.org/goleak" @@ -561,3 +563,13 @@ func BenchmarkWAL_Log(b *testing.B) { }) } } + +func TestUnregisterMetrics(t *testing.T) { + reg := prometheus.NewRegistry() + + for i := 0; i < 2; i++ { + wl, err := New(log.NewNopLogger(), reg, t.TempDir(), CompressionNone) + require.NoError(t, err) + require.NoError(t, wl.Close()) + } +} From 4aca4e2cbdc7f74fa80dc56ae2644dad55d663c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:27:33 +0000 Subject: [PATCH 253/253] build(deps): bump github.com/prometheus/common Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.50.0 to 0.53.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.50.0...v0.53.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- documentation/examples/remote_storage/go.mod | 2 +- documentation/examples/remote_storage/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/examples/remote_storage/go.mod b/documentation/examples/remote_storage/go.mod index 36ee5c4d20..dff988131b 100644 --- a/documentation/examples/remote_storage/go.mod +++ b/documentation/examples/remote_storage/go.mod @@ -9,7 +9,7 @@ require ( github.com/golang/snappy v0.0.4 github.com/influxdata/influxdb v1.11.5 github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/common v0.50.0 + github.com/prometheus/common v0.53.0 github.com/prometheus/prometheus v0.51.1 github.com/stretchr/testify v1.9.0 ) diff --git a/documentation/examples/remote_storage/go.sum b/documentation/examples/remote_storage/go.sum index bc5b2ddaa1..b145f362f4 100644 --- a/documentation/examples/remote_storage/go.sum +++ b/documentation/examples/remote_storage/go.sum @@ -269,8 +269,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.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ= -github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ= +github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= +github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= 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=