How to get back MDC “inheritance” with modern logback?

前端 未结 2 1033
情书的邮戳
情书的邮戳 2021-02-09 13:45

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

相关标签:
2条回答
  • 2021-02-09 14:01

    I see no straightforward way to change this back. Two alternatives that come to mind are:

    Way #1: Wrap all Runnables

    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.

    0 讨论(0)
  • 2021-02-09 14:22

    Way 4: Misuse TurboFilter

    ch.qos.logback.classic.Logger passes the logging event to a filter before passing it along to the appenders.

    Way 5: Modify log Encoder / provider Although this would mean the logging event is not updated, but the log output will be.

    0 讨论(0)
提交回复
热议问题