Question

I recently discovered the magic of using MDCs when logging. It works perfectly.

I have the following method:

public static final String MDC_CLIENT="client";
public static final String MDC_SESSION="session";
public static final String MDC_DEVICE="device";

// Called for every request.
public static void request(final HttpServletRequest request) {
  // The MDC is a thread-local storage accessable from the log formatter.
  MDC.put(MDC_CLIENT, String.format("%s:%s", request.getRemoteHost(), request.getRemotePort()));
  HttpSession session = request.getSession();
  MDC.put(MDC_SESSION, session.getId());
  MDC.put(MDC_DEVICE, (String)session.getAttribute("device"));
  // Also record the context.
  setContext(session.getServletContext());
}

This is called as the first action in every jsp. This allows me to keep track of the details of the session in the log nicely.

However - how do I know when to remove these map entries? What event should I watch for that will allow me to tidy up the map?

I am hosting under Tomcat. If it re-uses threads then I won't leak memory because these are essentially thread-local so each put will overwrite the old put from the last time the thread was used. If it doesn't - or I am hosted under something else that doesn't - I am essentially growing the map potentially forever - or at least until the host is restarted.

I think the essence of my question is - is there an event I can detect that indicates that a particular session or thread is finished with and about to be released.

Was it helpful?

Solution

Rather than putting the call in every JSP I would register a ServletRequestListener, which gets notified both when the request starts and when it finishes:

public class MDCListener implements ServletRequestListener {
  public void requestInitialized(ServletRequestEvent e) {
    YourUtilityClass.request((HttpServletRequest)e.getServletRequest());
  }

  public void requestDestroyed(ServletRequestEvent e) {
    YourUtilityClass.tearDown((HttpServletRequest)e.getServletRequest());
  }
}

Alternatively you could use a filter which lets you wrap around the usual request processing flow:

void doFilter(ServletRequest request, ServletResponse response,
              FilterChain chain) throws IOException, ServletException {
  setupMDC();
  chain.doFilter(request, response);
  tearDownMDC();
}

Either way you simply register the relevant classes in web.xml and the container should take care of the rest.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top