使用ServletRequestListener或Filter在Log4j MDC中设置requestIds?

时间:2016-10-14 19:31:42

标签: java java-ee log4j servlet-listeners

我正在尝试使用ServletRequestListener将RequestId注入Log4j MDC。为了避免内存泄漏,我正在requestDestroyed()方法中清除我的MDC添加内容。

我使用的是JBoss 4.2.1GA。

但是,我在一个非常具体的用例中遇到了一个特殊问题,其中一个Struts Action正在重定向一个动作。我可以看到调用了requestDestroyed()方法,但重定向的操作没有调用requestInitialized()方法。

public class Log4jMDCRequestListener implements ServletRequestListener {

    /**
     * Need to clear the MDC parameters at the end of the request as the thread can be reused by another request
     */
    @Override
    public void requestDestroyed(ServletRequestEvent paramServletRequestEvent) {
        MDCUtils.clear();
    }

    /**
     * Inject the necessary trackers into the MDC to use in the log4j loggers
     */
    @Override
    public void requestInitialized(ServletRequestEvent paramServletRequestEvent) {

        HttpServletRequest request = (HttpServletRequest) paramServletRequestEvent.getServletRequest();

        // generate a random requestId to correlate all logs from the same request
        String requestId = UUID.randomUUID().toString();
        MDCUtils.setRequestId(requestId);

        MDCUtils.setIP(WebUtil.getRealIP(request));

        HttpSession session = request.getSession(false);
        if (session != null) {
            MDCUtils.setSessionid(session.getId());
        }
    }
}

在我的web.xml中:

   <listener>
      <listener-class>webapp.listener.Log4jMDCRequestListener</listener-class>
   </listener>

使用fiddler我可以看到我的浏览器在调用requestDestoryed()方法后向我的应用程序发出新请求,但未触发requestInitialized()方法。如果我查看正在使用的各个请求对象的对象id,我可以看到它是相同的请求ID。

在没有触发requestInitialized方法的情况下,容器是否可以重用请求对象?有什么方法可以进一步调试吗?

我的问题是第二个请求以清除的MDC结束(在调用requestDestroyed之后)并且从不重新初始化。

我试图使用Filter而不是Listener,我看到了相同的行为。经过进一步分析,我想我已经注意到这个问题是容器调用登录页面而不是请求本身。

例如,在我的web.xml中:

  <login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
         <form-login-page>/login.do</form-login-page>
         <form-error-page>/login.do?error=true</form-error-page>
      </form-login-config>
   </login-config>

如果我在登录前尝试访问任何安全页面,容器会将我重定向到login.do表单,并在此过程中将跳过筛选器和侦听器。 (在我的ActionCommandBase实现中设置一个断点并检查调用堆栈,我可以看到在执行链时没有调用过滤器/监听器。

有什么方法吗?

0 个答案:

没有答案