diff --git a/cmd/syft/cli/commands.go b/cmd/syft/cli/commands.go index 17d38fd8e..2e1a407c5 100644 --- a/cmd/syft/cli/commands.go +++ b/cmd/syft/cli/commands.go @@ -6,17 +6,18 @@ import ( cranecmd "github.com/google/go-containerregistry/cmd/crane/cmd" "github.com/gookit/color" + logrusUpstream "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/wagoodman/go-partybus" + "github.com/anchore/go-logger/adapter/logrus" "github.com/anchore/stereoscope" "github.com/anchore/syft/cmd/syft/cli/options" "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/log" - "github.com/anchore/syft/internal/logger" "github.com/anchore/syft/internal/version" "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/event" @@ -118,7 +119,7 @@ func validateArgs(cmd *cobra.Command, args []string) error { } func checkForApplicationUpdate() { - log.Debugf("checking if new vesion of %s is available", internal.ApplicationName) + log.Debugf("checking if a new version of %s is available", internal.ApplicationName) isAvailable, newVersion, err := version.IsUpdateAvailable() if err != nil { // this should never stop the application @@ -138,22 +139,33 @@ func checkForApplicationUpdate() { func logApplicationConfig(app *config.Application) { versionInfo := version.FromBuild() - log.Infof("syft version: %+v", versionInfo.Version) + log.Infof("%s version: %+v", internal.ApplicationName, versionInfo.Version) log.Debugf("application config:\n%+v", color.Magenta.Sprint(app.String())) } func newLogWrapper(app *config.Application) { - cfg := logger.LogrusConfig{ + cfg := logrus.Config{ EnableConsole: (app.Log.FileLocation == "" || app.Verbosity > 0) && !app.Quiet, - EnableFile: app.Log.FileLocation != "", - Level: app.Log.LevelOpt, - Structured: app.Log.Structured, FileLocation: app.Log.FileLocation, + Level: app.Log.Level, } - logWrapper := logger.NewLogrusLogger(cfg) + if app.Log.Structured { + cfg.Formatter = &logrusUpstream.JSONFormatter{ + TimestampFormat: "2006-01-02 15:04:05", + DisableTimestamp: false, + DisableHTMLEscape: false, + PrettyPrint: false, + } + } + + logWrapper, err := logrus.New(cfg) + if err != nil { + // 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(logWrapper) - stereoscope.SetLogger(&logger.LogrusNestedLogger{ - Logger: logWrapper.Logger.WithField("from-lib", "stereoscope"), - }) + stereoscope.SetLogger(logWrapper.Nested("from-lib", "stereoscope")) } diff --git a/go.mod b/go.mod index ed37b293c..25cab7e03 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,6 @@ require ( github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5 github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240 github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb - github.com/x-cray/logrus-prefixed-formatter v0.5.2 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458 @@ -53,6 +52,7 @@ require ( require ( github.com/Masterminds/sprig/v3 v3.2.2 + github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8 github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33 github.com/docker/docker v20.10.17+incompatible github.com/google/go-containerregistry v0.11.0 diff --git a/go.sum b/go.sum index 87583c80f..7068b8d4d 100644 --- a/go.sum +++ b/go.sum @@ -272,6 +272,8 @@ github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.2.3 h1:Vmodnr52Rz1mcbwn0kzMhLRKb6soizewuKXdfZiNemU= github.com/aliyun/credentials-go v1.2.3/go.mod h1:/KowD1cfGSLrLsH28Jr8W+xwoId0ywIy5lNzDz6O1vw= +github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8 h1:imgMA0gN0TZx7PSa/pdWqXadBvrz8WsN6zySzCe4XX0= +github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8/go.mod h1:+gPap4jha079qzRTUaehv+UZ6sSdaNwkH0D3b6zhTuk= github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU= github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb/go.mod h1:DmTY2Mfcv38hsHbG78xMiTDdxFtkHpgYNVDPsF2TgHk= github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8= @@ -1986,8 +1988,6 @@ github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb h1:Yz6VVOcLuWLA github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb/go.mod h1:nDi3BAC5nEbVbg+WSJDHLbjHv0ZToq8nMPA97XMxF3E= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= -github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/go-gitlab v0.73.1 h1:UMagqUZLJdjss1SovIC+kJCH4k2AZWXl58gJd38Y/hI= github.com/xanzy/go-gitlab v0.73.1/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA= diff --git a/internal/config/application.go b/internal/config/application.go index 13ec69979..bd98777ab 100644 --- a/internal/config/application.go +++ b/internal/config/application.go @@ -10,10 +10,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/syft/internal" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/syft/pkg/cataloger" @@ -140,33 +140,23 @@ 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.Verbosity > 0: - switch v := cfg.Verbosity; { - case v == 1: - cfg.Log.LevelOpt = logrus.InfoLevel - case v >= 2: - cfg.Log.LevelOpt = logrus.DebugLevel - default: - cfg.Log.LevelOpt = logrus.ErrorLevel - } + cfg.Log.Level = logger.LevelFromVerbosity(int(cfg.Verbosity), logger.WarnLevel, logger.InfoLevel, logger.DebugLevel, logger.TraceLevel) + case cfg.Log.Level != "": - 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 { + if logger.IsVerbose(cfg.Log.Level) { cfg.Verbosity = 1 } default: - cfg.Log.LevelOpt = logrus.WarnLevel - } - - if cfg.Log.Level == "" { - cfg.Log.Level = cfg.Log.LevelOpt.String() + cfg.Log.Level = logger.WarnLevel } return nil diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100644 index d912156be..000000000 --- a/internal/config/config.go +++ /dev/null @@ -1 +0,0 @@ -package config diff --git a/internal/config/logging.go b/internal/config/logging.go index 6d6909d42..8c0b43c93 100644 --- a/internal/config/logging.go +++ b/internal/config/logging.go @@ -4,15 +4,15 @@ import ( "fmt" "github.com/mitchellh/go-homedir" - "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-location" mapstructure:"file"` // the file path to write logs to } @@ -30,4 +30,5 @@ func (cfg *logging) parseConfigValues() error { func (cfg logging) loadDefaultValues(v *viper.Viper) { 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 0dd2199c6..30952987f 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -3,10 +3,13 @@ Package log contains the singleton object and helper functions for facilitating */ package log -import "github.com/anchore/syft/syft/logger" +import ( + "github.com/anchore/go-logger" + "github.com/anchore/go-logger/adapter/discard" +) // Log is the singleton used to facilitate logging internally within syft -var Log logger.Logger = &nopLogger{} +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{}) { @@ -47,3 +50,23 @@ func Debugf(format string, args ...interface{}) { 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 ff20e4612..000000000 --- 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/logger/doc.go b/internal/logger/doc.go deleted file mode 100644 index 59647a80c..000000000 --- a/internal/logger/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package logger contains implementations for the syft.logger.Logger interface. -*/ -package logger diff --git a/internal/logger/logrus.go b/internal/logger/logrus.go deleted file mode 100644 index 37983e61c..000000000 --- a/internal/logger/logrus.go +++ /dev/null @@ -1,163 +0,0 @@ -package logger - -import ( - "fmt" - "io" - "io/fs" - "os" - - "github.com/sirupsen/logrus" - prefixed "github.com/x-cray/logrus-prefixed-formatter" -) - -const defaultLogFilePermissions fs.FileMode = 0644 - -// LogrusConfig contains all configurable values for the Logrus logger -type LogrusConfig struct { - EnableConsole bool - EnableFile bool - Structured bool - Level logrus.Level - FileLocation string -} - -// LogrusLogger contains all runtime values for using Logrus with the configured output target and input configuration values. -type LogrusLogger struct { - Config LogrusConfig - Logger *logrus.Logger - Output io.Writer -} - -// LogrusNestedLogger is a wrapper for Logrus to enable nested logging configuration (loggers that always attach key-value pairs to all log entries) -type LogrusNestedLogger struct { - Logger *logrus.Entry -} - -// NewLogrusLogger creates a new LogrusLogger with the given configuration -func NewLogrusLogger(cfg LogrusConfig) *LogrusLogger { - appLogger := logrus.New() - - var output io.Writer - switch { - case cfg.EnableConsole && cfg.EnableFile: - logFile, err := os.OpenFile(cfg.FileLocation, os.O_WRONLY|os.O_CREATE, defaultLogFilePermissions) - if err != nil { - panic(fmt.Errorf("unable to setup log file: %w", err)) - } - output = io.MultiWriter(os.Stderr, logFile) - case cfg.EnableConsole: - output = os.Stderr - case cfg.EnableFile: - logFile, err := os.OpenFile(cfg.FileLocation, os.O_WRONLY|os.O_CREATE, defaultLogFilePermissions) - if err != nil { - panic(fmt.Errorf("unable to setup log file: %w", err)) - } - output = logFile - default: - output = io.Discard - } - - appLogger.SetOutput(output) - appLogger.SetLevel(cfg.Level) - - if cfg.Structured { - appLogger.SetFormatter(&logrus.JSONFormatter{ - TimestampFormat: "2006-01-02 15:04:05", - DisableTimestamp: false, - DisableHTMLEscape: false, - PrettyPrint: false, - }) - } else { - appLogger.SetFormatter(&prefixed.TextFormatter{ - TimestampFormat: "2006-01-02 15:04:05", - ForceColors: true, - ForceFormatting: true, - }) - } - - return &LogrusLogger{ - Config: cfg, - Logger: appLogger, - Output: output, - } -} - -// Debugf takes a formatted template string and template arguments for the debug logging level. -func (l *LogrusLogger) Debugf(format string, args ...interface{}) { - l.Logger.Debugf(format, args...) -} - -// Infof takes a formatted template string and template arguments for the info logging level. -func (l *LogrusLogger) Infof(format string, args ...interface{}) { - l.Logger.Infof(format, args...) -} - -// Warnf takes a formatted template string and template arguments for the warning logging level. -func (l *LogrusLogger) Warnf(format string, args ...interface{}) { - l.Logger.Warnf(format, args...) -} - -// Errorf takes a formatted template string and template arguments for the error logging level. -func (l *LogrusLogger) Errorf(format string, args ...interface{}) { - l.Logger.Errorf(format, args...) -} - -// Debug logs the given arguments at the debug logging level. -func (l *LogrusLogger) Debug(args ...interface{}) { - l.Logger.Debug(args...) -} - -// Info logs the given arguments at the info logging level. -func (l *LogrusLogger) Info(args ...interface{}) { - l.Logger.Info(args...) -} - -// Warn logs the given arguments at the warning logging level. -func (l *LogrusLogger) Warn(args ...interface{}) { - l.Logger.Warn(args...) -} - -// Error logs the given arguments at the error logging level. -func (l *LogrusLogger) Error(args ...interface{}) { - l.Logger.Error(args...) -} - -// Debugf takes a formatted template string and template arguments for the debug logging level. -func (l *LogrusNestedLogger) Debugf(format string, args ...interface{}) { - l.Logger.Debugf(format, args...) -} - -// Infof takes a formatted template string and template arguments for the info logging level. -func (l *LogrusNestedLogger) Infof(format string, args ...interface{}) { - l.Logger.Infof(format, args...) -} - -// Warnf takes a formatted template string and template arguments for the warning logging level. -func (l *LogrusNestedLogger) Warnf(format string, args ...interface{}) { - l.Logger.Warnf(format, args...) -} - -// Errorf takes a formatted template string and template arguments for the error logging level. -func (l *LogrusNestedLogger) Errorf(format string, args ...interface{}) { - l.Logger.Errorf(format, args...) -} - -// Debug logs the given arguments at the debug logging level. -func (l *LogrusNestedLogger) Debug(args ...interface{}) { - l.Logger.Debug(args...) -} - -// Info logs the given arguments at the info logging level. -func (l *LogrusNestedLogger) Info(args ...interface{}) { - l.Logger.Info(args...) -} - -// Warn logs the given arguments at the warning logging level. -func (l *LogrusNestedLogger) Warn(args ...interface{}) { - l.Logger.Warn(args...) -} - -// Error logs the given arguments at the error logging level. -func (l *LogrusNestedLogger) Error(args ...interface{}) { - l.Logger.Error(args...) -} diff --git a/internal/ui/ephemeral_terminal_ui.go b/internal/ui/ephemeral_terminal_ui.go index 99b7a08b6..7a413e2e1 100644 --- a/internal/ui/ephemeral_terminal_ui.go +++ b/internal/ui/ephemeral_terminal_ui.go @@ -14,8 +14,8 @@ import ( "github.com/wagoodman/go-partybus" "github.com/wagoodman/jotframe/pkg/frame" + "github.com/anchore/go-logger" "github.com/anchore/syft/internal/log" - "github.com/anchore/syft/internal/logger" syftEvent "github.com/anchore/syft/syft/event" "github.com/anchore/syft/ui" ) @@ -60,9 +60,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() @@ -130,10 +130,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()) } diff --git a/syft/lib.go b/syft/lib.go index 474f3f57b..f10e778a3 100644 --- a/syft/lib.go +++ b/syft/lib.go @@ -21,11 +21,11 @@ import ( "github.com/wagoodman/go-partybus" + "github.com/anchore/go-logger" "github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/linux" - "github.com/anchore/syft/syft/logger" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg/cataloger" "github.com/anchore/syft/syft/source" diff --git a/syft/logger/logger.go b/syft/logger/logger.go deleted file mode 100644 index 3ace363f5..000000000 --- a/syft/logger/logger.go +++ /dev/null @@ -1,16 +0,0 @@ -/* -Package logger defines the logging interface which is used throughout the syft library. -*/ -package logger - -// Logger represents the behavior for logging within the syft library. -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{}) -}