Prevent stack trace logging for custom exception in Spring Boot application

38,465

Solution 1

Solution was to leave the exception handling to spring boot, so that custom exception is not logged and any other is logged by default. I removed the @ControllerAdvice and also the logging statements from the rest controller and added logging statement to custom exception constructor.

public DuplicateFoundException(String message) {
    super(message);
    LOGGER.warn(message);
}

I am not sure if this is the best approach, but now I have custom exception logging only at one place and don't have to repeat the log statement for every exception or see its stack trace or any other error message in the logs.

Solution 2

I'm using Spring Boot 2+ just add this line to your application.properties:

server.error.include-stacktrace=never

https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/web/ErrorProperties.IncludeStacktrace.html

Solution 3

Be wary of Spring Boot DevTools.

Despite NEVER being the default for server.error.include-stacktrace, if you include Spring Boot DevTools it overides to ALWAYS.

If you're interested in more detail, see this commit, which became part of Spring Boot 2.1.0+ enter image description here

Solution 4

If you don't need the stack trace you can suppress the stack trace by overriding fillInStackTrace in your exception class.

public class DuplicateFoundException extends RuntimeException {
    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }
}

When you invoke e.printStackTrace() then no stack trace will be printed.

See also this blog post.

Solution 5

Call overloaded super constructor to avoid showing the stacktrace in response.

public class ProductCustomException extends Exception{
    
    private static final long serialVersionUID = -291211739734090347L;

    public ProductCustomException(String message) {
        super(message,null,false,false);
    }

}

Super loaded Constructor from Exception Class

 protected Exception(String message, Throwable cause,
                        boolean enableSuppression,
                        boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
    
}
Share:
38,465
rhorvath
Author by

rhorvath

Updated on May 22, 2021

Comments

  • rhorvath
    rhorvath almost 3 years

    Is there a way in Spring Boot (mvc) to log a custom exception and throw it without its stack trace being visible in the log file? But for any other exception still see the stack trace.

    Long explanation:

    I am using spring boot to create a simple rest service. I like that for a custom exceptions there is no stack trace in the logs by default and json response is created with the basic exception details (status, error, message).

    The problem is that it also creates no log entry at all, therefore I would have to do this manually:

    Custom Exception

    @ResponseStatus(value = HttpStatus.CONFLICT)
    public class DuplicateFoundException extends RuntimeException {
        public DuplicateFoundException(String message) {
            super(message);
        }
    }
    

    Exception throwing in service method (in @RestController)

    if (!voteDao.findByItemAndUser(item, voteDto.getUserId()).isEmpty()) {
        log.warn("... already voted ...");   //TODO: don't do this for every throw
        throw new DuplicateFoundException("... already voted ...");
    }
    

    Having more exceptions leads to placing log statement before each throw, which is a bad approach I think. I've tried removing all the log statements from the service method and created @ControlledAdvice where I would log all the custom exceptions and just re-throw them so I still get the nice json as before:

    @ControllerAdvice
    public class RestExceptionHandler {
        private static final Logger log = Logger.getLogger(RestExceptionHandler.class);
    
        @ExceptionHandler
        public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
            if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
                log.warn(e.getMessage());
            } else {
                log.error("...");
            }
            throw e;
        }
    }
    

    Now the problem is that I see not just the log entry but also the stack trace for custom exceptions and can't find a way how to prevent this. I think the problem is caused by throwing it again. A possible solution could be to create a custom class for exception which I will return instead, but I dislike the idea since exception marshalling seems to work fine.

    Any hints? Thanks.

  • rhorvath
    rhorvath almost 9 years
    thanks, stack trace is gone but I still see "2015-07-07 11:47:57.188 ERROR 41456 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Failed to invoke @ExceptionHandler method: public org.springframework.web.servlet.ModelAndView". Is there a way to get rid of this as well so I don't see any error in log for custom exception ? I accepted the answer because the stack trace was gone, but now i see that my exception message is twice in the logs (1. log statement and 2. exception message from the failed method)
  • Roland Weisleder
    Roland Weisleder almost 9 years
    I think there is no easy way to do this. Maybe you should consider not using exceptions (i.e. a custom status code) as this case is not exceptional but expectable. stackoverflow.com/questions/3213094
  • rhorvath
    rhorvath almost 9 years
    my use case is basically the same as the example from official spring doc (spring.io/blog/2013/11/01/exception-handling-in-spring-mvc)‌​, therefore I would not call it expectable. Otherwise we could argue the point of the validationException as well. Creating a custom return object is possible as I also described in the question, but I was trying to find simpler and cleaner solution if possible.
  • Ashu Phaugat
    Ashu Phaugat over 5 years
    @RolandWeisleder Thanks for your answer, it really helped me.
  • shark1608
    shark1608 about 5 years
    As of 1.3.0, 'Never' is by default. Check the release notes
  • Robber
    Robber almost 5 years
    @shark1608 While it's true that the release notes say that, using Spring Boot 2.1.7 it was set to 'Always' by default
  • muttonUp
    muttonUp over 4 years
    @Robber See my answer below, which may explain why it is getting set to ALWAYS
  • BitfulByte
    BitfulByte over 4 years
    Thanks, appreciate the thoroughness. Always like to understand the 'why' part of a situation. Yet another case of unaware of the 'spring-boot magic'.
  • delitescere
    delitescere almost 4 years
    If you update application.yml (or application.properties) to specify NEVER Spring Boot DevTools will respect it (at least in 2.3)
  • hello_earth
    hello_earth about 3 years
    um, check that you are not overriding DefaultErrorAttributes too and not calling getErrorAttributes with hardcoded includeStackTrace parameter - as I was doing, duh!