diff --git a/cmd/cmd.go b/cmd/cmd.go index 4231d4e2..ad3c0253 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -7,16 +7,15 @@ import ( "sort" "github.com/gookit/color" + logrusUpstream "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/wagoodman/go-partybus" - anchoreLogger "github.com/anchore/go-logger" "github.com/anchore/go-logger/adapter/logrus" "github.com/anchore/grype/grype" "github.com/anchore/grype/internal/config" "github.com/anchore/grype/internal/log" - "github.com/anchore/grype/internal/logger" "github.com/anchore/grype/internal/version" "github.com/anchore/stereoscope" "github.com/anchore/syft/syft" @@ -62,32 +61,31 @@ func initAppConfig() { } func initLogging() { - enableConsole := (appConfig.Log.FileLocation == "" || appConfig.CliOptions.Verbosity > 0) && !appConfig.Quiet - cfg := logger.LogrusConfig{ - EnableConsole: enableConsole, - EnableFile: appConfig.Log.FileLocation != "", - Level: appConfig.Log.LevelOpt, - Structured: appConfig.Log.Structured, + cfg := logrus.Config{ + EnableConsole: (appConfig.Log.FileLocation == "" || appConfig.CliOptions.Verbosity > 0) && !appConfig.Quiet, FileLocation: appConfig.Log.FileLocation, + Level: appConfig.Log.Level, } - logWrapper := logger.NewLogrusLogger(cfg) - - grype.SetLogger(logWrapper) - - // TODO: separate syft logger config until grype consumes new logger - syftLoggerCfg := logrus.Config{ - EnableConsole: enableConsole, - Level: anchoreLogger.Level(appConfig.Log.LevelOpt.String()), + if appConfig.Log.Structured { + cfg.Formatter = &logrusUpstream.JSONFormatter{ + TimestampFormat: "2006-01-02T15:04:05.000Z", + DisableTimestamp: false, + DisableHTMLEscape: false, + PrettyPrint: false, + } } - lw, err := logrus.New(syftLoggerCfg) + + logWrapper, err := logrus.New(cfg) if err != nil { - panic(err) + // this is kinda circular, but we can't return an error... ¯\_(ツ)_/¯ + // I'm going to leave this here in case we one day have a different default logger other than the "discard" logger + log.Error("unable to initialize logger: %+v", err) + return } - syft.SetLogger(lw) - stereoscope.SetLogger(&logger.LogrusNestedLogger{ - Logger: logWrapper.Logger.WithField("from-lib", "stereoscope"), - }) + grype.SetLogger(logWrapper) + syft.SetLogger(logWrapper.Nested("form-lib", "syft")) + stereoscope.SetLogger(logWrapper.Nested("form-lib", "stereoscope")) } func logAppConfig() { diff --git a/go.mod b/go.mod index 887f95f0..e2c3c118 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7 - github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33 + github.com/anchore/stereoscope v0.0.0-20221130153459-3b80d983223f github.com/bmatcuk/doublestar/v2 v2.0.4 github.com/docker/docker v20.10.17+incompatible github.com/dustin/go-humanize v1.0.0 @@ -53,7 +53,7 @@ require ( require ( github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8 github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963 - github.com/anchore/syft v0.62.2 + github.com/anchore/syft v0.62.3 github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b github.com/in-toto/in-toto-golang v0.4.1-0.20221018183522-731d0640b65f github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index e18dc8d6..840358a1 100644 --- a/go.sum +++ b/go.sum @@ -238,10 +238,10 @@ github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7 h1:kDrYkTS github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4= github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963 h1:vrf2PYH77vqVJoNR15ZuFJ63qwBMqrmGIt/7VsBhLF8= github.com/anchore/sqlite v1.4.6-0.20220607210448-bcc6ee5c4963/go.mod h1:AVRyXOUP0hTz9Cb8OlD1XnwA8t4lBPfTuwPHmEUuiLc= -github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33 h1:Y+9aMJMTEMH+kJJFEaxqrF6X1t9CkjpWjOzaCo1q5vM= -github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33/go.mod h1:WOWtswyDxLkBnizq9LihYa9uw88r1FhBvJo7g//Ljcc= -github.com/anchore/syft v0.62.2 h1:4LXWeEIcHMDYnV3O1DR/erveeLqkpcDrC51zhpc+WFI= -github.com/anchore/syft v0.62.2/go.mod h1:aDR91I0K5EHp8oiE3DibOnOajF/A0N2tti46RNTiSrc= +github.com/anchore/stereoscope v0.0.0-20221130153459-3b80d983223f h1:JB4foD0R//XJ6oAtjK9h9ABjHhmzUAakjQRKMckPhnA= +github.com/anchore/stereoscope v0.0.0-20221130153459-3b80d983223f/go.mod h1:Oa0EpewvxiynI8zxLGj2SZ6gSoGtBPQrbZNBrYNBsvE= +github.com/anchore/syft v0.62.3 h1:2D5J2oeGIJ3BtIofRllxww4EdAv/dykekrF6zScanJY= +github.com/anchore/syft v0.62.3/go.mod h1:QIZSl6B5mb+o6Rorz547sAWSRhLjKzNtTNXuO10udZU= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= @@ -1326,6 +1326,7 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +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-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= diff --git a/grype/lib.go b/grype/lib.go index 7a6e81d5..5fbe7a55 100644 --- a/grype/lib.go +++ b/grype/lib.go @@ -3,8 +3,8 @@ package grype import ( "github.com/wagoodman/go-partybus" + "github.com/anchore/go-logger" "github.com/anchore/grype/grype/db" - "github.com/anchore/grype/grype/logger" "github.com/anchore/grype/grype/match" "github.com/anchore/grype/grype/matcher" "github.com/anchore/grype/grype/pkg" diff --git a/grype/logger/logger.go b/grype/logger/logger.go deleted file mode 100644 index 75b2bfd7..00000000 --- a/grype/logger/logger.go +++ /dev/null @@ -1,12 +0,0 @@ -package logger - -type Logger interface { - Errorf(format string, args ...interface{}) - Error(args ...interface{}) - Warnf(format string, args ...interface{}) - Warn(args ...interface{}) - Infof(format string, args ...interface{}) - Info(args ...interface{}) - Debugf(format string, args ...interface{}) - Debug(args ...interface{}) -} diff --git a/internal/config/application.go b/internal/config/application.go index cfea00bb..5731fd26 100644 --- a/internal/config/application.go +++ b/internal/config/application.go @@ -9,10 +9,10 @@ import ( "github.com/adrg/xdg" "github.com/mitchellh/go-homedir" - "github.com/sirupsen/logrus" "github.com/spf13/viper" "gopkg.in/yaml.v2" + "github.com/anchore/go-logger" "github.com/anchore/grype/grype/match" "github.com/anchore/grype/grype/vulnerability" "github.com/anchore/grype/internal" @@ -29,7 +29,8 @@ type parser interface { } type Application struct { - ConfigPath string `yaml:",omitempty" json:"configPath"` // the location where the application config was read from (either from -c or discovered while loading) + ConfigPath string `yaml:",omitempty" json:"configPath"` // the location where the application config was read from (either from -c or discovered while loading) + Verbosity uint `yaml:"verbosity,omitempty" json:"verbosity" mapstructure:"verbosity"` Output string `yaml:"output" json:"output" mapstructure:"output"` // -o, the Presenter hint string to use for report formatting File string `yaml:"file" json:"file" mapstructure:"file"` // --file, the file to write report output to Distro string `yaml:"distro" json:"distro" mapstructure:"distro"` // --distro, specify a distro to explicitly use @@ -136,31 +137,24 @@ func (cfg *Application) parseLogLevelOption() error { // TODO: this is bad: quiet option trumps all other logging options (such as to a file on disk) // we should be able to quiet the console logging and leave file logging alone... // ... this will be an enhancement for later - cfg.Log.LevelOpt = logrus.PanicLevel + cfg.Log.Level = logger.DisabledLevel + + case cfg.CliOptions.Verbosity > 0: + verb := cfg.CliOptions.Verbosity + cfg.Log.Level = logger.LevelFromVerbosity(verb, logger.WarnLevel, logger.InfoLevel, logger.DebugLevel, logger.TraceLevel) + case cfg.Log.Level != "": - if cfg.CliOptions.Verbosity > 0 { - return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together") - } - - lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level)) + var err error + cfg.Log.Level, err = logger.LevelFromString(string(cfg.Log.Level)) if err != nil { - return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err) + return err } - cfg.Log.LevelOpt = lvl - if cfg.Log.LevelOpt >= logrus.InfoLevel { - cfg.CliOptions.Verbosity = 1 + if logger.IsVerbose(cfg.Log.Level) { + cfg.Verbosity = 1 } default: - - switch v := cfg.CliOptions.Verbosity; { - case v == 1: - cfg.Log.LevelOpt = logrus.InfoLevel - case v >= 2: - cfg.Log.LevelOpt = logrus.DebugLevel - default: - cfg.Log.LevelOpt = logrus.WarnLevel - } + cfg.Log.Level = logger.WarnLevel } return nil diff --git a/internal/config/logging.go b/internal/config/logging.go index 44fe6528..bf9ffe37 100644 --- a/internal/config/logging.go +++ b/internal/config/logging.go @@ -1,20 +1,20 @@ package config import ( - "github.com/sirupsen/logrus" "github.com/spf13/viper" + + "github.com/anchore/go-logger" ) // logging contains all logging-related configuration options available to the user via the application config. type logging struct { Structured bool `yaml:"structured" json:"structured" mapstructure:"structured"` // show all log entries as JSON formatted strings - LevelOpt logrus.Level `yaml:"-" json:"-"` // the native log level object used by the logger - Level string `yaml:"level" json:"level" mapstructure:"level"` // the log level string hint + Level logger.Level `yaml:"level" json:"level" mapstructure:"level"` // the log level string hint FileLocation string `yaml:"file" json:"file" mapstructure:"file"` // the file path to write logs to } func (cfg logging) loadDefaultValues(v *viper.Viper) { - v.SetDefault("log.level", "") - v.SetDefault("log.file", "") v.SetDefault("log.structured", false) + v.SetDefault("log.file", "") + v.SetDefault("log.level", string(logger.WarnLevel)) } diff --git a/internal/log/log.go b/internal/log/log.go index 03f27b18..42ef116e 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -1,37 +1,69 @@ package log -import "github.com/anchore/grype/grype/logger" +import ( + "github.com/anchore/go-logger" + "github.com/anchore/go-logger/adapter/discard" +) -var Log logger.Logger = &nopLogger{} +// Log is the singleton used to facilitate logging internally within syft +var Log logger.Logger = discard.New() +// Errorf takes a formatted template string and template arguments for the error logging level. func Errorf(format string, args ...interface{}) { Log.Errorf(format, args...) } +// Error logs the given arguments at the error logging level. func Error(args ...interface{}) { Log.Error(args...) } +// Warnf takes a formatted template string and template arguments for the warning logging level. func Warnf(format string, args ...interface{}) { Log.Warnf(format, args...) } +// Warn logs the given arguments at the warning logging level. func Warn(args ...interface{}) { Log.Warn(args...) } +// Infof takes a formatted template string and template arguments for the info logging level. func Infof(format string, args ...interface{}) { Log.Infof(format, args...) } +// Info logs the given arguments at the info logging level. func Info(args ...interface{}) { Log.Info(args...) } +// Debugf takes a formatted template string and template arguments for the debug logging level. func Debugf(format string, args ...interface{}) { Log.Debugf(format, args...) } +// Debug logs the given arguments at the debug logging level. func Debug(args ...interface{}) { Log.Debug(args...) } + +// Tracef takes a formatted template string and template arguments for the trace logging level. +func Tracef(format string, args ...interface{}) { + Log.Tracef(format, args...) +} + +// Trace logs the given arguments at the trace logging level. +func Trace(args ...interface{}) { + Log.Trace(args...) +} + +// WithFields returns a message logger with multiple key-value fields. +func WithFields(fields ...interface{}) logger.MessageLogger { + return Log.WithFields(fields...) +} + +// Nested returns a new logger with hard coded key-value pairs +func Nested(fields ...interface{}) logger.Logger { + return Log.Nested(fields...) +} diff --git a/internal/log/nop.go b/internal/log/nop.go deleted file mode 100644 index ff20e461..00000000 --- a/internal/log/nop.go +++ /dev/null @@ -1,12 +0,0 @@ -package log - -type nopLogger struct{} - -func (l *nopLogger) Errorf(format string, args ...interface{}) {} -func (l *nopLogger) Error(args ...interface{}) {} -func (l *nopLogger) Warnf(format string, args ...interface{}) {} -func (l *nopLogger) Warn(args ...interface{}) {} -func (l *nopLogger) Infof(format string, args ...interface{}) {} -func (l *nopLogger) Info(args ...interface{}) {} -func (l *nopLogger) Debugf(format string, args ...interface{}) {} -func (l *nopLogger) Debug(args ...interface{}) {} diff --git a/internal/ui/ephemeral_terminal_ui.go b/internal/ui/ephemeral_terminal_ui.go index 132cf96a..498bebc2 100644 --- a/internal/ui/ephemeral_terminal_ui.go +++ b/internal/ui/ephemeral_terminal_ui.go @@ -14,9 +14,9 @@ import ( "github.com/wagoodman/go-partybus" "github.com/wagoodman/jotframe/pkg/frame" + "github.com/anchore/go-logger" grypeEvent "github.com/anchore/grype/grype/event" "github.com/anchore/grype/internal/log" - "github.com/anchore/grype/internal/logger" "github.com/anchore/grype/ui" ) @@ -62,9 +62,9 @@ func (h *ephemeralTerminalUI) Setup(unsubscribe func() error) error { // prep the logger to not clobber the screen from now on (logrus only) h.logBuffer = bytes.NewBufferString("") - logWrapper, ok := log.Log.(*logger.LogrusLogger) + logController, ok := log.Log.(logger.Controller) if ok { - logWrapper.Logger.SetOutput(h.logBuffer) + logController.SetOutput(h.logBuffer) } return h.openScreen() @@ -142,10 +142,10 @@ func (h *ephemeralTerminalUI) closeScreen(force bool) { func (h *ephemeralTerminalUI) flushLog() { // flush any errors to the screen before the report - logWrapper, ok := log.Log.(*logger.LogrusLogger) + logController, ok := log.Log.(logger.Controller) if ok { - fmt.Fprint(logWrapper.Output, h.logBuffer.String()) - logWrapper.Logger.SetOutput(h.uiOutput) + fmt.Fprint(logController.GetOutput(), h.logBuffer.String()) + logController.SetOutput(h.uiOutput) } else { fmt.Fprint(h.uiOutput, h.logBuffer.String()) }