6

我正在使用 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

这样,无论会话更改多少次,我都会在日志中获取当前会话。

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

4

1 回答 1

4

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

Vaadin 实际上确实有SessionInitListenerand SessionDestroyListener,但这也不是您想要的:MDC 是线程本地的,但并非同一会话中的所有请求都在同一线程中处理。因此,您必须在RequestHandler. 我不认为 Vaadin 有一个请求结束的回调接口,所以似乎没有清除值的好地方。

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

于 2015-02-23T16:21:40.187 回答