package logger import ( "fmt" "log" "strings" ) // Level represents the logging verbosity level. type Level int const ( LevelDebug Level = iota LevelInfo LevelWarn ) var currentLevel = LevelInfo // SetLevel sets the global log level from a string: "debug", "info", or "warn". func SetLevel(s string) { switch strings.ToLower(s) { case "debug": currentLevel = LevelDebug case "info": currentLevel = LevelInfo case "warn": currentLevel = LevelWarn default: currentLevel = LevelInfo } } // Debug logs a message only when LOG_LEVEL=debug. func Debug(format string, args ...interface{}) { if currentLevel <= LevelDebug { log.Printf(format, args...) } } // Info logs a message when LOG_LEVEL is debug or info. func Info(format string, args ...interface{}) { if currentLevel <= LevelInfo { log.Printf(format, args...) } } // Warn logs a message at any log level (always visible). func Warn(format string, args ...interface{}) { if currentLevel <= LevelWarn { log.Printf(format, args...) } } // Fatal logs and exits. Always visible regardless of level. func Fatal(format string, args ...interface{}) { log.Fatalf(format, args...) } // formatKV formats key=value pairs for structured console output. func formatKV(pairs ...interface{}) string { if len(pairs)%2 != 0 { return fmt.Sprint(pairs...) } var b strings.Builder for i := 0; i < len(pairs); i += 2 { if i > 0 { b.WriteString(" | ") } b.WriteString(fmt.Sprintf("%v=%v", pairs[i], pairs[i+1])) } return b.String() }