After going back to an older project and getting around to update its dependencies I had to realize that logback does not anymore propagate MDCs to children since version 1.1.5
: https://github.com/qos-ch/logback/commit/aa7d584ecdb1638bfc4c7223f4a5ff92d5ee6273
This change makes most of the logs nigh useless.
While I can understand the arguments given in the linked issues, I can not understand why this change could not have been made in a more backwards compatible manner (as is generally usual in java..).
Q: What is the now correct way to achieve the same behaviour other than having to subclass everything from Runnables to Threads?
I see no straightforward way to change this back. Two alternatives that come to mind are:
Way #1: Wrap all Runnable
s
Introduce an abstract class that will copy MDC
from the original Thread
to a new Thread
and use it instead of Runnable
public abstract class MdcAwareRunnable implements Runnable
{
private Map<String, String> originalMdc;
public MdcAwareRunnable()
{
this.originalMdc = MDC.getCopyOfContextMap();
}
@Override
public void run()
{
MDC.setContextMap(originalMdc);
runImpl();
}
protected abstract void runImpl();
/**
* In case some Runnable comes from external API and we can't change that code we can wrap it anyway.
*/
public static MdcAwareRunnable wrap(Runnable runnable)
{
return new MdcAwareRunnable()
{
@Override
protected void runImpl()
{
runnable.run();
}
};
}
}
If some Runnable
comes from an external API that you can't change that code, use wrap
helper method.
Drawback: need to analyze and change whole code.
Way #2: Mess with slf4j internals
Resurrect the original LogbackMDCAdapter
implementation that uses InheritableThreadLocal
from before that commit and put it somewhere in your code under some other name. Then somewhere around startup use reflection to override MDC.mdcAdapter property with and instance of that custom implementation. This is obviously a dirty hack but it saves a lot of troubles comparing to #1.
Note: for performance reasons it makes to inherit your resurrected version from existing LogbackMDCAdapter
and just override all the methods with old implementation. See LoggingEvent.java and LogbackMDCAdapter.getPropertyMap
internal method for some details.
Way #3: Mess with logback jar (even stranger alternative)
This sounds to me as a quite bad plan but for completness here it is.
Again resurrect the original LogbackMDCAdapter
but this time don't rename, compile it and override that .class file inside logback.jar.
Or resurrect the original LogbackMDCAdapter
with renaming, remove .class file for org.slf4j.impl.StaticMDCBinder
from logback.jar and add your own class that will return resurrected version of LogbackMDCAdapter
either to logback.jar or to your code. MDC
seems to be bound to that class by name to create an implementation of MDCAdapter
to use.
Or you can achieve similar result by using custom ClassLoader
that would map org.slf4j.impl.StaticMDCBinder
to your class instead of the one inside logback.jar. Note: this is probably impossible to achieve inside a Web-container that will add its own custom ClassLoaders.