package logging import ( "fmt" "io" "log" "os" "strings" ) // Level represents the severity of a log message. type Level int const ( LevelDebug Level = iota LevelInfo LevelWarn LevelError ) // Logger provides level-aware logging. type Logger struct { level Level logger *log.Logger } // Setup configures the global log output destination. // Returns the opened file (if a file path was given) so the caller can defer Close. // For "stdout", "stderr", or empty string, returns nil (no file to close). func Setup(output string) (*os.File, error) { switch strings.ToLower(output) { case "", "stderr": log.SetOutput(os.Stderr) return nil, nil case "stdout": log.SetOutput(os.Stdout) return nil, nil default: file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { return nil, fmt.Errorf("failed to open log file %s: %w", output, err) } log.SetOutput(file) return file, nil } } // NewLogger creates a new Logger with the given level and output writer. // If level is empty or invalid, defaults to LevelInfo. func NewLogger(level string, output io.Writer) *Logger { return &Logger{ level: parseLevel(level), logger: log.New(output, "", log.LstdFlags), } } // Debug logs a message at debug level. func (l *Logger) Debug(msg string) { if l.level <= LevelDebug { l.logger.Printf("[DEBUG] %s", msg) } } // Debugf logs a formatted message at debug level. func (l *Logger) Debugf(format string, args ...interface{}) { if l.level <= LevelDebug { l.logger.Printf("[DEBUG] "+format, args...) } } // Info logs a message at info level. func (l *Logger) Info(msg string) { if l.level <= LevelInfo { l.logger.Printf("[INFO] %s", msg) } } // Infof logs a formatted message at info level. func (l *Logger) Infof(format string, args ...interface{}) { if l.level <= LevelInfo { l.logger.Printf("[INFO] "+format, args...) } } // Warn logs a message at warn level. func (l *Logger) Warn(msg string) { if l.level <= LevelWarn { l.logger.Printf("[WARN] %s", msg) } } // Warnf logs a formatted message at warn level. func (l *Logger) Warnf(format string, args ...interface{}) { if l.level <= LevelWarn { l.logger.Printf("[WARN] "+format, args...) } } // Error logs a message at error level. func (l *Logger) Error(msg string) { if l.level <= LevelError { l.logger.Printf("[ERROR] %s", msg) } } // Errorf logs a formatted message at error level. func (l *Logger) Errorf(format string, args ...interface{}) { if l.level <= LevelError { l.logger.Printf("[ERROR] "+format, args...) } } func parseLevel(level string) Level { switch strings.ToLower(level) { case "debug": return LevelDebug case "info": return LevelInfo case "warn": return LevelWarn case "error": return LevelError default: return LevelInfo } }