diff --git a/.golangci.reference.yml b/.golangci.reference.yml index 467381bccbf6..9cd3507b5389 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -2173,6 +2173,7 @@ linters: - whitespace - wrapcheck - wsl + - zerologlint # Enable all available linters. # Default: false @@ -2285,6 +2286,7 @@ linters: - whitespace - wrapcheck - wsl + - zerologlint # Enable presets. # https://golangci-lint.run/usage/linters diff --git a/go.mod b/go.mod index 0a21db0ce59a..d7fbe48f0e61 100644 --- a/go.mod +++ b/go.mod @@ -111,6 +111,7 @@ require ( github.com/xen0n/gosmopolitan v1.2.1 github.com/yagipy/maintidx v1.0.0 github.com/yeya24/promlinter v0.2.0 + github.com/ykadowak/zerologlint v0.1.1 gitlab.com/bosi/decorder v0.2.3 golang.org/x/tools v0.8.0 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index fe7d4a18c972..4efdef45a303 100644 --- a/go.sum +++ b/go.sum @@ -562,6 +562,8 @@ github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= +github.com/ykadowak/zerologlint v0.1.1 h1:CA1+RsGS1DbBn3jJP2jpWfiMJipWdeqJfSY0GpNgqaY= +github.com/ykadowak/zerologlint v0.1.1/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= 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= diff --git a/pkg/golinters/zerologlint.go b/pkg/golinters/zerologlint.go new file mode 100644 index 000000000000..a37bca12e272 --- /dev/null +++ b/pkg/golinters/zerologlint.go @@ -0,0 +1,17 @@ +package golinters + +import ( + "github.com/ykadowak/zerologlint" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewZerologLint() *goanalysis.Linter { + return goanalysis.NewLinter( + "zerologlint", + "Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg`.", + []*analysis.Analyzer{zerologlint.Analyzer}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index e1ccdb46e401..7f2182438927 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -890,6 +890,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.26.0"). WithPresets(linter.PresetStyle). WithURL("https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint/README.md"), + + linter.NewConfig(golinters.NewZerologLint()). + WithSince("v1.53.0"). + WithPresets(linter.PresetBugs). + WithLoadForGoAnalysis(). + WithURL("https://github.com/ykadowak/zerologlint"), } enabledByDefault := map[string]bool{ diff --git a/test/linters_test.go b/test/linters_test.go index 58af3e1c6cb2..dd130db3e7db 100644 --- a/test/linters_test.go +++ b/test/linters_test.go @@ -31,6 +31,7 @@ func TestSourcesFromTestdataSubDir(t *testing.T) { subDirs := []string{ "loggercheck", "ginkgolinter", + "zerologlint", } for _, dir := range subDirs { diff --git a/test/testdata/zerologlint/go.mod b/test/testdata/zerologlint/go.mod new file mode 100644 index 000000000000..7fa01dcba9f1 --- /dev/null +++ b/test/testdata/zerologlint/go.mod @@ -0,0 +1,14 @@ +module zerologlint + +go 1.19 + +require ( + github.com/rs/zerolog v1.29.1 + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 +) + +require ( + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + golang.org/x/sys v0.7.0 // indirect +) diff --git a/test/testdata/zerologlint/go.sum b/test/testdata/zerologlint/go.sum new file mode 100644 index 000000000000..8d3ce039655a --- /dev/null +++ b/test/testdata/zerologlint/go.sum @@ -0,0 +1,21 @@ +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +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.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/test/testdata/zerologlint/zerologlint.go b/test/testdata/zerologlint/zerologlint.go new file mode 100644 index 000000000000..3eb334908c91 --- /dev/null +++ b/test/testdata/zerologlint/zerologlint.go @@ -0,0 +1,77 @@ +//golangcitest:args -Ezerologlint +package zerologlint + +import ( + "fmt" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "golang.org/x/exp/slices" +) + +func expectWarnings() { + log.Error() // want "must be dispatched by Msg or Send method" + log.Info() // want "must be dispatched by Msg or Send method" + log.Fatal() // want "must be dispatched by Msg or Send method" + log.Debug() // want "must be dispatched by Msg or Send method" + log.Warn() // want "must be dispatched by Msg or Send method" + + err := fmt.Errorf("foobarerror") + log.Error().Err(err) // want "must be dispatched by Msg or Send method" + log.Error().Err(err).Str("foo", "bar").Int("foo", 1) // want "must be dispatched by Msg or Send method" + + logger := log.Error() // want "must be dispatched by Msg or Send method" + logger.Err(err).Str("foo", "bar").Int("foo", 1) + + // include zerolog.Dict() + log.Info(). // want "must be dispatched by Msg or Send method" + Str("foo", "bar"). + Dict("dict", zerolog.Dict(). + Str("bar", "baz"). + Int("n", 1), + ) + + // conditional + logger2 := log.Info() // want "must be dispatched by Msg or Send method" + if err != nil { + logger2 = log.Error() // want "must be dispatched by Msg or Send method" + } + logger2.Str("foo", "bar") +} + +func expectNoWarnings() { + log.Fatal().Send() + log.Panic().Msg("") + log.Debug().Send() + log.Info().Msg("") + log.Warn().Send() + log.Error().Msg("") + + log.Error().Str("foo", "bar").Send() + err := fmt.Errorf("foobarerror") + log.Error().Err(err).Str("foo", "bar").Int("foo", 1).Msg("") + + logger := log.Error() + logger.Send() + + // include zerolog.Dict() + log.Info(). + Str("foo", "bar"). + Dict("dict", zerolog.Dict(). + Str("bar", "baz"). + Int("n", 1), + ).Send() + + // conditional + logger2 := log.Info() + if err != nil { + logger2 = log.Error() + } + logger2.Send() +} + +// https://github.com/ykadowak/zerologlint/pull/2 +func packageNil() { + s := []int{1, 2, 3} + slices.Sort(s) +}