回到较旧的项目并开始更新其依赖项之后,我必须意识到,自版本$items= $em->getDoctrine->createQueryBuilder()
->select('[items]')
->from(User::class, 'users')
->join('users.items', 'items')
->where('users.id = :userId')
->setParameter('userId', $theId)
->getQuery()
->getResult();
以来,logback不再将MDC传播给子项:https://github.com/qos-ch/logback/commit/aa7d584ecdb1638bfc4c7223f4a5ff92d5ee6273
此更改使大部分日志几乎无用。
虽然我可以理解链接问题中给出的参数,但我无法理解为什么不能以更加向后兼容的方式进行此更改(在java中通常是常见的..)
问:除了必须将所有内容从Runnables子类化为线程之外,现在正确的方式实现相同的行为是什么?
答案 0 :(得分:3)
我认为没有直接的方法来改变它。我想到的两个选择是:
方式#1:包裹所有Runnable
s
引入一个抽象类,将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
辅助方法。
缺点:需要分析和更改整个代码。
方式#2:与slf4j内部混乱
在该提交之前恢复使用LogbackMDCAdapter
的原始InheritableThreadLocal
实现,并将其放在代码中的某个其他名称下。然后在启动周围的某处使用反射来覆盖MDC.mdcAdapter属性和该自定义实现的实例。这显然是一个肮脏的黑客,但它比#1节省了很多麻烦。
注意:出于性能原因,它会从现有LogbackMDCAdapter
继承您的复活版本,并使用旧实现覆盖所有方法。有关详细信息,请参阅LoggingEvent.java和LogbackMDCAdapter.getPropertyMap
内部方法。
方式#3:与logback jar混淆(甚至更奇怪的替代方案)
这对我来说是一个非常糟糕的计划,但对于这里的完整性而言。
再次恢复原始LogbackMDCAdapter
,但这次不重命名,编译它并覆盖logback.jar中的.class文件。
或者通过重命名恢复原始LogbackMDCAdapter
,从logback.jar中删除org.slf4j.impl.StaticMDCBinder
的.class文件,并添加自己的类,将LogbackMDCAdapter
的复活版本返回到logback.jar或者你的代码。 MDC
似乎按名称绑定到该类,以创建要使用的MDCAdapter
实现。
或者您可以使用将ClassLoader
映射到您的类而不是logback.jar中的org.slf4j.impl.StaticMDCBinder
的自定义ggplot(data, aes(x = x, y = Pinera)) +
geom_point(shape = 1) +
geom_smooth(method = loess, se = TRUE)
ggplot(data, aes(x = x, y = Pinera, weight = pesos)) +
geom_point(shape = 1) +
geom_smooth(method = loess, se = TRUE)
来获得类似的结果。注意:在添加自己的自定义ClassLoader的Web容器中可能无法实现这一点。
答案 1 :(得分:0)
方式 4:滥用 TurboFilter
ch.qos.logback.classic.Logger
将日志事件传递给过滤器,然后再将其传递给附加程序。
方式五:修改日志编码器/提供者 虽然这意味着日志事件不会更新,但日志输出会。