简短版本(有足够的细节)
如何保留添加在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() {
}
}
事件的顺序是:
- 请求已收到。
- My
doFilter()
被调用,将随机令牌添加到 MDC。
- 该请求是通过调用来处理的
chain.doFilter()
.
- 无论发生什么(处理完成、发生错误),MDC 中的随机令牌都会被清除。
finally
block.
问题是,如果发生错误并进行处理(例如通过自定义ErrorController
实现),相关日志不包含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
当异常抛出时块被执行Controller
它会处理它,从而清除 MDC。
错误处理(包括自定义ErrorController
) 之后执行,这意味着相关日志中不再有 token。
如何添加自定义令牌all相关的日志entire从接收请求到发送响应的请求处理过程,包括错误处理?我希望在线程发送响应后清除 MDC,作为最后一个操作。无论发生什么情况(成功响应、错误处理期间抛出异常等),都应该清除 MDC。
当多个客户端同时使用 Rest 服务时,日志可能会变得非常混乱。在某个请求的整个处理过程中生成的每个日志上附加一个唯一的令牌将大大简化调试。