The logger functionality is provided by the Logging trait.
This trait is mixed into, for example, the DataProcessor class.
This trait has mutable members.
This is a mistake. The PState/UState also mix in the Logging trait for use at runtime that way each thread (which requires a unique PState/UState) can have its own logger, own state for whether logging is on/off, own logging level, own I/O streams for writing to the log, etc.
Currently the DataProcessor.doUnparse method is the only thing that calls DataProcessor.log, but it should be calling ustate.log instead.
This change has API implications however, as the API for setting a logger and turning on logging needs to arrange for that information to be recorded on the PState/UState, but those objects aren't directly visible to the API.
Since the logger is mutable state, we really don't want users to establish a single logger on the say, compiler or ProcessorFactory object instance, or even the DataProcessor instance, since that logger really should not get shared if users call parse multiple times on different threads. Rather, each parse/unparse call, which can be done on a separate thread, needs to be able to establish all its own mutable state.
Unfortunately, right now the parse() call takes two arguments, the InputSourceDataInputStream, and the InfosetOutputter. I suppose the InputSourceDataInputStream, which cannot be shared, could have the logger methods mixed into it..... doesn't seem particularly clean.
There are two different loggers: the compile-time logger, and the runtime logger(s) - the latter is plural since there can be distinct ones per each thread used for a parse or unparse call.