For #3, I agree that we should perform formatting on the application thread before transferring control to an asynchronous thread.
> On Feb 5, 2024, at 14:49, Piotr P. Karwasz <piotr.karw...@gmail.com> wrote: > > Hi all (and especially Remko), > > Lately I spent some time looking at the asynchronous logger/logger > config and I think it could profit from some refactoring in 3.x. > > The problems I am seeing are: > > 1. The disruptors of `AsyncLogger` and `AsyncLoggerConfig` use > different structures. The disruptor of `AsyncLoggerConfig` contains > basically a `Pair<AsyncLogger, LogEvent>`, while `AsyncLogger` uses > `RingBufferLogEvent`, which is basically `MutableLogEvent` with an > additional field of type `AsyncLogger`. > > The design of the `AsyncLoggerConfigDisruptor` seems better: it always > uses an allocation-free `EventTranslatorTwoArg`[1], while > `AsyncLoggerDisruptor` users must choose between a > `EventTranslatorVarArg` which allocates a temporary array and an > `EventTranslator` that copies the log event into a thread-bound > structure first. > > Can we remove `RingBufferLogEvent` and use `Pair<AsyncLogger, > MutableLogEvent>` instead? > > 2. I am not convinced by the utility of having multiple > implementations of `ReusableMessage`. Since the `ReusableMessage` > interface does not specify how to format messages, transferring data > between a `ReusableParameterizedMessage` and `MutableLogEvent` > requires a call to `ReusableMessage#formatTo` to account for the > possibility of different formatting algorithms. > > We could remove `ReusableObjectMessage`, `ReusableSimpleMessage`, > `ReusableParameterizedMessage` and merge `ReusableMessageFactory` with > `ReusableLogEventFactory`. > > Instead of 4 thread locals for each type of `ReusableMessage` we would > just have a single `Recycler<MutableLogEvent>` and the performance of > `MutableLogEvent#setMessage` could be improved: > > public void setMessage(final Message message) { > if (message instanceof MutableLogEvent) { > // NOP > } else ... > } > > 3. Before a thread jump, three values must be computed: the source > location (optional), the context map and the formatted message. > Currently the location were these are computed varies and can be as > early as the `ReusableLogEventFactory`. I would propose to move them > to the last moment before we pass control to another thread, i.e.: > > * in `EventTranslator#translateTo` (this way nothing is computed if > the ring buffer is full and the `AsyncQueueFullPolicy` chooses to > discard the message) for `AsyncLogger`/`AsyncLoggerConfig`, > * just before the call to `Queue#offer` for the `AsyncAppender`. > > What do you think? > > Piotr > > [1] > https://lmax-exchange.github.io/disruptor/javadoc/com.lmax.disruptor/com/lmax/disruptor/EventTranslatorTwoArg.html