kotlinx.coroutines
kotlinx.coroutines copied to clipboard
Add an integration with Log4J 2's ThreadContext
Log4J 2 has a ThreadContext, which works the same way as SLF4J's MDC. Using the ThreadContext directly with coroutines breaks, but the same approach for an integration that exists for SLF4J can be used for Log4J.
The tests are copied from the SLF4J project, and are only modified to also include verification of stack state, since ThreadContext contains both a Map and a Stack.
@elizarov Thank you very much for the feedback. I feel I gained a much better understanding of coroutines from it, and appreciate you taking the time to leave it.
I've applied the changes you suggested, and will summarize them below.
- Dropped support for the logging context stack. It now only supports the Map. Conversations from the Log4J 2 maintainers suggested that using the stack is not really encouraged. This matches the behavior I've seen in other applications.
- Renamed
Log4JThreadContext
->DiagnosticContext
as I think it is unlikely for developers to have multiple conflicting classes of the same name, and I wanted to get away from thinking about threads. - Added the
MutableDiagnosticContext
type, for cases when the state for the duration of the coroutine context should be modified. The API for this matches closely with that of Log4J'sCloseableThreadContext
, which rolls-back the state whenclose()
is called. - Added the
immutableDiagnosticContext()
function to create an optimized instance ofDiagnosticContext
for cases when the state should be captured when the coroutine context starts, but will not be modified.
@MariusVolkhart Any updates on this integration?
@t1mwillis What sort of an update are you looking for? I believe this code to be working, but I've only had limited ability to deploy it into production.
@elizarov would you please take another look at this?
@t1mwillis It has recently occurred to me that it may be possible to implement the ThreadContextMap
interface in such a way that the CoroutineContext
is used as the storage container, rather than a ThreadLocal
map as is used by the default ThreadContextMap
subclasses. The API would probably look pretty similar, but there would likely be one round of copying things from the CoroutineContext
to theThreadLocal
and back saved.
I haven't had the chance to investigate this yet.
@MariusVolkhart my use case was simply having a structured way to write a tracking id from the parent thread to a coroutine. At present I am grabbing this tracking id from the parent thread and then setting it in the coroutine using threadContext.put('trackingid', parentThreadTrackingId)
. This works but seems unnecessary