diff --git a/.golangci.reference.yml b/.golangci.reference.yml index 93704cb504ab..ce9267e68c4f 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -1144,6 +1144,32 @@ linters-settings: # Default: 1 tab-width: 1 + loggercheck: + # Allow check for the github.com/go-kit/log library. + # Default: true + kitlog: false + # Allow check for the k8s.io/klog/v2 library. + # Default: true + klog: false + # Allow check for the github.com/go-logr/logr library. + # Default: true + logr: false + # Allow check for the "sugar logger" from go.uber.org/zap library. + # Default: true + zap: false + # Require all logging keys to be inlined constant strings. + # Default: false + require-string-key: true + # Require printf-like format specifier (%s, %d for example) not present. + # Default: false + no-printf-like: true + # List of custom rules to check against, where each rule is a single logger pattern, useful for wrapped loggers. + # For example: https://github.com/timonwong/loggercheck/blob/7395ab86595781e33f7afba27ad7b55e6956ebcd/testdata/custom-rules.txt + # Default: empty + rules: + - k8s.io/klog/v2.InfoS # package level exported functions + - (github.com/go-logr/logr.Logger).Error # "Methods" + - (*go.uber.org/zap.SugaredLogger).With # Also "Methods", but with a pointer receiver maintidx: # Show functions with maintainability index lower than N. # A high index indicates better maintainability (it's kind of the opposite of complexity). @@ -1981,7 +2007,7 @@ linters: - interfacer - ireturn - lll - - logrlint + - loggercheck - maintidx - makezero - maligned @@ -2086,7 +2112,7 @@ linters: - interfacer - ireturn - lll - - logrlint + - loggercheck - maintidx - makezero - maligned diff --git a/go.mod b/go.mod index 8c5b3478d128..71e7d6af3c87 100644 --- a/go.mod +++ b/go.mod @@ -95,7 +95,7 @@ require ( github.com/tdakkota/asciicheck v0.1.1 github.com/tetafro/godot v1.4.11 github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 - github.com/timonwong/logrlint v0.1.0 + github.com/timonwong/loggercheck v0.9.3 github.com/tomarrell/wrapcheck/v2 v2.6.2 github.com/tommy-muehle/go-mnd/v2 v2.5.0 github.com/ultraware/funlen v0.0.3 diff --git a/go.sum b/go.sum index dc213a9e9647..ec573e621a99 100644 --- a/go.sum +++ b/go.sum @@ -531,8 +531,12 @@ github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/timonwong/logrlint v0.1.0 h1:phZCcypL/vtx6cGxObJgWZ5wexZF5SXFPLOM+ru0e/M= -github.com/timonwong/logrlint v0.1.0/go.mod h1:Zleg4Gw+kRxNej+Ra7o+tEaW5k1qthTaYKU7rSD39LU= +github.com/timonwong/loggercheck v0.9.1 h1:7HrqjZzIWiSsAI1kO/LHqpEVHvBOOeiZ68XGQCU/WqY= +github.com/timonwong/loggercheck v0.9.1/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= +github.com/timonwong/loggercheck v0.9.2 h1:KrR/4yWGJcwulKPtlOyVCbgl/uckJMSMiCAzcv4OGx0= +github.com/timonwong/loggercheck v0.9.2/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= +github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI= +github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index 97f38e7bc17c..0822862e90c4 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -69,6 +69,15 @@ var defaultLintersSettings = LintersSettings{ LineLength: 120, TabWidth: 1, }, + LoggerCheck: LoggerCheckSettings{ + Kitlog: true, + Klog: true, + Logr: true, + Zap: true, + RequireStringKey: false, + NoPrintfLike: false, + Rules: nil, + }, MaintIdx: MaintIdxSettings{ Under: 20, }, @@ -157,6 +166,7 @@ type LintersSettings struct { InterfaceBloat InterfaceBloatSettings Ireturn IreturnSettings Lll LllSettings + LoggerCheck LoggerCheckSettings MaintIdx MaintIdxSettings Makezero MakezeroSettings Maligned MalignedSettings @@ -479,6 +489,16 @@ type LllSettings struct { TabWidth int `mapstructure:"tab-width"` } +type LoggerCheckSettings struct { + Kitlog bool `mapstructure:"kitlog"` + Klog bool `mapstructure:"klog"` + Logr bool `mapstructure:"logr"` + Zap bool `mapstructure:"zap"` + RequireStringKey bool `mapstructure:"require-string-key"` + NoPrintfLike bool `mapstructure:"no-printf-like"` + Rules []string `mapstructure:"rules"` +} + type MaintIdxSettings struct { Under int `mapstructure:"under"` } diff --git a/pkg/golinters/loggercheck.go b/pkg/golinters/loggercheck.go new file mode 100644 index 000000000000..fc29127c3bb7 --- /dev/null +++ b/pkg/golinters/loggercheck.go @@ -0,0 +1,44 @@ +package golinters + +import ( + "github.com/timonwong/loggercheck" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewLoggerCheck(settings *config.LoggerCheckSettings) *goanalysis.Linter { + var opts []loggercheck.Option + + if settings != nil { + var disable []string + if !settings.Kitlog { + disable = append(disable, "kitlog") + } + if !settings.Klog { + disable = append(disable, "klog") + } + if !settings.Logr { + disable = append(disable, "logr") + } + if !settings.Zap { + disable = append(disable, "zap") + } + + opts = []loggercheck.Option{ + loggercheck.WithDisable(disable), + loggercheck.WithRequireStringKey(settings.RequireStringKey), + loggercheck.WithRules(settings.Rules), + loggercheck.WithNoPrintfLike(settings.NoPrintfLike), + } + } + + analyzer := loggercheck.NewAnalyzer(opts...) + return goanalysis.NewLinter( + analyzer.Name, + analyzer.Doc, + []*analysis.Analyzer{analyzer}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/golinters/logrlint.go b/pkg/golinters/logrlint.go deleted file mode 100644 index 9899808c7476..000000000000 --- a/pkg/golinters/logrlint.go +++ /dev/null @@ -1,19 +0,0 @@ -package golinters - -import ( - "github.com/timonwong/logrlint" - "golang.org/x/tools/go/analysis" - - "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" -) - -func NewLogrLint() *goanalysis.Linter { - a := logrlint.Analyzer - - return goanalysis.NewLinter( - a.Name, - a.Doc, - []*analysis.Analyzer{a}, - nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) -} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index 16debbf80ff5..17231850c5fc 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -140,6 +140,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { interfaceBloatCfg *config.InterfaceBloatSettings ireturnCfg *config.IreturnSettings lllCfg *config.LllSettings + loggerCheckCfg *config.LoggerCheckSettings maintIdxCfg *config.MaintIdxSettings makezeroCfg *config.MakezeroSettings malignedCfg *config.MalignedSettings @@ -214,6 +215,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { interfaceBloatCfg = &m.cfg.LintersSettings.InterfaceBloat ireturnCfg = &m.cfg.LintersSettings.Ireturn lllCfg = &m.cfg.LintersSettings.Lll + loggerCheckCfg = &m.cfg.LintersSettings.LoggerCheck maintIdxCfg = &m.cfg.LintersSettings.MaintIdx makezeroCfg = &m.cfg.LintersSettings.Makezero malignedCfg = &m.cfg.LintersSettings.Maligned @@ -583,11 +585,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.8.0"). WithPresets(linter.PresetStyle), - linter.NewConfig(golinters.NewLogrLint()). + linter.NewConfig(golinters.NewLoggerCheck(loggerCheckCfg)). WithSince("v1.49.0"). WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/timonwong/logrlint"), + WithPresets(linter.PresetStyle, linter.PresetBugs). + WithAlternativeNames("logrlint"). + WithURL("https://github.com/timonwong/loggercheck"), linter.NewConfig(golinters.NewMaintIdx(maintIdxCfg)). WithSince("v1.44.0"). diff --git a/test/linters_test.go b/test/linters_test.go index be705a13a9fb..159e76c8bb56 100644 --- a/test/linters_test.go +++ b/test/linters_test.go @@ -29,7 +29,7 @@ func TestTypecheck(t *testing.T) { func TestSourcesFromTestdataSubDir(t *testing.T) { subDirs := []string{ - "logrlint", + "loggercheck", } for _, dir := range subDirs { diff --git a/test/testdata/loggercheck/configs/loggercheck_custom.yml b/test/testdata/loggercheck/configs/loggercheck_custom.yml new file mode 100644 index 000000000000..6cee97fda463 --- /dev/null +++ b/test/testdata/loggercheck/configs/loggercheck_custom.yml @@ -0,0 +1,13 @@ +linters-settings: + loggercheck: + rules: + - (*command-line-arguments.Logger).Debugw + - (*command-line-arguments.Logger).Infow + - (*command-line-arguments.Logger).Warnw + - (*command-line-arguments.Logger).Errorw + - (*command-line-arguments.Logger).With + - command-line-arguments.Debugw + - command-line-arguments.Infow + - command-line-arguments.Warnw + - command-line-arguments.Errorw + - command-line-arguments.With diff --git a/test/testdata/loggercheck/configs/loggercheck_kitlogonly.yml b/test/testdata/loggercheck/configs/loggercheck_kitlogonly.yml new file mode 100644 index 000000000000..50dc99cbac70 --- /dev/null +++ b/test/testdata/loggercheck/configs/loggercheck_kitlogonly.yml @@ -0,0 +1,6 @@ +linters-settings: + loggercheck: + kitlog: true + klog: false + logr: false + zap: false diff --git a/test/testdata/loggercheck/configs/loggercheck_logronly.yml b/test/testdata/loggercheck/configs/loggercheck_logronly.yml new file mode 100644 index 000000000000..001666b7a268 --- /dev/null +++ b/test/testdata/loggercheck/configs/loggercheck_logronly.yml @@ -0,0 +1,5 @@ +linters-settings: + loggercheck: + logr: true + klog: false + zap: false diff --git a/test/testdata/loggercheck/configs/loggercheck_noprintflike.yml b/test/testdata/loggercheck/configs/loggercheck_noprintflike.yml new file mode 100644 index 000000000000..9ef9b44ac5e6 --- /dev/null +++ b/test/testdata/loggercheck/configs/loggercheck_noprintflike.yml @@ -0,0 +1,3 @@ +linters-settings: + loggercheck: + no-printf-like: true diff --git a/test/testdata/loggercheck/configs/loggercheck_requirestringkey.yml b/test/testdata/loggercheck/configs/loggercheck_requirestringkey.yml new file mode 100644 index 000000000000..62e5d8f8885c --- /dev/null +++ b/test/testdata/loggercheck/configs/loggercheck_requirestringkey.yml @@ -0,0 +1,3 @@ +linters-settings: + loggercheck: + require-string-key: true diff --git a/test/testdata/loggercheck/configs/loggercheck_zaponly.yml b/test/testdata/loggercheck/configs/loggercheck_zaponly.yml new file mode 100644 index 000000000000..1ac350893b85 --- /dev/null +++ b/test/testdata/loggercheck/configs/loggercheck_zaponly.yml @@ -0,0 +1,5 @@ +linters-settings: + loggercheck: + logr: false + klog: false + zap: true diff --git a/test/testdata/loggercheck/go.mod b/test/testdata/loggercheck/go.mod new file mode 100644 index 000000000000..e60fbda3ad72 --- /dev/null +++ b/test/testdata/loggercheck/go.mod @@ -0,0 +1,16 @@ +module loggercheck + +go 1.19 + +require ( + github.com/go-kit/log v0.2.1 + github.com/go-logr/logr v1.2.3 + go.uber.org/zap v1.23.0 + k8s.io/klog/v2 v2.70.1 +) + +require ( + github.com/go-logfmt/logfmt v0.5.1 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect +) diff --git a/test/testdata/loggercheck/go.sum b/test/testdata/loggercheck/go.sum new file mode 100644 index 000000000000..ef4aef6d0715 --- /dev/null +++ b/test/testdata/loggercheck/go.sum @@ -0,0 +1,32 @@ +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= diff --git a/test/testdata/loggercheck/loggercheck_custom.go b/test/testdata/loggercheck/loggercheck_custom.go new file mode 100644 index 000000000000..5182d373c1ad --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_custom.go @@ -0,0 +1,118 @@ +//golangcitest:args -Eloggercheck +//golangcitest:config_path configs/loggercheck_custom.yml +package loggercheck + +import ( + "errors" + + "go.uber.org/zap" +) + +var l = New() + +type Logger struct { + s *zap.SugaredLogger +} + +func New() *Logger { + logger := zap.NewExample().Sugar() + return &Logger{s: logger} +} + +func (l *Logger) With(keysAndValues ...interface{}) *Logger { + return &Logger{ + s: l.s.With(keysAndValues...), + } +} + +func (l *Logger) Debugw(msg string, keysAndValues ...interface{}) { + l.s.Debugw(msg, keysAndValues...) +} + +func (l *Logger) Infow(msg string, keysAndValues ...interface{}) { + l.s.Infow(msg, keysAndValues...) +} + +func (l *Logger) Warnw(msg string, keysAndValues ...interface{}) { + l.s.Warnw(msg, keysAndValues...) +} + +func (l *Logger) Errorw(msg string, keysAndValues ...interface{}) { + l.s.Errorw(msg, keysAndValues...) +} + +func (l *Logger) Fatalw(msg string, keysAndValues ...interface{}) { + l.s.Fatalw(msg, keysAndValues...) +} + +func (l *Logger) Sync() error { + return l.s.Sync() +} + +// package level wrap func + +func With(keysAndValues ...interface{}) *Logger { + return &Logger{ + s: l.s.With(keysAndValues...), + } +} + +func Debugw(msg string, keysAndValues ...interface{}) { + l.s.Debugw(msg, keysAndValues...) +} + +func Infow(msg string, keysAndValues ...interface{}) { + l.s.Infow(msg, keysAndValues...) +} + +func Warnw(msg string, keysAndValues ...interface{}) { + l.s.Warnw(msg, keysAndValues...) +} + +func Errorw(msg string, keysAndValues ...interface{}) { + l.s.Errorw(msg, keysAndValues...) +} + +func Fatalw(msg string, keysAndValues ...interface{}) { + l.s.Fatalw(msg, keysAndValues...) +} + +func Sync() error { + return l.s.Sync() +} + +func ExampleCustomLogger() { + err := errors.New("example error") + + // custom SugaredLogger + log := New() + defer log.Sync() + + log.Infow("abc", "key1", "value1") + log.Infow("abc", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` + + log.Errorw("message", "err", err, "key1", "value1") + log.Errorw("message", err, "key1", "value1", "key2", "value2") // want `odd number of arguments passed as key-value pairs for logging` + + // with test + log.With("with_key1", "with_value1").Infow("message", "key1", "value1") + log.With("with_key1", "with_value1").Infow("message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` + log.With("with_key1").Infow("message", "key1", "value1") // want `odd number of arguments passed as key-value pairs for logging` +} + +func ExampleCustomLoggerPackageLevelFunc() { + err := errors.New("example error") + + defer Sync() + + Infow("abc", "key1", "value1") + Infow("abc", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` + + Errorw("message", "err", err, "key1", "value1") + Errorw("message", err, "key1", "value1", "key2", "value2") // want `odd number of arguments passed as key-value pairs for logging` + + // with test + With("with_key1", "with_value1").Infow("message", "key1", "value1") + With("with_key1", "with_value1").Infow("message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` + With("with_key1").Infow("message", "key1", "value1") // want `odd number of arguments passed as key-value pairs for logging` +} diff --git a/test/testdata/loggercheck/loggercheck_default.go b/test/testdata/loggercheck/loggercheck_default.go new file mode 100644 index 000000000000..1a95b246de4c --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_default.go @@ -0,0 +1,28 @@ +//golangcitest:args -Eloggercheck +package loggercheck + +import ( + "fmt" + + "github.com/go-logr/logr" + "go.uber.org/zap" + "k8s.io/klog/v2" +) + +func ExampleDefaultLogr() { + log := logr.Discard() + log = log.WithValues("key") // want `odd number of arguments passed as key-value pairs for logging` + log.Info("message", "key1", "value1", "key2", "value2", "key3") // want `odd number of arguments passed as key-value pairs for logging` + log.Error(fmt.Errorf("error"), "message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` + log.Error(fmt.Errorf("error"), "message", "key1", "value1", "key2", "value2") +} + +func ExampleDefaultKlog() { + klog.InfoS("message", "key1") // want `odd number of arguments passed as key-value pairs for logging` +} + +func ExampleZapSugarNotChecked() { + sugar := zap.NewExample().Sugar() + defer sugar.Sync() + sugar.Infow("message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` +} diff --git a/test/testdata/loggercheck/loggercheck_kitlogonly.go b/test/testdata/loggercheck/loggercheck_kitlogonly.go new file mode 100644 index 000000000000..50ee68f1d3cb --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_kitlogonly.go @@ -0,0 +1,31 @@ +//golangcitest:args -Eloggercheck +//golangcitest:config_path configs/loggercheck_kitlogonly.yml +package loggercheck + +import ( + kitlog "github.com/go-kit/log" + "github.com/go-logr/logr" + "go.uber.org/zap" + "k8s.io/klog/v2" +) + +func ExampleKitLogOnly_NoLogr() { + log := logr.Discard() + log.Info("message", "key1", "value1", "key2", "value2", "key3") + klog.InfoS("message", "key1") + + sugar := zap.NewExample().Sugar() + sugar.Infow("message", "key1", "value1", "key2") + sugar.Errorw("error message", "key1") +} + +func ExampleKitLogOnly() { + logger := kitlog.NewNopLogger() + + logger.Log("msg", "message", "key1", "value1") + logger.Log("msg") // want `odd number of arguments passed as key-value pairs for logging` + logger.Log("msg", "message", "key1") // want `odd number of arguments passed as key-value pairs for logging` + + kitlog.With(logger, "key1", "value1").Log("msg", "message") + kitlog.With(logger, "key1").Log("msg", "message") // want `odd number of arguments passed as key-value pairs for logging` +} diff --git a/test/testdata/loggercheck/loggercheck_logronly.go b/test/testdata/loggercheck/loggercheck_logronly.go new file mode 100644 index 000000000000..56629705824d --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_logronly.go @@ -0,0 +1,25 @@ +//golangcitest:args -Eloggercheck +//golangcitest:config_path configs/loggercheck_logronly.yml +package loggercheck + +import ( + "fmt" + + "github.com/go-logr/logr" + "go.uber.org/zap" + "k8s.io/klog/v2" +) + +func ExampleLogrOnly() { + log := logr.Discard() + log.Info("message", "key1", "value1", "key2", "value2", "key3") // want `odd number of arguments passed as key-value pairs for logging` + + klog.InfoS("message", "key1") + + sugar := zap.NewExample().Sugar() + sugar.Infow("message", "key1", "value1", "key2") + sugar.Errorw("error message", "key1") + + // Will not check by default (-requirestringkey) + log.Error(fmt.Errorf("error"), "message", []byte("key1"), "value1") +} diff --git a/test/testdata/loggercheck/loggercheck_noprintflike.go b/test/testdata/loggercheck/loggercheck_noprintflike.go new file mode 100644 index 000000000000..de93db4b43f6 --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_noprintflike.go @@ -0,0 +1,15 @@ +//golangcitest:args -Eloggercheck +//golangcitest:config_path configs/loggercheck_noprintflike.yml +package loggercheck + +import ( + "github.com/go-logr/logr" +) + +func ExampleNoPrintfLike() { + log := logr.Discard() + + log.Info("This message is ok") + log.Info("Should not contains printf like format specifiers: %s %d %w") // want `logging message should not use format specifier "%s"` + log.Info("It also checks for the key value pairs", "key", "value %.2f") // want `logging message should not use format specifier "%\.2f"` +} diff --git a/test/testdata/loggercheck/loggercheck_requirestringkey.go b/test/testdata/loggercheck/loggercheck_requirestringkey.go new file mode 100644 index 000000000000..5efacca14c69 --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_requirestringkey.go @@ -0,0 +1,22 @@ +//golangcitest:args -Eloggercheck +//golangcitest:config_path configs/loggercheck_requirestringkey.yml +package loggercheck + +import ( + "github.com/go-logr/logr" +) + +func ExampleRequireStringKey() { + log := logr.Discard() + log.Info("message", "key1", "value1") + const key1 = "key1" + log.Info("message", key1, "value1") + + key2 := []byte(key1) + log.Info("message", key2, "value2") // want `logging keys are expected to be inlined constant strings, please replace "key2" provided with string` + + key3 := key1 + log.Info("message", key3, "value3") // want `logging keys are expected to be inlined constant strings, please replace "key3" provided with string` + + log.Info("message", "键1", "value1") // want `logging keys are expected to be alphanumeric strings, please remove any non-latin characters from "键1"` +} diff --git a/test/testdata/loggercheck/loggercheck_zaponly.go b/test/testdata/loggercheck/loggercheck_zaponly.go new file mode 100644 index 000000000000..626a3c27ee75 --- /dev/null +++ b/test/testdata/loggercheck/loggercheck_zaponly.go @@ -0,0 +1,12 @@ +//golangcitest:args -Eloggercheck +//golangcitest:config_path configs/loggercheck_zaponly.yml +package loggercheck + +import "go.uber.org/zap" + +func ExampleZapOnly() { + sugar := zap.NewExample().Sugar() + + sugar.Infow("message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` + sugar.Errorw("error message", "key1") // want `odd number of arguments passed as key-value pairs for logging` +} diff --git a/test/testdata/logrlint/logrlint.go b/test/testdata/loggercheck/logrlint_compatiblity.go similarity index 58% rename from test/testdata/logrlint/logrlint.go rename to test/testdata/loggercheck/logrlint_compatiblity.go index 6277dea4e146..78bc8d91ee6f 100644 --- a/test/testdata/logrlint/logrlint.go +++ b/test/testdata/loggercheck/logrlint_compatiblity.go @@ -1,16 +1,28 @@ //golangcitest:args -Elogrlint -package logrlint +package loggercheck import ( "fmt" "github.com/go-logr/logr" + "go.uber.org/zap" + "k8s.io/klog/v2" ) -func Example() { +func ExampleLogrlintLogr() { log := logr.Discard() log = log.WithValues("key") // want `odd number of arguments passed as key-value pairs for logging` log.Info("message", "key1", "value1", "key2", "value2", "key3") // want `odd number of arguments passed as key-value pairs for logging` log.Error(fmt.Errorf("error"), "message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` log.Error(fmt.Errorf("error"), "message", "key1", "value1", "key2", "value2") } + +func ExampleLogrlintKlog() { + klog.InfoS("message", "key1") // want `odd number of arguments passed as key-value pairs for logging` +} + +func ExampleLogrlintZapSugar() { + sugar := zap.NewExample().Sugar() + defer sugar.Sync() + sugar.Infow("message", "key1", "value1", "key2") // want `odd number of arguments passed as key-value pairs for logging` +} diff --git a/test/testdata/logrlint/go.mod b/test/testdata/logrlint/go.mod deleted file mode 100644 index a9d8d16ad374..000000000000 --- a/test/testdata/logrlint/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module logrlint - -go 1.16 - -require github.com/go-logr/logr v1.2.3 diff --git a/test/testdata/logrlint/go.sum b/test/testdata/logrlint/go.sum deleted file mode 100644 index 6da913857d04..000000000000 --- a/test/testdata/logrlint/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=