Open ppkarwasz opened 6 months ago
This is a solid proposal I think.
[I am not much familiar with the part of the code base you are talking about, hence apologies in advance if I say something stupid.]
will prevent the propagation of
MDC
for Log4j Core users and the propagation ofThreadContext
for Logback users.
@ppkarwasz, this is the core problem this problem is attacking to, right? That is, avoiding redundant propagation when a particular bridge is in play.
In view of a future integration with
context-propagation
I would propose to:
- modify
MDCContextMap
...- modify
Log4jMDCAdapter
...
I would greatly appreciate it if you can thoroughly document the rationale in the touched parts of the code base while implementing these changes.
@ppkarwasz, this is the core problem this problem is attacking to, right? That is, avoiding redundant propagation when a particular bridge is in play.
Yes, my main motivation is to reduce the overhead of context propagation. See also the discussion at micrometer-metrics/context-propagation#108.
Unfortunately I don't think we can implement these changes by default, since I found examples of legitimate usages of ThreadContext
accessors. E.g.:
Map<String, String> oldMap = ThreadContext.getImmutableMapOrNull();
try {
ThreadContext.put("key", "value");
...
} finally {
ThreadContext.clear();
if (oldMap != null) {
ThreadContext.putAll(oldMap);
}
}
or
String oldValue = ThreadContext.get("key");
try {
ThreadContext.put("key", "value");
...
} finally {
if (oldValue == null) {
ThreadContext.remove("key");
} else {
ThreadContext.put("key", oldValue);
}
}
ThreadContext
API users unfortunately must use accessors or need to switch to CloseableThreadContext
.
I still don't get what the perceived benefit is here. What problem does this solve?
@rgoers,
The problem this tries to solve is to prevent context propagators from copying both MDC#getCopyOfContextMap()
and ThreadContext#getImmutableMapOrNull()
between threads.
Since these two methods return the same data, it would be nice to only propagate one of them: MDC
if the user uses Logback and ThreadContext
if the user uses Log4j Core.
In the case of MDC
and ThreadContext
propagating both of the is only not effective, but for other logging backends it might even be wrong. For example org.jboss.logmanager.MDC
supports objects. If we propagate its data using ThreadContext
we will loose information.
@ppkarwasz Thanks for that. That definitely sounds like something should be done to address it.
Currently we have two bridges between
MDC
andThreadContext
:MDCContextMap
inlog4j-to-slf4j
that forwardsThreadContext
calls toMDC
,Log4jMDCAdapter
inlog4j-slf4j2-impl
andlog4j-slf4j-impl
that forwardsMDC
calls toThreadContext
.While the mutator methods of these bridges are required by user code, the accessors are basically useless:
ThreadContext
accessor,MDC
accessor.The accessors are only used by third-party integrators like the Context Propagation Library (see
Slf4jThreadLocalAccessor
for example).In view of a future integration with
context-propagation
I would propose to:MDCContextMap
accessors to always returnnull
in theget
andgetImmutableMapOrNull
and return a newHashMap
in thegetCopy
method. These values are allowed by theThreadContextMap
contract,Log4jMDCAdapter
accessors to always returnnull
. This value is allowed by theMDCAdapter
contract.These changes will guarantee that at least one of
MDC#getCopyOfContextMap
andThreadContextMap#getImmutableMapOrNull
will returnnull
. According to the semantics of thecontext-propagation
project,null
means "don't propagate" and will prevent the propagation ofMDC
for Log4j Core users and the propagation ofThreadContext
for Logback users.Remark: we can also introduce a
log4j.threadContext.map.bridgeAccessors
property in Log4j 3 andlog4j2.threadContextMapBridgeAccessors
property in Log4j 2 to allow users that useMDC
andThreadContext
for non-logging purposes to restore the previous behavior.