diff --git a/.golangci.yml b/.golangci.yml index 5fdb7ea98..657ff93a7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -11,6 +11,7 @@ linters: - govet - loggercheck - misspell + - modernize - nilnesserr # TODO(bwplotka): Enable once https://github.com/golangci/golangci-lint/issues/3228 is fixed. # - nolintlint @@ -43,6 +44,9 @@ linters: - linters: - gocritic text: "appendAssign" + - linters: + - errcheck + path: _test.go warn-unused: true settings: depguard: @@ -77,6 +81,15 @@ linters: - shadow - fieldalignment enable-all: true + modernize: + disable: + # Suggest replacing omitempty with omitzero for struct fields. + # Disable this check for now since it introduces too many changes in our existing codebase. + # See https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#hdr-Analyzer_omitzero for more details. + - omitzero + # Disable newexpr check for now since it introduces too many changes in our existing codebase. + # To be re-enabled as a part of https://github.com/prometheus/prometheus/issues/18066. + - newexpr perfsprint: # Optimizes even if it requires an int or uint type cast. int-conversion: true diff --git a/config/config.go b/config/config.go index ff54cdd82..d0040763e 100644 --- a/config/config.go +++ b/config/config.go @@ -33,7 +33,7 @@ type Secret string var MarshalSecretValue = false // MarshalYAML implements the yaml.Marshaler interface for Secrets. -func (s Secret) MarshalYAML() (interface{}, error) { +func (s Secret) MarshalYAML() (any, error) { if MarshalSecretValue { return string(s), nil } @@ -44,7 +44,7 @@ func (s Secret) MarshalYAML() (interface{}, error) { } // UnmarshalYAML implements the yaml.Unmarshaler interface for Secrets. -func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (s *Secret) UnmarshalYAML(unmarshal func(any) error) error { type plain Secret return unmarshal((*plain)(s)) } diff --git a/config/http_config.go b/config/http_config.go index 7089fc75a..03e0f0388 100644 --- a/config/http_config.go +++ b/config/http_config.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "net" "net/http" "net/url" @@ -76,7 +77,7 @@ var TLSVersions = map[string]TLSVersion{ "TLS10": (TLSVersion)(tls.VersionTLS10), } -func (tv *TLSVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (tv *TLSVersion) UnmarshalYAML(unmarshal func(any) error) error { var s string err := unmarshal(&s) if err != nil { @@ -89,7 +90,7 @@ func (tv *TLSVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { return fmt.Errorf("unknown TLS version: %s", s) } -func (tv TLSVersion) MarshalYAML() (interface{}, error) { +func (tv TLSVersion) MarshalYAML() (any, error) { for s, v := range TLSVersions { if tv == v { return s, nil @@ -178,7 +179,7 @@ type URL struct { } // UnmarshalYAML implements the yaml.Unmarshaler interface for URLs. -func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (u *URL) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err @@ -193,7 +194,7 @@ func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error { } // MarshalYAML implements the yaml.Marshaler interface for URLs. -func (u URL) MarshalYAML() (interface{}, error) { +func (u URL) MarshalYAML() (any, error) { if u.URL != nil { return u.Redacted(), nil } @@ -269,16 +270,16 @@ type OAuth2 struct { Audience string `yaml:"audience,omitempty" json:"audience,omitempty"` // Claims is a map of claims to be added to the JWT token. Only used if // GrantType is set to "urn:ietf:params:oauth:grant-type:jwt-bearer". - Claims map[string]interface{} `yaml:"claims,omitempty" json:"claims,omitempty"` - Scopes []string `yaml:"scopes,omitempty" json:"scopes,omitempty"` - TokenURL string `yaml:"token_url,omitempty" json:"token_url,omitempty"` - EndpointParams map[string]string `yaml:"endpoint_params,omitempty" json:"endpoint_params,omitempty"` - TLSConfig TLSConfig `yaml:"tls_config,omitempty"` + Claims map[string]any `yaml:"claims,omitempty" json:"claims,omitempty"` + Scopes []string `yaml:"scopes,omitempty" json:"scopes,omitempty"` + TokenURL string `yaml:"token_url,omitempty" json:"token_url,omitempty"` + EndpointParams map[string]string `yaml:"endpoint_params,omitempty" json:"endpoint_params,omitempty"` + TLSConfig TLSConfig `yaml:"tls_config,omitempty"` ProxyConfig `yaml:",inline"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (o *OAuth2) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (o *OAuth2) UnmarshalYAML(unmarshal func(any) error) error { type plain OAuth2 if err := unmarshal((*plain)(o)); err != nil { return err @@ -463,7 +464,7 @@ func (c *HTTPClientConfig) Validate() error { } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *HTTPClientConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (c *HTTPClientConfig) UnmarshalYAML(unmarshal func(any) error) error { type plain HTTPClientConfig *c = DefaultHTTPClientConfig if err := unmarshal((*plain)(c)); err != nil { @@ -483,7 +484,7 @@ func (c *HTTPClientConfig) UnmarshalJSON(data []byte) error { } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (a *BasicAuth) UnmarshalYAML(unmarshal func(any) error) error { type plain BasicAuth return unmarshal((*plain)(a)) } @@ -1130,10 +1131,7 @@ func cloneRequest(r *http.Request) *http.Request { r2 := new(http.Request) *r2 = *r // Deep copy of the Header. - r2.Header = make(http.Header) - for k, s := range r.Header { - r2.Header[k] = s - } + maps.Copy(r.Header, r2.Header) return r2 } @@ -1256,7 +1254,7 @@ func (c *TLSConfig) SetDirectory(dir string) { } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (c *TLSConfig) UnmarshalYAML(unmarshal func(any) error) error { type plain TLSConfig if err := unmarshal((*plain)(c)); err != nil { return err diff --git a/config/http_config_test.go b/config/http_config_test.go index 26f7d5f54..8c7668f77 100644 --- a/config/http_config_test.go +++ b/config/http_config_test.go @@ -1128,7 +1128,6 @@ func TestTLSRoundTripper(t *testing.T) { var c *http.Client for i, tc := range testCases { - tc := tc t.Run(strconv.Itoa(i), func(t *testing.T) { writeCertificate(bs, tc.ca, ca) writeCertificate(bs, tc.cert, cert) @@ -1239,7 +1238,6 @@ func TestTLSRoundTripper_Inline(t *testing.T) { } for i, tc := range testCases { - tc := tc t.Run(strconv.Itoa(i), func(t *testing.T) { cfg := HTTPClientConfig{ TLSConfig: TLSConfig{ @@ -1316,10 +1314,8 @@ func TestTLSRoundTripperRaces(t *testing.T) { ch := make(chan struct{}) var total, ok int64 // Spawn 10 Go routines polling the server concurrently. - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 10 { + wg.Go(func() { for { select { case <-ch: @@ -1333,13 +1329,11 @@ func TestTLSRoundTripperRaces(t *testing.T) { } } } - }() + }) } // Change the CA file every 10ms for 1 second. - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { i := 0 for { tick := time.NewTicker(10 * time.Millisecond) @@ -1355,7 +1349,7 @@ func TestTLSRoundTripperRaces(t *testing.T) { return } } - }() + }) wg.Wait() require.NotEqualf(t, ok, total, "Expecting some requests to fail but got %d/%d successful requests", ok, total) @@ -1788,7 +1782,7 @@ endpoint_params: Scopes: []string{"A", "B"}, TokenURL: ts.tokenURL(), EndpointParams: map[string]string{"hi": "hello"}, - Claims: map[string]interface{}{ + Claims: map[string]any{ "iss": "https://example.com", "aud": "common-test", "sub": "common", diff --git a/config/oauth_assertion.go b/config/oauth_assertion.go index bf4bcb949..ba5ffb4dc 100644 --- a/config/oauth_assertion.go +++ b/config/oauth_assertion.go @@ -18,6 +18,7 @@ import ( "encoding/json" "fmt" "io" + "maps" "net/http" "net/url" "strings" @@ -133,9 +134,7 @@ func (js jwtSource) Token() (*oauth2.Token, error) { claims["scope"] = scopes } - for k, v := range js.conf.PrivateClaims { - claims[k] = v - } + maps.Copy(claims, js.conf.PrivateClaims) assertion := jwt.NewWithClaims(js.conf.SigningAlgorithm, claims) if js.conf.PrivateKeyID != "" { diff --git a/expfmt/expfmt.go b/expfmt/expfmt.go index 4e4c13e72..10bf35708 100644 --- a/expfmt/expfmt.go +++ b/expfmt/expfmt.go @@ -122,7 +122,7 @@ func NewOpenMetricsFormat(version string) (Format, error) { // removed. func (f Format) WithEscapingScheme(s model.EscapingScheme) Format { var terms []string - for _, p := range strings.Split(string(f), ";") { + for p := range strings.SplitSeq(string(f), ";") { toks := strings.Split(p, "=") if len(toks) != 2 { trimmed := strings.TrimSpace(p) @@ -194,7 +194,7 @@ func (f Format) FormatType() FormatType { // "escaping" term exists, that will be used. Otherwise, the global default will // be returned. func (f Format) ToEscapingScheme() model.EscapingScheme { - for _, p := range strings.Split(string(f), ";") { + for p := range strings.SplitSeq(string(f), ";") { toks := strings.Split(p, "=") if len(toks) != 2 { continue diff --git a/expfmt/text_create.go b/expfmt/text_create.go index 6b8978145..f4074ae9a 100644 --- a/expfmt/text_create.go +++ b/expfmt/text_create.go @@ -42,12 +42,12 @@ const ( var ( bufPool = sync.Pool{ - New: func() interface{} { + New: func() any { return bufio.NewWriter(io.Discard) }, } numBufPool = sync.Pool{ - New: func() interface{} { + New: func() any { b := make([]byte, 0, initialNumBufSize) return &b }, diff --git a/helpers/templates/time.go b/helpers/templates/time.go index b7dc655f6..d9fcaa0ab 100644 --- a/helpers/templates/time.go +++ b/helpers/templates/time.go @@ -25,7 +25,7 @@ import ( var errNaNOrInf = errors.New("value is NaN or Inf") -func ConvertToFloat(i interface{}) (float64, error) { +func ConvertToFloat(i any) (float64, error) { switch v := i.(type) { case float64: return v, nil @@ -58,7 +58,7 @@ func FloatToTime(v float64) (*time.Time, error) { return &t, nil } -func HumanizeDuration(i interface{}) (string, error) { +func HumanizeDuration(i any) (string, error) { v, err := ConvertToFloat(i) if err != nil { return "", err @@ -105,7 +105,7 @@ func HumanizeDuration(i interface{}) (string, error) { return fmt.Sprintf("%.4g%ss", v, prefix), nil } -func HumanizeTimestamp(i interface{}) (string, error) { +func HumanizeTimestamp(i any) (string, error) { v, err := ConvertToFloat(i) if err != nil { return "", err diff --git a/helpers/templates/time_test.go b/helpers/templates/time_test.go index 9bbf7c205..9c0c346d7 100644 --- a/helpers/templates/time_test.go +++ b/helpers/templates/time_test.go @@ -23,7 +23,7 @@ import ( func TestHumanizeDuration(t *testing.T) { tc := []struct { name string - input interface{} + input any expected string }{ // Integers @@ -81,7 +81,7 @@ func TestHumanizeDurationErrorString(t *testing.T) { func TestHumanizeTimestamp(t *testing.T) { tc := []struct { name string - input interface{} + input any expected string }{ // Int diff --git a/model/labels.go b/model/labels.go index dfeb34be5..29688a13c 100644 --- a/model/labels.go +++ b/model/labels.go @@ -124,7 +124,7 @@ func (ln LabelName) IsValidLegacy() bool { } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (ln *LabelName) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err diff --git a/model/labelset.go b/model/labelset.go index 9de47b256..6010b26a8 100644 --- a/model/labelset.go +++ b/model/labelset.go @@ -16,6 +16,7 @@ package model import ( "encoding/json" "fmt" + "maps" "sort" ) @@ -107,9 +108,7 @@ func (ls LabelSet) Before(o LabelSet) bool { // Clone returns a copy of the label set. func (ls LabelSet) Clone() LabelSet { lsn := make(LabelSet, len(ls)) - for ln, lv := range ls { - lsn[ln] = lv - } + maps.Copy(lsn, ls) return lsn } @@ -117,13 +116,9 @@ func (ls LabelSet) Clone() LabelSet { func (ls LabelSet) Merge(other LabelSet) LabelSet { result := make(LabelSet, len(ls)) - for k, v := range ls { - result[k] = v - } + maps.Copy(result, ls) - for k, v := range other { - result[k] = v - } + maps.Copy(result, other) return result } diff --git a/model/metric.go b/model/metric.go index 429a0dab1..2fe461511 100644 --- a/model/metric.go +++ b/model/metric.go @@ -17,6 +17,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "regexp" "sort" "strconv" @@ -258,9 +259,7 @@ func (m Metric) Before(o Metric) bool { // Clone returns a copy of the Metric. func (m Metric) Clone() Metric { clone := make(Metric, len(m)) - for k, v := range m { - clone[k] = v - } + maps.Copy(clone, m) return clone } diff --git a/model/metric_test.go b/model/metric_test.go index c997fa622..90f9f9bf6 100644 --- a/model/metric_test.go +++ b/model/metric_test.go @@ -844,7 +844,7 @@ func TestEscapeMetricFamily(t *testing.T) { }, } - unexportList := []interface{}{dto.MetricFamily{}, dto.Metric{}, dto.LabelPair{}, dto.Counter{}, dto.Gauge{}} + unexportList := []any{dto.MetricFamily{}, dto.Metric{}, dto.LabelPair{}, dto.Counter{}, dto.Gauge{}} for _, scenario := range scenarios { t.Run(scenario.name, func(t *testing.T) { diff --git a/model/signature_test.go b/model/signature_test.go index 3c08af4e6..26260e857 100644 --- a/model/signature_test.go +++ b/model/signature_test.go @@ -281,7 +281,7 @@ func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerpri end.Add(concLevel) errc := make(chan error, 1) - for i := 0; i < concLevel; i++ { + for range concLevel { go func() { start.Wait() for j := b.N / concLevel; j >= 0; j-- { diff --git a/model/time.go b/model/time.go index 1730b0fdc..8c70ce855 100644 --- a/model/time.go +++ b/model/time.go @@ -340,12 +340,12 @@ func (d *Duration) UnmarshalText(text []byte) error { } // MarshalYAML implements the yaml.Marshaler interface. -func (d Duration) MarshalYAML() (interface{}, error) { +func (d Duration) MarshalYAML() (any, error) { return d.String(), nil } // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (d *Duration) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err != nil { return err diff --git a/model/value.go b/model/value.go index a9995a37e..8dffd9c4a 100644 --- a/model/value.go +++ b/model/value.go @@ -259,13 +259,13 @@ func (s Scalar) String() string { // MarshalJSON implements json.Marshaler. func (s Scalar) MarshalJSON() ([]byte, error) { v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64) - return json.Marshal([...]interface{}{s.Timestamp, v}) + return json.Marshal([...]any{s.Timestamp, v}) } // UnmarshalJSON implements json.Unmarshaler. func (s *Scalar) UnmarshalJSON(b []byte) error { var f string - v := [...]interface{}{&s.Timestamp, &f} + v := [...]any{&s.Timestamp, &f} if err := json.Unmarshal(b, &v); err != nil { return err @@ -291,12 +291,12 @@ func (s *String) String() string { // MarshalJSON implements json.Marshaler. func (s String) MarshalJSON() ([]byte, error) { - return json.Marshal([]interface{}{s.Timestamp, s.Value}) + return json.Marshal([]any{s.Timestamp, s.Value}) } // UnmarshalJSON implements json.Unmarshaler. func (s *String) UnmarshalJSON(b []byte) error { - v := [...]interface{}{&s.Timestamp, &s.Value} + v := [...]any{&s.Timestamp, &s.Value} return json.Unmarshal(b, &v) } diff --git a/model/value_float.go b/model/value_float.go index 6bfc757d1..b7d93615e 100644 --- a/model/value_float.go +++ b/model/value_float.go @@ -79,7 +79,7 @@ func (s SamplePair) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil + return fmt.Appendf(nil, "[%s,%s]", t, v), nil } // UnmarshalJSON implements json.Unmarshaler. diff --git a/model/value_histogram.go b/model/value_histogram.go index 91ce5b7a4..f27856ccc 100644 --- a/model/value_histogram.go +++ b/model/value_histogram.go @@ -67,11 +67,11 @@ func (s HistogramBucket) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return []byte(fmt.Sprintf("[%s,%s,%s,%s]", b, l, u, c)), nil + return fmt.Appendf(nil, "[%s,%s,%s,%s]", b, l, u, c), nil } func (s *HistogramBucket) UnmarshalJSON(buf []byte) error { - tmp := []interface{}{&s.Boundaries, &s.Lower, &s.Upper, &s.Count} + tmp := []any{&s.Boundaries, &s.Lower, &s.Upper, &s.Count} wantLen := len(tmp) if err := json.Unmarshal(buf, &tmp); err != nil { return err @@ -152,11 +152,11 @@ func (s SampleHistogramPair) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil + return fmt.Appendf(nil, "[%s,%s]", t, v), nil } func (s *SampleHistogramPair) UnmarshalJSON(buf []byte) error { - tmp := []interface{}{&s.Timestamp, &s.Histogram} + tmp := []any{&s.Timestamp, &s.Histogram} wantLen := len(tmp) if err := json.Unmarshal(buf, &tmp); err != nil { return err diff --git a/promslog/slog.go b/promslog/slog.go index f5b9e98ba..f8f77165a 100644 --- a/promslog/slog.go +++ b/promslog/slog.go @@ -61,7 +61,7 @@ func NewLevel() *Level { } } -func (l *Level) UnmarshalYAML(unmarshal func(interface{}) error) error { +func (l *Level) UnmarshalYAML(unmarshal func(any) error) error { var s string type plain string if err := unmarshal((*plain)(&s)); err != nil { diff --git a/promslog/slog_test.go b/promslog/slog_test.go index 0ea1a31c2..05cbd61f0 100644 --- a/promslog/slog_test.go +++ b/promslog/slog_test.go @@ -82,8 +82,7 @@ func TestUnmarshallBadLevel(t *testing.T) { func getLogEntryLevelCounts(s string, re *regexp.Regexp) map[string]int { counters := make(map[string]int) - lines := strings.Split(s, "\n") - for _, line := range lines { + for line := range strings.SplitSeq(s, "\n") { matches := re.FindStringSubmatch(line) if len(matches) > 1 { levelIndex := re.SubexpIndex("LevelValue")