Короткая версия (с достаточным количеством деталей)
Как сохранить атрибут MDC, добавленный в doFilter()
метод javax.servlet.Filter
реализации ...
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
}
}
... во время обработки исключения, если исключение возникает в другом фильтре или в контроллере (вызов chain.doFilter(...)
).
В настоящее время, если возникает исключение: будет выполнен блок finally, очищающий MDC, а затем исключение будет выброшено из фильтра. Все журналы во время обработки исключений не будут содержать атрибут MDC.
Длинная версия (слишком подробная)
У меня есть простая реализация Filter
для перехвата всех запросов. Он создает только случайную строку символов (токен) для включения во все журналы, связанные с обработкой запроса.
@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() {
}
}
Последовательность событий будет:
- Запрос получен.
- Мой
doFilter()
вызывается, добавляя случайный токен в MDC.
- Запрос обрабатывается по телефону
chain.doFilter()
.
- Что бы ни случилось (обработка завершена, произошла ошибка), MDC очищается от случайного токена в блоке
finally
.
Проблема заключается в том, что если ошибка возникает и обрабатывается (например, пользовательской реализацией ErrorController
), соответствующие журналы не включают токен:
[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
Блок finally
выполняется, когда выдается исключение из Controller
, который его обрабатывает, что приводит к очистке MDC.
После этого выполняется обработка ошибок (включая пользовательский ErrorController
), что означает, что в соответствующих журналах больше нет токена.
Как добавить пользовательский токен в все журналы, относящиеся к всей обработке запроса от его получения до отправки ответа, включая обработку ошибок? Я хочу, чтобы MDC очищался после того, как поток отправил ответ, как последнее действие. MDC следует очищать независимо от того, что происходит (успешный ответ, исключение, выданное во время обработки ошибок и т. Д.).
Если несколько клиентов одновременно используют службу Rest, журналы могут сильно испортиться. Присвоение уникального токена каждому журналу, созданному в течение всего процесса обработки определенного запроса, значительно упростит отладку.