Logback MDC put()可变对象

时间:2013-09-20 09:10:08

标签: java vaadin logback slf4j mdc

我正在使用Vaadin框架,它对拦截事件的支持很少,我不知道会话或UI何时被激活,所以我不能将它们的ID放在MDC中。

通常我会:

public void onSessionBegin(){
    MDC.put("session", VaadinSession.getCurrent().toString()); //<-- String is immutable
}
public void onSessionEnd(){
    MDC.remove("session");
}

但我没有这样的事件,所以我想:

// in the servlet init or wherever
MDC.put("session", new Object(){
        public String toString() {
            VaadinSession.getCurrent().toString()
        };
    }); //<-- This is mutable and will be evaluated each time

这样,无论有多少时间会改变会话,在日志中我都会得到当前的会话。

这可能吗?如何使用自定义MDC实现替换logback MDC实现?我应该编辑slf4j和logback的来源吗?

1 个答案:

答案 0 :(得分:4)

您不希望从每个日志记录行的线程局部变量中检索当前会话(这是VaadinSession.getCurrent()所做的)。 API使用静态String类型,因为它是最快的。

Vaadin确实有SessionInitListenerSessionDestroyListener,但这也不是你想要的:MDC是线程本地的,但不是同一个会话中的所有请求都在同一个线程内处理。因此,您必须在RequestHandler的实现中为每个请求设置MDC中的值。我不认为Vaadin在请求结束时有一个回调界面,因此似乎没有理由清除该值。

UPDATE:在这个答案被接受之后,我发现实际上有更好的方法来设置和清除值,这样如果服务器为不同的会话回收线程,它就不会#39 ; t包含虚假信息。您应该做的是子类VaadinServletVaadinPortlet并覆盖createServletService()以返回VaadinServletServiceVaadinPortletService的自定义子类,而后者又会覆盖requestStart() }和requestEnd()分别设置和删除MDC中的值。