What you are describing is doable, within limits. The passcode list you can keep with the code in PROGMEM, or in EEPROM. You can log to EEPROM, but there are only 1024 bytes to work with, so it's not much of a log.
For bigger logs it's popular to use SD card or an attached network device to log to a server.
I am sorry to inform you that you are a little further from your objective than you may have thought. This happens often in this game. You'll be finished faster if you lose the denial and get on with the work.
It is not possible to run the servo while inside your new hypothetical button lockout if the lockout is implemented as a delay. Delay blocks everything else. This is why it is necessary to use a method that keeps track of time.
You don't want a delay. You want a lockout. Think of it in those terms and you might get somewhere.
You don't need a delay. You need to make note of the time when the button is pressed by saving millis() in an unsigned long variable. Then when the button is pushed again, you need to check the difference between the current time and the saved time and see if enough time has passed to allow the button push to proceed.
What you are trying to accomplish is usually done in C with an array of function pointers, one entry for each of the functions. You can select a random index into the array and call the function through the pointer.
Read up on "function pointer table in C" and you'll get the idea.
With that many functions, it will be worth your while to learn how to put the table of function pointers into PROGMEM, as well.
I mean I used Serial.print in the main loop, in the class functions, and in the constructor…
It's my understanding that your constructor can't do much because the Arduino hardware isn't initialized yet. Printing is a no-no, millis() isn't initialized, and so on. Perhaps someone more familiar with the issue can jump in with more if I've got this wrong.
You could use a .begin() method, like Serial does, to work around this.