I want to give Logback MDC information to Spring Boot ErrorController logs

Asked 2 years ago, Updated 2 years ago, 87 views

(Multipost with Stack Overflow)

We would like to give you a unique value for Spring Boot log output on a per-request basis.
For this purpose, we implemented the Logback MDC with reference to Example 7.5 in as described below.

In this implementation, the normal controller of Spring MVC will log the desired information (requestId value in this implementation), but the ErrorController class output.

I understand why ErrorController only takes action after MDCFilter is done (because MDC.remove() is done), but I don't know how to implement it.

(MDCFilter should be applied before DispatcherServlet, but I didn't know how to do that.)

logback-spring.xml:

Run Results ("requestId:" followed by UUID, but not):

(Full code is here)

I found similar questions (but didn't seem to get a clear answer):

spring-boot tomcat logging

2022-09-30 17:13

2 Answers

I think one of the countermeasures is to leave it alone without remove.

It's certainly not very well behaved to keep information that's no longer valid, but in fact, the thread that processed this user request will be reused in the near future to process another user request.
It will be overwritten with valid information at that time, so it is unlikely that any actual damage will occur.

I was asked if I had to clear the MDC every time I requested it.It may be helpful for your consideration:


2022-09-30 17:13

We followed up and found that the ErrorController was running from Tomcat's StandardHostValve#invoke().
Called by throwable(request, response, t); in the following quote:

final class StandardHostValve extensionsValveBase{
...
    @ Override
    public final void invoke (Request request, Response response)
        US>throws IOException, ServletException{
...
            // Look for (and render if found) an application level error page
            if(response.isErrorReportRequired()){
                // If an error has occurred that events 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); // **This is where ErrorController is called**
                    } else{
                        status(request, response);
                    }
                }
            }

            if(!request.isAsync()&&!asyncAtStart){
                context.fireRequestDestroyEvent(request.getRequest());
            }
...
    }
...
}

After that, you can see that context.fireRequestDestroyEvent(request.getRequest()); is called.
I think I should just pick up this event and clear the MDC.

To receive this event, implement and register ServletRequestListener:

public class MDCClearListener implements ServletRequestListener{

    @ Override
    public void requestDestroyed(final ServletRequestEventsre) {
        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;
    }

After performing the above implementation, we were able to get the desired result ("requestId:" followed by the UUID):

 22:09:19.294 [http-nio-8080-exec-1] requestId: 82debc7b-5834-49d1-aba7-738c8b50d581 ERROR c.e.l.MyErrorController-MyErrorController
java.lang.RuntimeException: Error occurred.
...

(The full code can be found in the solution branch in the same repository.)

I would like to evaluate this as a similar question with new answers.
In conclusion, I don't think it's a very appropriate method.

The first method is to handle errors by @ExceptionHandler instead of ErrorController.
This is available for error handling of Spring MVC; otherwise, for example, Spring Security cannot be handled.
You can try behavior with the answer/exceptionhandler-with-springsecurity branch.

Also, there are people who explain the mechanism of error handling around here:

The second method is to use an interceptor.
This method overrides the MDC each Controller call.In other words, the ID printed by MyErrorController is no longer the "Request ID" (even if the request is the same, a different UUID will be dumped).

You can try with answer/interceptor branch.


2022-09-30 17:13

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.