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.
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.