GildedRose-Refactoring-Kata/go/lib/logger.go
2023-07-11 20:36:37 +01:00

182 lines
4.7 KiB
Go

package lib
import (
"fmt"
"go.uber.org/fx/fxevent"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// Logger structure
type Logger struct {
*zap.SugaredLogger
}
type GinLogger struct {
*Logger
}
type FxLogger struct {
*Logger
}
var (
globalLogger *Logger
zapLogger *zap.Logger
)
// GetLogger get the logger
func GetLogger() Logger {
if globalLogger == nil {
logger := newLogger(NewEnv())
globalLogger = &logger
}
return *globalLogger
}
// GetGinLogger get the gin logger
func (this Logger) GetGinLogger() GinLogger {
logger := zapLogger.WithOptions(
zap.WithCaller(false),
)
return GinLogger{
Logger: newSugaredLogger(logger),
}
}
// GetFxLogger gets logger for go-fx
func (this *Logger) GetFxLogger() fxevent.Logger {
logger := zapLogger.WithOptions(
zap.WithCaller(false),
)
return &FxLogger{Logger: newSugaredLogger(logger)}
}
// LogEvent log event for fx logger
func (this *FxLogger) LogEvent(event fxevent.Event) {
switch e := event.(type) {
case *fxevent.OnStartExecuting:
this.Logger.Debug("OnStart hook executing: ",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
)
case *fxevent.OnStartExecuted:
if e.Err != nil {
this.Logger.Debug("OnStart hook failed: ",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.Error(e.Err),
)
} else {
this.Logger.Debug("OnStart hook executed: ",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.String("runtime", e.Runtime.String()),
)
}
case *fxevent.OnStopExecuting:
this.Logger.Debug("OnStop hook executing: ",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
)
case *fxevent.OnStopExecuted:
if e.Err != nil {
this.Logger.Debug("OnStop hook failed: ",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.Error(e.Err),
)
} else {
this.Logger.Debug("OnStop hook executed: ",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.String("runtime", e.Runtime.String()),
)
}
case *fxevent.Supplied:
this.Logger.Debug("supplied: ", zap.String("type", e.TypeName), zap.Error(e.Err))
case *fxevent.Provided:
for _, rtype := range e.OutputTypeNames {
this.Logger.Debug("provided: ", e.ConstructorName, " => ", rtype)
}
case *fxevent.Decorated:
for _, rtype := range e.OutputTypeNames {
this.Logger.Debug("decorated: ",
zap.String("decorator", e.DecoratorName),
zap.String("type", rtype),
)
}
case *fxevent.Invoking:
this.Logger.Debug("invoking: ", e.FunctionName)
case *fxevent.Started:
if e.Err == nil {
this.Logger.Debug("started")
}
case *fxevent.LoggerInitialized:
if e.Err == nil {
this.Logger.Debug("initialized: custom fxevent.Logger -> ", e.ConstructorName)
}
}
}
func newSugaredLogger(logger *zap.Logger) *Logger {
return &Logger{
SugaredLogger: logger.Sugar(),
}
}
// newLogger sets up logger
func newLogger(env Env) Logger {
config := zap.NewDevelopmentConfig()
logOutput := env.LogOutput
if env.Environment == "development" {
fmt.Println("encode level")
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
}
if env.Environment == "production" && logOutput != "" {
config.OutputPaths = []string{logOutput}
}
logLevel := env.LogLevel
level := zap.PanicLevel
switch logLevel {
case "debug":
level = zapcore.DebugLevel
case "info":
level = zapcore.InfoLevel
case "warn":
level = zapcore.WarnLevel
case "error":
level = zapcore.ErrorLevel
case "fatal":
level = zapcore.FatalLevel
default:
level = zap.PanicLevel
}
config.Level.SetLevel(level)
zapLogger, _ = config.Build()
logger := newSugaredLogger(zapLogger)
return *logger
}
// Write interface implementation for gin-framework
func (this GinLogger) Write(p []byte) (n int, err error) {
this.Info(string(p))
return len(p), nil
}
// Printf prits go-fx logs
func (this FxLogger) Printf(str string, args ...interface{}) {
if len(args) > 0 {
this.Debugf(str, args)
}
this.Debug(str)
}