package logger import ( "io" "log/slog" "os" "strings" ) // Config holds the logger configuration type Config struct { ServiceName string Environment string // APP_ENV 기준 LevelOverride string Output io.Writer } func IsProductionLikeEnv(appEnv string) bool { env := strings.ToLower(strings.TrimSpace(appEnv)) return env == "prod" || env == "production" || env == "stage" || env == "staging" } // Init initializes the global logger with slog. // It detects the environment to switch between TextHandler (dev) and JSONHandler (prod). func Init(cfg Config) { var handler slog.Handler output := cfg.Output if output == nil { output = os.Stdout } opts := &slog.HandlerOptions{ Level: ResolveBackendLogLevel(cfg.Environment, cfg.LevelOverride), // Customize attributes (Time format) ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { return slog.String(a.Key, a.Value.Time().Format("2006-01-02 15:04:05")) } return a }, } // Adjust level and format based on environment env := strings.ToLower(cfg.Environment) if env == "dev" || env == "local" || env == "development" { handler = slog.NewTextHandler(output, opts) } else { // Production defaults to JSON handler = slog.NewJSONHandler(output, opts) } // Create logger with common attributes logger := slog.New(handler).With( slog.String("svc", cfg.ServiceName), ) // Set as global default logger slog.SetDefault(logger) } func ResolveBackendLogLevel(appEnv, override string) slog.Level { switch strings.ToLower(strings.TrimSpace(override)) { case "debug": return slog.LevelDebug case "info": return slog.LevelInfo case "warn", "warning": return slog.LevelWarn case "error": return slog.LevelError } env := strings.ToLower(strings.TrimSpace(appEnv)) if env == "dev" || env == "local" || env == "development" { return slog.LevelDebug } return slog.LevelInfo }