如何解决使用 Logback MDC 记录 Spring Boot ErrorController 关于相关问题的回答
(更新:我的问题似乎与 this one 相同,但没有有效答案。)
我正在尝试登录 Spring Boot ErrorController
,但它的日志没有 MDC 值。
@Controller
@RequestMapping("/error")
@requiredArgsConstructor
@Slf4j
public class MyErrorController implements ErrorController {
private final ErrorAttributes errorAttributes;
@Override
public String getErrorPath() {
return null;
}
@RequestMapping
@ResponseBody
public Map<String,String> error(final HttpServletRequest request) {
final ServletWebRequest webRequest = new ServletWebRequest(request);
final Throwable th = errorAttributes.getError(webRequest);
if (th != null) {
// **Logged without "requestId" value**
log.error("MyErrorController",th);
}
return Map.of("result","error");
}
}
// http://logback.qos.ch/manual/mdc.html#autoMDC
public class MDCFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(final HttpServletRequest request,final HttpServletResponse response,final FilterChain filterChain)
throws servletexception,IOException {
final String requestId = UUID.randomUUID().toString();
MDC.put("requestId",requestId);
try {
filterChain.doFilter(request,response);
} finally {
MDC.remove("requestId");
}
}
}
@Configuration
public class MyConfig {
@Bean
public FilterRegistrationBean<MDCFilter> mdcFilter() {
final FilterRegistrationBean<MDCFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new MDCFilter());
bean.addUrlPatterns("/*");
bean.setorder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
logback-spring.xml
:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] requestId:%X{requestId} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
result(requestId
值没有出现):
18:15:13.705 [http-nio-8080-exec-1] requestId: ERROR c.e.l.MyErrorController - MyErrorController
java.lang.RuntimeException: Error occured.
...
我认为我需要在MDCFilter
之前适应dispatcherServlet
,但我不知道该怎么做。
解决方法
一切都按预期进行。
这是记录的行:
08:19:34.204 [http-nio-8080-exec-2] MY_MDC_VALUE DEBUG o.s.web.servlet.DispatcherServlet - Failed to complete request: java.lang.RuntimeException: Error occured.
您发布的是来自 MyErroController 的日志
08:19:34.209 [http-nio-8080-exec-2] ERROR c.e.l.MyErrorController - MyErrorController
当你打电话时
MDC.clear();
执行此日志语句时,MDC 为空。
,删除 ServletRequestListener#requestDestroyed()
上的 MDC 数据,而不是 Filter
上的数据。
在 Tomcat 上 StandardHostValve 在 RequestDestroyEvent
执行后触发 ErrorController
。
// Look for (and render if found) an application level error page
if (response.isErrorReportRequired()) {
// If an error has occurred that prevents further I/O,don't waste time
// producing an error report that will never be read
AtomicBoolean result = new AtomicBoolean(false);
response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED,result);
if (result.get()) {
if (t != null) {
throwable(request,response,t); // *ErrorController is executed*
} else {
status(request,response);
}
}
}
if (!request.isAsync() && !asyncAtStart) {
context.fireRequestDestroyEvent(request.getRequest()); // *RequestDestroyEvent is fired*
}
因此,请执行以下操作:
public class MDCClearListener implements ServletRequestListener {
@Override
public void requestDestroyed(final ServletRequestEvent sre) {
MDC.remove("requestId");
}
}
@Bean
public ServletListenerRegistrationBean<MDCClearListener> mdcClearListener() {
final ServletListenerRegistrationBean<MDCClearListener> bean = new ServletListenerRegistrationBean<>();
bean.setListener(new MDCClearListener());
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
(具体代码存在于 solution
branch。)
关于相关问题的回答
This answer 不适合我。因为:
第一种方式不使用ErrorController
而是使用@ExceptionHandler
,因此无法捕获Spring Security Filter
抛出的异常。
(尝试 answer/exceptionhandler-with-springsecurity
branch 代码。)
第二种方式将 UUID 放在拦截器上,因此记录了 MyController
和 MyErrorController
之间的不同 requestId。这不是“请求”ID。
(尝试 answer/interceptor
branch 代码。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。