Sunday, December 26, 2021

Sentry in Spring Boot application reports uncaught exception while @RestControllerAdvice is handling exception

Introduction

Even when you have a @RestControllerAdvice configured and you know it gets invoked, it can be that Sentry.io's monitoring library still reports it as an (uncaught) exception. Reason for this is that when you configure Sentry as specified without setting its order in the exception-handler-resolver chain, it's by default set as lowest, so invoked as first in the chain. 

Solution

Thus to fix this, set it to a higher order number. Safest seems to set it to Integer.MAX_VALUE, that way it will always be invoked as the latest.

The most recent Sentry integration examples can be found here for Spring and here for Spring Boot. Maybe you want to consider logging via Logback or Log4J too, see the related Sentry integration examples on the same page.

Another solution is overriding the getOrder() method for older Sentry versions. Below is an example, using the suggesting configuration from this old obsolete Sentry page.

@Configuration
@Slf4j
public class SentryConfig {
    @Bean
    public HandlerExceptionResolver sentryExceptionResolver() {

        return new SentryExceptionResolver() {
            @Override
            public ModelAndView resolveException(HttpServletRequest request,
                    HttpServletResponse response,
                    Object handler,
                    Exception ex) {
                log.info("Sentry resolving this exception: ", ex);
                // You could skip exceptions that are considered client-side errors and return null in that case so it is considered taken care of.
                return super.resolveException(request, response, handler, ex);
            }

            @Override
            public int getOrder() {
                // Ensure other resolver(s) can run first, otherwise this handler is invoked as first and thus reporting an issue for Sentry
                return Integer.MAX_VALUE;
            }
        };
    }
    @Bean
    public ServletContextInitializer sentryServletContextInitializer() {
        return new io.sentry.spring.SentryServletContextInitializer();
    }
}


Similar solutions mentioned here: https://stackoverflow.com/questions/48401974/how-to-have-my-own-error-handlers-before-sentry-in-a-spring-application