Logging mutable objects asynchronously always has the risk that the object is modified between the time the logger is called and the time the log message is formatted and written to disk.
Log4j built-in Message implementation classes prevent this race condition in one of two ways:
- Implement the ReusableMessage interface. Asynchronous logging components in log4j cooperate with ReusableMessages by copying their content (formatted message, parameters) into the LogEvent rather than passing the Message instance itself. This ensures the formatted message will not change when the mutable object is modified.
- Cache the formatted message when the getFormattedMessage method is called. Asynchronous logging components in log4j will call this method before passing the Message object to another thread. (See
LOG4J2-763.) For example, FormattedMessage, LocalizedMessage, MessageFormatMessage, ObjectArrayMessage, ObjectMessage, ParameterizedMessage, SimpleMessage and StringFormattedMessage take this approach. Once initialized, getFormattedMessage returns the cached String, so changes to the mutable object will not impact the formatted message.
For performance reasons, users can choose to format all messages in the background by setting system property log4j.format.msg.async to true. (See
Some messages do not capture mutable objects and are not at risk of the above race condition.
This ticket proposes to introduce interface AsynchronouslyFormattable as a marker interface to signal to asynchronous logging components that messages of this type can safely be passed to a background thread without calling getFormattedMessage first.
This benefits performance and avoids creating unnecessary (unused) objects.
Candidates for implementing this interface are message implementations which do not cache anything in getFormattedMessage:
- flow messages (SimpleEntryMessage and SimpleExitMessage)
- ThreadDumpMessage (threads are cached in the constructor)