如何找回MDC"继承"与现代的logback?

时间:2017-03-27 18:04:22

标签: logback slf4j mdc

回到较旧的项目并开始更新其依赖项之后,我必须意识到,自版本$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子类化为线程之外,现在正确的方式实现相同的行为是什么?

2 个答案:

答案 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.javaLogbackMDCAdapter.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 将日志事件传递给过滤器,然后再将其传递给附加程序。

方式五:修改日志编码器/提供者 虽然这意味着日志事件不会更新,但日志输出会。