Re: has a lot of messages in console.log [...] that human developers tend to keep to a minimum.
I have loads of prints (not printf, something bit more typesafe) in all my code - console apps all have levels of verbosity, GUI apps have cli options to open a console and/or a text widget to collect them. Or you can opt to send them elsewhere. Like a log file.
Very useful for debugging - of the parameters being fed into the programs, of the various scripts that invoke the programs in a larger context and, yes, of the programs themselves: e.g. one useful set of prints will log which places config files were found, how they (re)set command line options and, at the end of it, what the final options settings were.
I take pleasure in formatting the traces through little lexers and parsers, so that when something undesirable/unexpected does happen it is very easy to generate output that clearly shows what went wrong and why. Maybe that is is something wrong in the language implementation, maybe it is something that would be sensible to add to the language or maybe I can point out where the user's syntax wasn't doing what they thought.
> they can't use any more modern debugging technique
Well, the native debugger is very useful - for debugging the engine that trawls through the syntax declarations: yup, that is an augmented FSM interpreter ok, you can watch in excruciating detail how it picks the next state descriptor, and the next - nice tight loop you got there.
Bloody useless at debugging the interactions between the FSM states: talk about not seeing the forest for the trees!
When - if - the language becomes complex enough, it will gain its own debugger. But that is then operating at a higher level than all the above - debugging the user's script.
The same applies to profiling: I can run the native profiler and spot that my tight loop is a bit loose here (and, nope, it isn't spending excessive time skipping the prints when logging is off), but to see a noticeable improvement in parsing speed the rules have to be ordered to match the rate they are actually encountered in real life inputs (minimise failed matches): so the code implements that profiling and, guess what, when it is enabled it generates a formatted log! Using print statements.
And then there are the embedded systems, where attaching a debugger is not even supported - or not worth the cost of setting up the hardware, we aren't going to be using it after this. Or, as above, where the debugger will let us see the deep internals of the language (may be Python, may be Lua - or may be another domain-specific "little language") being interpreted but not anything actually meaningful... Print to a serial port is really useful.