package logger import ( "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) var ( Log *zap.Logger Sugar *zap.SugaredLogger ) // Config holds logger configuration type Config struct { Level string `mapstructure:"level"` Encoding string `mapstructure:"encoding"` OutputPath string `mapstructure:"output_path"` } // Init initializes the global logger func Init(cfg *Config) error { level := zapcore.InfoLevel if cfg != nil && cfg.Level != "" { if err := level.UnmarshalText([]byte(cfg.Level)); err != nil { return err } } encoding := "json" if cfg != nil && cfg.Encoding != "" { encoding = cfg.Encoding } outputPath := "stdout" if cfg != nil && cfg.OutputPath != "" { outputPath = cfg.OutputPath } zapConfig := zap.Config{ Level: zap.NewAtomicLevelAt(level), Development: false, DisableCaller: false, DisableStacktrace: false, Sampling: nil, Encoding: encoding, EncoderConfig: zapcore.EncoderConfig{ MessageKey: "message", LevelKey: "level", TimeKey: "time", NameKey: "logger", CallerKey: "caller", FunctionKey: zapcore.OmitKey, StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.LowercaseLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, }, OutputPaths: []string{outputPath}, ErrorOutputPaths: []string{"stderr"}, } var err error Log, err = zapConfig.Build() if err != nil { return err } Sugar = Log.Sugar() return nil } // InitDevelopment initializes logger for development environment func InitDevelopment() error { var err error Log, err = zap.NewDevelopment() if err != nil { return err } Sugar = Log.Sugar() return nil } // InitProduction initializes logger for production environment func InitProduction() error { var err error Log, err = zap.NewProduction() if err != nil { return err } Sugar = Log.Sugar() return nil } // Sync flushes any buffered log entries func Sync() error { if Log != nil { return Log.Sync() } return nil } // WithFields creates a new logger with additional fields func WithFields(fields ...zap.Field) *zap.Logger { return Log.With(fields...) } // Debug logs a debug message func Debug(msg string, fields ...zap.Field) { Log.Debug(msg, fields...) } // Info logs an info message func Info(msg string, fields ...zap.Field) { Log.Info(msg, fields...) } // Warn logs a warning message func Warn(msg string, fields ...zap.Field) { Log.Warn(msg, fields...) } // Error logs an error message func Error(msg string, fields ...zap.Field) { Log.Error(msg, fields...) } // Fatal logs a fatal message and exits func Fatal(msg string, fields ...zap.Field) { Log.Fatal(msg, fields...) } // Panic logs a panic message and panics func Panic(msg string, fields ...zap.Field) { Log.Panic(msg, fields...) } // Field creates a zap field func Field(key string, value interface{}) zap.Field { return zap.Any(key, value) } // String creates a string field func String(key, value string) zap.Field { return zap.String(key, value) } // Int creates an int field func Int(key string, value int) zap.Field { return zap.Int(key, value) } // Err creates an error field func Err(err error) zap.Field { return zap.Error(err) } func init() { // Initialize with development logger by default // This will be overridden when Init() is called with proper config if os.Getenv("ENV") == "production" { _ = InitProduction() } else { _ = InitDevelopment() } }