package logging import ( "errors" "fmt" "os" "strconv" "time" "github.com/go-logr/logr" zaplib "go.uber.org/zap" "go.uber.org/zap/zapcore" "sigs.k8s.io/controller-runtime/pkg/log/zap" ) const ( LogLevelDebug = "debug" LogLevelInfo = "info" LogLevelWarn = "warn" LogLevelError = "error" LogFormatText = "text" LogFormatJSON = "json" ) var ( LogOpts = zap.Options{ TimeEncoder: zapcore.TimeEncoderOfLayout(time.RFC3339), Development: true, EncoderConfigOptions: []zap.EncoderConfigOption{ func(ec *zapcore.EncoderConfig) { ec.LevelKey = "severity" ec.MessageKey = "message" }, }, } ) func NewLogger(logLevel string, logFormat string) (logr.Logger, error) { if !validLogFormat(logFormat) { return logr.Logger{}, errors.New("invalid log format specified") } o := LogOpts o.EncoderConfigOptions = make([]zap.EncoderConfigOption, len(LogOpts.EncoderConfigOptions)) copy(o.EncoderConfigOptions, LogOpts.EncoderConfigOptions) if logFormat == "json" { o.Development = false o.TimeEncoder = nil } switch logLevel { case LogLevelDebug: lvl := zaplib.NewAtomicLevelAt(zaplib.DebugLevel) // maps to logr's V(1) o.Level = &lvl case LogLevelInfo: lvl := zaplib.NewAtomicLevelAt(zaplib.InfoLevel) o.Level = &lvl case LogLevelWarn: lvl := zaplib.NewAtomicLevelAt(zaplib.WarnLevel) o.Level = &lvl case LogLevelError: lvl := zaplib.NewAtomicLevelAt(zaplib.ErrorLevel) o.Level = &lvl default: // We use bitsize of 8 as zapcore.Level is a type alias to int8 levelInt, err := strconv.ParseInt(logLevel, 10, 8) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse --log-level=%s: %v", logLevel, err) os.Exit(1) } // For example, --log-level=debug a.k.a --log-level=-1 maps to zaplib.DebugLevel, which is associated to logr's V(1) // --log-level=-2 maps the specific custom log level that is associated to logr's V(2). level := zapcore.Level(levelInt) atomicLevel := zaplib.NewAtomicLevelAt(level) o.Level = &atomicLevel } return zap.New(zap.UseFlagOptions(&o)), nil } func validLogFormat(logFormat string) bool { validFormat := []string{"text", "json"} for _, v := range validFormat { if v == logFormat { return true } } return false }