回到一个老项目并更新其依赖后,我不得不意识到自从版本1.1.5
起,logback不再将MDC传播到子级:
这个改变使大部分的日志信息几乎没用了。
虽然我可以理解链接问题中给出的论点,但我不明白为什么这个改变不能以更具有向后兼容性的方式进行(通常在Java中都是这样做的..)。
问:现在除了必须从Runnables到Threads的所有内容进行子类化之外,还有什么其他正确的方法来实现相同的行为?
回到一个老项目并更新其依赖后,我不得不意识到自从版本1.1.5
起,logback不再将MDC传播到子级:
这个改变使大部分的日志信息几乎没用了。
虽然我可以理解链接问题中给出的论点,但我不明白为什么这个改变不能以更具有向后兼容性的方式进行(通常在Java中都是这样做的..)。
问:现在除了必须从Runnables到Threads的所有内容进行子类化之外,还有什么其他正确的方法来实现相同的行为?
Runnable
引入一个抽象类,将MDC
从原始Thread
复制到新的Thread
中,并使用它来代替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();
}
};
}
}
Runnable
是来自于你无法更改的外部API,那么使用wrap
辅助方法。InheritableThreadLocal
的原始LogbackMDCAdapter
实现恢复到提交之前,并将其放在您的代码中的其他位置。然后,在启动时使用反射覆盖MDC.mdcAdapter属性,使用该自定义实现的实例。这显然是一种肮脏的黑客行为,但与第1种方法相比,它可以节省很多麻烦。LogbackMDCAdapter
继承您恢复的版本,并仅使用旧实现覆盖所有方法。请参见LoggingEvent.java和LogbackMDCAdapter.getPropertyMap
内部方法以获取一些详细信息。LogbackMDCAdapter
,但这次不要重命名,编译它并覆盖logback.jar中的.class文件。LogbackMDCAdapter
,从logback.jar中删除org.slf4j.impl.StaticMDCBinder
的.class文件,并添加您自己的类,该类将返回恢复的LogbackMDCAdapter
版本,无论是logback.jar还是您的代码。通过名称将MDC
绑定到该类以创建要使用的MDCAdapter
实现。ClassLoader
来实现类映射,该映射将org.slf4j.impl.StaticMDCBinder
映射到您的类,而不是logback.jar中的类。注意:在Web容器内可能无法实现此目标,因为它会添加其自己的自定义ClassLoader。方法四:误用TurboFilter
ch.qos.logback.classic.Logger
在将日志事件传递给附加器之前会先将其传递给过滤器。
方法五:修改日志编码器/提供程序 虽然这意味着日志事件不会被更新,但日志输出会被更新。