Short Version (With Enough Details)
How to preserve the MDC attribute added in a doFilter()
method of a javax.servlet.Filter
implementation ...
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
MDC.put("token", MyToken.random()); // add the MDC attribute related to the current request processing
chain.doFilter(request, response); // send the request to other filters and the Controller
} finally {
MDC.clear(); // MDC attribute must be removed so future tasks executed on the same thread would not log invalid information
}
}
... during exception handling if an exception occurs in another filter or in the Controller (the call to chain.doFilter(...)
).
Currently, if an exception occurs: the finally block would be executed, clearing the MDC, and then the exception would be thrown out of the filter. All the logs during the exception handling will not contain the MDC attribute.
Long Version (Overly Detailed)
I have a simple Filter
implementation to intercept all requests. It only creates a random string of characters (a token) to be included in all logs related to processing the request.
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
MDC.put("token", MyToken.random());
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
@Override
public void destroy() {
}
}
The sequence of events would be:
- The request is received.
- My
doFilter()
is called, adding the random token to MDC. - The request is processed by calling
chain.doFilter()
. - Whatever happens (processing finished, error occurred), the MDC is cleared of the random token in the
finally
block.
The problem is that if an error occurs and it is processed (e.g. by a custom ErrorController
implementation), the related logs do not include the token:
[2019.03.13 15:00:14.535] token:308...8bf [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : GET "/resource", parameters={}
[2019.03.13 15:00:14.551] token:308...8bf [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : Completed 400 BAD_REQUEST
[2019.03.13 15:00:14.551] token: [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
[2019.03.13 15:00:14.551] token: [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity myproj.CustomErrorController.handleError(javax.servlet.http.HttpServletRequest)
[2019.03.13 15:00:14.551] token: [ERROR] 8124 [https-jsse-nio-8443-exec-7] m.CustomErrorController : HTTP Error: Bad Request (400)
[2019.03.13 15:00:14.551] token: [DEBUG] 8124 [https-jsse-nio-8443-exec-7] o.s.w.s.DispatcherServlet : Exiting from "ERROR" dispatch, status 400
The finally
block is executed when the exception is thrown from the Controller
which handles it, resulting in clearing the MDC.
Error handling (including the custom ErrorController
) is executed after this, which means there is no more token in the related logs.
How can I add a custom token to all the logs related to the entire processing of the request from receiving it until sending a response, including error handling? I want the MDC to be cleared after a response has been sent by the thread, as the last action. The MDC should be cleared regardless of what happens (successful response, exception thrown during error handling, etc).
With multiple clients using the Rest service simultaneously, logs can get really messed up. Having a unique token attached to each log produced during the entire handling process of a certain request would greatly simplify debugging.