回到一个较旧的项目并开始更新其依赖项之后,我必须意识到自从版本以来,logback不再将MDC传播给子项1.1.5:https://github.com/qos-ch/logback/commit/aa7d584ecdb1638bfc4c7223f4a5ff92d5ee6273
这种变化使得大多数日志几乎无用.
虽然我可以理解链接问题中给出的论点,但我无法理解为什么这种更改不能以更向后兼容的方式进行(如java中通常常见的那样).
问:除了必须将所有内容从Runnables子类化为Threads之外,实现相同行为的现在正确的方法是什么?
我认为没有直接的方法可以改变这种情况。我想到的两种选择是:
方式#1:包裹所有Runnables
引入一个抽象类,它将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();
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
如果某些Runnable来自外部 API,您无法更改该代码,请使用wrap辅助方法。
缺点:需要分析和更改整个代码。
方式#2:搞乱 slf4j 内部结构
LogbackMDCAdapter恢复在提交之前使用的原始实现InheritableThreadLocal,并将其以其他名称放在代码中的某个位置。然后在启动时使用反射来覆盖MDC.mdcAdapter属性和该自定义实现的实例。这显然是一个肮脏的黑客行为,但与#1 相比,它省去了很多麻烦。
注意:出于性能原因,它需要从现有版本继承复活版本LogbackMDCAdapter,并使用旧实现覆盖所有方法。有关详细信息,请参阅LoggingEvent.java和内部方法。LogbackMDCAdapter.getPropertyMap
方式#3:搞乱 logback jar(甚至更奇怪的选择)
对我来说,这听起来是一个相当糟糕的计划,但为了完整性,它就是这样。
再次复活原来的文件LogbackMDCAdapter,但这次不要重命名,编译它并覆盖 logback.jar 中的 .class 文件。
或者通过重命名恢复原始版本LogbackMDCAdapter,从 logback.jar 中删除 .class 文件并添加您自己的类,该类将返回logback.jar 或您的代码org.slf4j.impl.StaticMDCBinder的恢复版本。似乎通过名称绑定到该类来创建要使用的实现。LogbackMDCAdapterMDCMDCAdapter
或者,您可以通过使用映射ClassLoader到org.slf4j.impl.StaticMDCBinder您的类的自定义(而不是 logback.jar 中的类)来实现类似的结果。注意:这可能无法在添加自己的自定义类加载器的 Web 容器内实现。
| 归档时间: |
|
| 查看次数: |
950 次 |
| 最近记录: |