From fb5692186f935398fe2794cd8cd0b65755611112 Mon Sep 17 00:00:00 2001 From: rawmind0 Date: Tue, 29 Oct 2024 15:35:07 +0100 Subject: [PATCH] Update logger to facilitate the use of global logger --- Makefile | 6 +++ cmd/demo-cli/main.go | 1 + pkg/cli/config.go | 7 ++-- pkg/cli/handlers.go | 8 ++-- pkg/cli/root.go | 27 ++++++------- pkg/logger/README.md | 40 ++++++++++++++++++++ pkg/logger/global.go | 88 +++++++++++++++++++++++++++++++++++++++++++ pkg/logger/logger.go | 65 ++++++++------------------------ pkg/logger/methods.go | 2 +- 9 files changed, 173 insertions(+), 71 deletions(-) create mode 100644 pkg/logger/README.md create mode 100644 pkg/logger/global.go diff --git a/Makefile b/Makefile index e66170d..a958500 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,12 @@ check-modtidy: go mod tidy git diff --exit-code -- go.mod go.sum +fmt: + gofmt -l -s -w . + +vet: + go vet ./... + lint: golangci-lint --version golangci-lint run diff --git a/cmd/demo-cli/main.go b/cmd/demo-cli/main.go index 552e249..2b48d69 100644 --- a/cmd/demo-cli/main.go +++ b/cmd/demo-cli/main.go @@ -13,6 +13,7 @@ func main() { EnvPrefix: "golem", GitVersion: version.GitVersion, GitRevision: version.GitRevision, + LogLevel: "debug" } // Define application level features diff --git a/pkg/cli/config.go b/pkg/cli/config.go index f033443..45b1238 100644 --- a/pkg/cli/config.go +++ b/pkg/cli/config.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "github.com/zondax/golem/pkg/logger" "strings" @@ -15,7 +14,7 @@ func SetupConfiguration(c *cobra.Command) { c.PersistentFlags().StringVarP(&configFileFlag, "config", "c", "", "The path to the config file to use.") err := viper.BindPFlag("config", c.PersistentFlags().Lookup("config")) if err != nil { - logger.GetLoggerFromContext(context.Background()).Fatalf("unable to bind config flag: %+v", err) + logger.Fatalf("unable to bind config flag: %+v", err) } viper.SetConfigName("config") // config file name without extension @@ -50,12 +49,12 @@ func LoadConfig[T Config]() (*T, error) { configFileOverride := viper.GetString("config") if configFileOverride != "" { viper.SetConfigFile(configFileOverride) - logger.GetLoggerFromContext(context.Background()).Infof("Using config file: %s", viper.ConfigFileUsed()) + logger.Infof("Using config file: %s", viper.ConfigFileUsed()) } err = viper.ReadInConfig() if err != nil { - logger.GetLoggerFromContext(context.Background()).Fatalf("%+v", err) + logger.Fatalf("%+v", err) } // adds all default+configFile values in viper to struct diff --git a/pkg/cli/handlers.go b/pkg/cli/handlers.go index e150a81..1f50ad8 100644 --- a/pkg/cli/handlers.go +++ b/pkg/cli/handlers.go @@ -1,11 +1,11 @@ package cli import ( - "context" - "github.com/zondax/golem/pkg/logger" "os" "os/signal" "syscall" + + "github.com/zondax/golem/pkg/logger" ) var defaultConfigHandler DefaultConfigHandler @@ -15,13 +15,13 @@ func setupCloseHandler(handler CleanUpHandler) { signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c - logger.GetLoggerFromContext(context.Background()).Warn("\r- Ctrl+C pressed in Terminal") + logger.Warn("\r- Ctrl+C pressed in Terminal") if handler != nil { handler() } - _ = logger.Sync() // Sync logger + logger.Sync() // Sync logger // TODO: friendly closing callback os.Exit(0) }() diff --git a/pkg/cli/root.go b/pkg/cli/root.go index 9a34b25..acd432e 100644 --- a/pkg/cli/root.go +++ b/pkg/cli/root.go @@ -2,11 +2,11 @@ package cli import ( "fmt" + "os" + "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/zondax/golem/pkg/constants" "github.com/zondax/golem/pkg/logger" - "os" ) type AppSettings struct { @@ -16,6 +16,7 @@ type AppSettings struct { EnvPrefix string // environment variable MYAPP_..... GitVersion string GitRevision string + LogLevel string // Global log level for the app } type CLI struct { @@ -50,9 +51,9 @@ func (c *CLI) init() { Run: func(cmd *cobra.Command, args []string) { err := c.checkConfig() if err != nil { - fmt.Printf("%s\n", c.checkConfig().Error()) + logger.Errorf("%s\n", c.checkConfig().Error()) } else { - fmt.Printf("Configuration OK\n") + logger.Infof("Configuration OK\n") } }, } @@ -61,15 +62,18 @@ func (c *CLI) init() { Use: "version", Short: "Print version", Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("%s\n", c.GetVersionString()) + logger.Infof("%s\n", c.GetVersionString()) }, } c.GetRoot().AddCommand(checkCmd) c.GetRoot().AddCommand(versionCmd) - // TODO: We can make this optional? and more configurable if we see the need - logger.InitLogger(logger.Config{Level: constants.DebugLevel}) + // If app log level is defined it is configued, logger.defaultConfig by default + if len(c.app.LogLevel) > 0 { + logger.InitLogger(logger.Config{Level: c.app.LogLevel}) + } + setupCloseHandler(nil) // Set Configuration Defaults setupDefaultConfiguration(func() { @@ -91,15 +95,12 @@ func (c *CLI) GetVersionString() string { func (c *CLI) Run() { if err := c.rootCmd.Execute(); err != nil { - _, err := fmt.Fprintln(os.Stderr, err) - if err != nil { - return - } - _ = logger.Sync() + logger.Error(err.Error()) + logger.Sync() os.Exit(1) } } func (c *CLI) Close() { - _ = logger.Sync() + logger.Sync() } diff --git a/pkg/logger/README.md b/pkg/logger/README.md new file mode 100644 index 0000000..5a0671c --- /dev/null +++ b/pkg/logger/README.md @@ -0,0 +1,40 @@ +# logger package + +The logger package is intended to make unified log management in the whole app + +The log may be used in 2 ways: + +- Global: easy use of the global logger without the need to init or configure. +``` +package main + +import ( + "github.com/zondax/golem/pkg/logger" +) + +func main() { + // Importing logger global logger is configured in info level and may be used + logger.Info("Log info message") + + // Reconfigure global logger with config + logger.SetGlobalConfig(logger.Config{Level: "debug"}) + logger.Info("Log debug message") + logger.Sync() +} +``` + +- Local: use distinct logger for the package +``` +package main + +import ( + "github.com/zondax/golem/pkg/logger" +) + +func main() { + // Generate new logger with options and use it + log := logger.NewLogger(opts ...interface{}) + log.Info("Log info message") + log.Sync() +} +``` diff --git a/pkg/logger/global.go b/pkg/logger/global.go new file mode 100644 index 0000000..573cc9b --- /dev/null +++ b/pkg/logger/global.go @@ -0,0 +1,88 @@ +package logger + +import ( + "go.uber.org/zap" +) + +func ReplaceGlobals(logger *zap.Logger) func() { + return zap.ReplaceGlobals(logger) +} + +func SetGlobalConfig(config Config) func() { + logger := configureAndBuildLogger(config) + return ReplaceGlobals(logger) +} + +func L() *zap.Logger { + return zap.L() +} + +func S() *zap.SugaredLogger { + return zap.S() +} + +func Info(msg string) { + L().Info(msg) +} + +func Debug(msg string) { + L().Debug(msg) +} + +func Warn(msg string) { + L().Warn(msg) +} + +func Error(msg string) { + L().Error(msg) +} + +func DPanic(msg string) { + L().DPanic(msg) +} + +func Panic(msg string) { + L().Panic(msg) +} + +func Fatal(msg string) { + L().Fatal(msg) +} + +func Infof(template string, args ...interface{}) { + S().Infof(template, args...) +} + +func Debugf(template string, args ...interface{}) { + S().Debugf(template, args...) +} + +func Warnf(template string, args ...interface{}) { + S().Warnf(template, args...) +} + +func Errorf(template string, args ...interface{}) { + S().Errorf(template, args...) +} + +func DPanicf(template string, args ...interface{}) { + S().DPanicf(template, args...) +} + +func Panicf(template string, args ...interface{}) { + S().Panicf(template, args...) +} + +func Fatalf(template string, args ...interface{}) { + S().Fatalf(template, args...) +} + +func Sync() error { + // Sync global logger + err := L().Sync() + if err != nil { + return err + } + // Sync global sugar logger + return S().Sync() +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 66d7494..f56062b 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -1,10 +1,10 @@ package logger import ( + "strings" + "go.uber.org/zap" "go.uber.org/zap/zapcore" - "strings" - "sync" ) const ( @@ -14,10 +14,10 @@ const ( var ( defaultConfig = Config{ - Level: "info", + Level: "info", + Encoding: "json", } - baseLogger *zap.Logger - lock sync.RWMutex + defaultOptions = []zap.Option{zap.AddCallerSkip(1), zap.AddStacktrace(zapcore.ErrorLevel)} ) type Config struct { @@ -34,49 +34,35 @@ type Logger struct { logger *zap.Logger } -var stringToLevel = map[string]zapcore.Level{ - "debug": zapcore.DebugLevel, - "info": zapcore.InfoLevel, - "warn": zapcore.WarnLevel, - "error": zapcore.ErrorLevel, - "fatal": zapcore.FatalLevel, - "panic": zapcore.PanicLevel, +func init() { + InitLogger(defaultConfig) } func InitLogger(config Config) { - lock.Lock() - defer lock.Unlock() - - baseLogger = configureAndBuildLogger(config) + baseLogger := configureAndBuildLogger(config) zap.ReplaceGlobals(baseLogger) } func NewLogger(opts ...interface{}) *Logger { - lock.Lock() - defer lock.Unlock() - var config *Config - var fields []Field + var zapFields []zap.Field for _, opt := range opts { switch opt := opt.(type) { case Config: config = &opt case Field: - fields = append(fields, opt) + zapFields = append(zapFields, zap.Any(opt.Key, opt.Value)) } } - logger := configureAndBuildLogger(defaultConfig) - if baseLogger != nil { - logger = baseLogger.WithOptions(zap.AddCallerSkip(1)) - } + logger := L().WithOptions(defaultOptions...) if config != nil { logger = configureAndBuildLogger(*config) } - logger = logger.With(toZapFields(fields)...) + logger = logger.With(zapFields...) return &Logger{logger: logger} } @@ -91,35 +77,16 @@ func configureAndBuildLogger(config Config) *zap.Logger { encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder cfg.EncoderConfig = encoderConfig - level := zapcore.InfoLevel - if l, ok := stringToLevel[strings.ToLower(config.Level)]; ok { - level = l + level, err := zapcore.ParseLevel(strings.ToLower(config.Level)) + if err != nil { + level = zapcore.InfoLevel } cfg.Level = zap.NewAtomicLevelAt(level) - logger, err := cfg.Build(zap.AddCallerSkip(1), zap.AddStacktrace(zapcore.ErrorLevel)) + logger, err := cfg.Build(defaultOptions...) if err != nil { panic(initializingLogError + err.Error()) } return logger } - -func Sync() error { - lock.Lock() - defer lock.Unlock() - - return baseLogger.Sync() -} - -func DefaultConfig() Config { - return defaultConfig -} - -func toZapFields(fields []Field) []zap.Field { - var zapFields []zap.Field - for _, field := range fields { - zapFields = append(zapFields, zap.Any(field.Key, field.Value)) - } - return zapFields -} diff --git a/pkg/logger/methods.go b/pkg/logger/methods.go index c2064ed..0ae518e 100644 --- a/pkg/logger/methods.go +++ b/pkg/logger/methods.go @@ -71,7 +71,7 @@ func (l *Logger) WithFields(fields ...zap.Field) *Logger { } func (l *Logger) IsDebugEnabled() bool { - return baseLogger.Core().Enabled(zap.DebugLevel) + return l.logger.Core().Enabled(zap.DebugLevel) } func GetLoggerFromContext(ctx context.Context) *Logger {