我最近发现了在记录时使用MDCs的神奇之处。它运作得很好。
我有以下方法:
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());
}
这被称为每个jsp中的第一个动作。这使我能够很好地跟踪日志中会话的详细信息。
然而 - 我怎么知道何时remove
这些地图条目?我应该注意哪些事件才能让我整理地图?
我在Tomcat下托管。如果它重新使用线程,那么我不会泄漏内存,因为它们本质上是线程本地的,因此每个put
将覆盖上次使用线程时的旧put
。如果它没有 - 或者我托管在其他东西之外 - 我实际上可能永远地增长地图 - 或者至少在主机重新启动之前。
我认为我的问题的实质是 - 是否有一个我可以检测到的事件,表明特定的会话或线程已经完成并即将被释放。
答案 0 :(得分:5)
不是将调用放在每个JSP中,而是注册ServletRequestListener,它会在请求开始时和结束时得到通知:
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());
}
}
或者你可以使用一个过滤器,它可以包含通常的请求处理流程:
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
setupMDC();
chain.doFilter(request, response);
tearDownMDC();
}
无论哪种方式,您只需在web.xml
中注册相关的类,容器应该处理其余的。