Search code examples
springspring-bootservletsservlet-filtersspring-restcontroller

OncePerRequestFilter - handling exceptions annotated with @ResponseStatus


I'm looking for a way to log all my requests and responses in the database (1 record = 1 request + 1 response). My use case in details:

  1. Log record in database with request URL, params, IP, start date etc.
  2. Update database record (when request finish) and save response, exceptions, end date etc.

I'm trying to do with custom OncePerRequestFilter and it work's almost OK. But I have problem with handling exceptions annotated with annotation @ResponseStatus. This kind of exceptions (thrown in controllers) I can't catch in my custom doFilter method. Do you know any way to capture these exceptions in filter? Unless I should do this in some other way?

AuditFilter:

@Component
public class AuditFilter extends OncePerRequestFilter {

    private Logger logger = Logger.getLogger(AuditFilter.class.getName());
    private RequestAuditRepository repository;


    AuditFilter(RequestAuditRepository repository) {
        this.repository = repository;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
    }

    private void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain)
            throws ServletException, IOException {

        RequestAuditLog requestAuditLog = new RequestAuditLog();
        String catchedExceptionMsg = null;
        try {
            beforeRequest(requestAuditLog, request); 
            filterChain.doFilter(request, response);
        }
        catch (Exception e) {
            // Not called when exception with @ResponStatus annotation throwed
            catchedExceptionMsg = e.getMessage();
            throw e;
        }
        finally {
            afterRequest(requestAuditLog, catchedExceptionMsg, request, response);
            response.copyBodyToResponse();
        }
    }

    ...

}

BadRequestException:

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
    public BadRequestException(String message) {
        super(message);
    }
}

Solution

  • I think the BadRequestException is handled even before your custom filter gets triggered and therefore you can't catch this exception in your filter.

    What you could do is that you write your own ExceptionHandler additionally to your filter and log your stuff there.

    @ControllerAdvice
    public class MyExceptionHandler {
    
      @ExceptionHandler(BadRequestException.class)
      public void handleError(BadRequestException ex) {
         // do your stuff here
      }
    
    }