From eed6d22253594ff0b2129cb08ec4b4d140fa0962 Mon Sep 17 00:00:00 2001 From: Dipesh Dulal Date: Mon, 9 Aug 2021 10:47:59 +0545 Subject: [PATCH 1/5] chore: update logger to remove depdendency from env --- lib/lib.go | 2 +- lib/logger.go | 59 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/lib/lib.go b/lib/lib.go index 8ad3248..8a3aae0 100644 --- a/lib/lib.go +++ b/lib/lib.go @@ -6,6 +6,6 @@ import "go.uber.org/fx" var Module = fx.Options( fx.Provide(NewRequestHandler), fx.Provide(NewEnv), - fx.Provide(NewLogger), + fx.Provide(GetLogger), fx.Provide(NewDatabase), ) diff --git a/lib/logger.go b/lib/logger.go index b8a3474..0e5a973 100644 --- a/lib/logger.go +++ b/lib/logger.go @@ -1,6 +1,8 @@ package lib import ( + "os" + "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -10,22 +12,63 @@ type Logger struct { *zap.SugaredLogger } -// NewLogger sets up logger -func NewLogger(env Env) Logger { +type GinLogger struct { + *Logger +} + +var ( + globalLogger *Logger + zapLogger *zap.Logger +) + +// GetLogger get the logger +func GetLogger() Logger { + if globalLogger == nil { + logger := newLogger() + globalLogger = &logger + } + return *globalLogger +} + +// GetGinLogger get the gin logger +func (l Logger) GetGinLogger() GinLogger { + logger := zapLogger.WithOptions( + zap.WithCaller(false), + ) + return GinLogger{ + Logger: newSugaredLogger(logger), + } +} + +func newSugaredLogger(logger *zap.Logger) *Logger { + return &Logger{ + SugaredLogger: logger.Sugar(), + } +} + +// newLogger sets up logger +func newLogger() Logger { config := zap.NewDevelopmentConfig() + env := os.Getenv("ENV") + logOutput := os.Getenv("LOG_OUTPUT") - if env.Environment == "development" { + if env == "development" { config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder } - if env.Environment == "production" && env.LogOutput != "" { - config.OutputPaths = []string{env.LogOutput} + if env == "production" && logOutput != "" { + config.OutputPaths = []string{logOutput} } - logger, _ := config.Build() + zapLogger, _ = config.Build() + logger := newSugaredLogger(zapLogger) - sugar := logger.Sugar() + return *logger +} - return Logger{sugar} +// Write interface implementation for gin-framework +func (l GinLogger) Write(p []byte) (n int, err error) { + l.Info(string(p)) + return len(p), nil } From 38e95e2bbdb5cd0fe7ab9921abb1a35106bbeac1 Mon Sep 17 00:00:00 2001 From: Dipesh Dulal Date: Mon, 9 Aug 2021 10:48:16 +0545 Subject: [PATCH 2/5] feat: use zap logger in request handler gin framework --- lib/request_handler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/request_handler.go b/lib/request_handler.go index 2121b7a..b09f8ed 100644 --- a/lib/request_handler.go +++ b/lib/request_handler.go @@ -10,7 +10,8 @@ type RequestHandler struct { } // NewRequestHandler creates a new request handler -func NewRequestHandler() RequestHandler { +func NewRequestHandler(logger Logger) RequestHandler { + gin.DefaultWriter = logger.GetGinLogger() engine := gin.New() return RequestHandler{Gin: engine} } From a310ce300373bcf3881196ff2cd81ce5bdc1f2b6 Mon Sep 17 00:00:00 2001 From: Dipesh Dulal Date: Mon, 9 Aug 2021 11:14:46 +0545 Subject: [PATCH 3/5] chore: unify logger for go-fx --- lib/logger.go | 20 ++++++++++++++++++++ server.go | 8 +++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/logger.go b/lib/logger.go index 0e5a973..e75b980 100644 --- a/lib/logger.go +++ b/lib/logger.go @@ -16,6 +16,10 @@ type GinLogger struct { *Logger } +type FxLogger struct { + *Logger +} + var ( globalLogger *Logger zapLogger *zap.Logger @@ -40,6 +44,17 @@ func (l Logger) GetGinLogger() GinLogger { } } +// GetFxLogger get the fx logger +func (l Logger) GetFxLogger() FxLogger { + logger := zapLogger.WithOptions( + zap.WithCaller(false), + ) + + return FxLogger{ + Logger: newSugaredLogger(logger), + } +} + func newSugaredLogger(logger *zap.Logger) *Logger { return &Logger{ SugaredLogger: logger.Sugar(), @@ -72,3 +87,8 @@ func (l GinLogger) Write(p []byte) (n int, err error) { l.Info(string(p)) return len(p), nil } + +// Printf prits go-fx logs +func (l FxLogger) Printf(str string, args ...interface{}) { + l.Infof(str, args) +} diff --git a/server.go b/server.go index 7852f5e..3cd632d 100755 --- a/server.go +++ b/server.go @@ -2,13 +2,15 @@ package main import ( "github.com/dipeshdulal/clean-gin/bootstrap" + "github.com/dipeshdulal/clean-gin/lib" + _ "github.com/go-sql-driver/mysql" "github.com/joho/godotenv" "go.uber.org/fx" - _ "github.com/go-sql-driver/mysql" - ) func main() { godotenv.Load() - fx.New(bootstrap.Module).Run() + + logger := lib.GetLogger().GetFxLogger() + fx.New(bootstrap.Module, fx.Logger(logger)).Run() } From 3f3c48ffdcc477e2407c085a4aac9eac7b35df21 Mon Sep 17 00:00:00 2001 From: Dipesh Dulal Date: Mon, 9 Aug 2021 11:20:09 +0545 Subject: [PATCH 4/5] chore: unify logger for viper --- lib/env.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/env.go b/lib/env.go index da65f48..38e602a 100644 --- a/lib/env.go +++ b/lib/env.go @@ -1,8 +1,6 @@ package lib import ( - "log" - "github.com/spf13/viper" ) @@ -20,7 +18,8 @@ type Env struct { } // NewEnv creates a new environment -func NewEnv() Env { +func NewEnv(log Logger) Env { + env := Env{} viper.SetConfigFile(".env") @@ -34,6 +33,6 @@ func NewEnv() Env { log.Fatal("☠️ environment can't be loaded: ", err) } - log.Printf("%+v \n", env) + log.Infof("%+v \n", env) return env } From a75abf84496dc174313a90bb2f4254633da2a818 Mon Sep 17 00:00:00 2001 From: Dipesh Dulal Date: Mon, 9 Aug 2021 11:30:35 +0545 Subject: [PATCH 5/5] chore: unify logger for gorm --- lib/db.go | 23 ++++----------- lib/logger.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/lib/db.go b/lib/db.go index 195ad00..2b591ee 100644 --- a/lib/db.go +++ b/lib/db.go @@ -2,13 +2,9 @@ package lib import ( "fmt" - "log" - "os" - "time" "gorm.io/driver/mysql" "gorm.io/gorm" - "gorm.io/gorm/logger" ) // Database modal @@ -17,7 +13,7 @@ type Database struct { } // NewDatabase creates a new database instance -func NewDatabase(env Env, zapLogger Logger) Database { +func NewDatabase(env Env, logger Logger) Database { username := env.DBUsername password := env.DBPassword @@ -27,25 +23,16 @@ func NewDatabase(env Env, zapLogger Logger) Database { url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", username, password, host, port, dbname) - newLogger := logger.New( - log.New(os.Stdout, "\r\n", log.LstdFlags), - logger.Config{ - SlowThreshold: time.Second, - LogLevel: logger.Info, - Colorful: true, - }, - ) - db, err := gorm.Open(mysql.Open(url), &gorm.Config{ - Logger: newLogger, + Logger: logger.GetGormLogger(), }) if err != nil { - zapLogger.Info("Url: ", url) - zapLogger.Panic(err) + logger.Info("Url: ", url) + logger.Panic(err) } - zapLogger.Info("Database connection established") + logger.Info("Database connection established") return Database{ DB: db, diff --git a/lib/logger.go b/lib/logger.go index e75b980..782c10a 100644 --- a/lib/logger.go +++ b/lib/logger.go @@ -1,10 +1,14 @@ package lib import ( + "context" "os" + "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" + + gormlogger "gorm.io/gorm/logger" ) // Logger structure @@ -20,6 +24,11 @@ type FxLogger struct { *Logger } +type GormLogger struct { + *Logger + gormlogger.Config +} + var ( globalLogger *Logger zapLogger *zap.Logger @@ -55,6 +64,21 @@ func (l Logger) GetFxLogger() FxLogger { } } +// GetGormLogger gets the gorm framework logger +func (l Logger) GetGormLogger() *GormLogger { + logger := zapLogger.WithOptions( + zap.AddCaller(), + zap.AddCallerSkip(3), + ) + + return &GormLogger{ + Logger: newSugaredLogger(logger), + Config: gormlogger.Config{ + LogLevel: gormlogger.Info, + }, + } +} + func newSugaredLogger(logger *zap.Logger) *Logger { return &Logger{ SugaredLogger: logger.Sugar(), @@ -92,3 +116,60 @@ func (l GinLogger) Write(p []byte) (n int, err error) { func (l FxLogger) Printf(str string, args ...interface{}) { l.Infof(str, args) } + +// GORM Framework Logger Interface Implementations +// ---- START ---- + +// LogMode set log mode +func (l *GormLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface { + newlogger := *l + newlogger.LogLevel = level + return &newlogger +} + +// Info prints info +func (l GormLogger) Info(ctx context.Context, str string, args ...interface{}) { + if l.LogLevel >= gormlogger.Info { + l.Debugf(str, args...) + } +} + +// Warn prints warn messages +func (l GormLogger) Warn(ctx context.Context, str string, args ...interface{}) { + if l.LogLevel >= gormlogger.Warn { + l.Warnf(str, args...) + } + +} + +// Error prints error messages +func (l GormLogger) Error(ctx context.Context, str string, args ...interface{}) { + if l.LogLevel >= gormlogger.Error { + l.Errorf(str, args...) + } +} + +// Trace prints trace messages +func (l GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { + if l.LogLevel <= 0 { + return + } + elapsed := time.Since(begin) + if l.LogLevel >= gormlogger.Info { + sql, rows := fc() + l.Debug("[", elapsed.Milliseconds(), " ms, ", rows, " rows] ", "sql -> ", sql) + return + } + + if l.LogLevel >= gormlogger.Warn { + sql, rows := fc() + l.SugaredLogger.Warn("[", elapsed.Milliseconds(), " ms, ", rows, " rows] ", "sql -> ", sql) + return + } + + if l.LogLevel >= gormlogger.Error { + sql, rows := fc() + l.SugaredLogger.Error("[", elapsed.Milliseconds(), " ms, ", rows, " rows] ", "sql -> ", sql) + return + } +}