为Spring Boot应用程序中的自定义异常阻止堆栈跟踪日志记录

问题描述 投票:15回答:4

Spring Boot(mvc)中是否有一种方法记录一个自定义异常并抛出它,而其堆栈跟踪在日志中不可见文件?但是对于其他任何异常,仍然请参见堆栈跟踪。

详细说明:

我正在使用Spring Boot来创建简单的Rest服务。 我喜欢自定义异常,默认情况下日志中没有堆栈跟踪,并且使用基本异常详细信息(状态,错误,消息)创建了json响应。

问题是,它也不会创建日志条目,因此我将必须手动执行此操作:

自定义例外

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

在服务方法中抛出异常(在@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 ...");
}

具有更多异常会导致在每次抛出之前放置log语句,我认为这是一种不好的方法。我尝试从服务方法中删除所有日志语句,并创建了@ ControlledAdvice,我将在其中记录所有自定义异常,然后重新抛出它们,所以我仍然像以前一样得到漂亮的json:

@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;
    }
}

现在的问题是,我不仅看到日志条目,还看到自定义异常的堆栈跟踪,并且找不到一种方法来防止这种情况。我认为问题是由再次抛出引起的。一个可能的解决方案是为异常创建一个自定义类,我将返回该类,但是我不喜欢这种想法,因为异常编组似乎可以正常工作。

有任何提示吗?谢谢。

java spring logging exception-handling spring-boot
4个回答
13
投票

我正在使用Spring Boot 2+只需将此行添加到您的application.properties:

server.error.include-堆栈跟踪=从不

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


9
投票

如果不需要堆栈跟踪,则可以通过在异常类中重写fillInStackTrace来抑制堆栈跟踪。

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

当调用e.printStackTrace()时,将不会打印堆栈跟踪。

另请参见this blog post


1
投票

解决方案是将异常处理留给spring boot,这样默认情况下不会记录自定义异常,而会记录其他任何异常。我从其余控制器中删除了@ControllerAdvice以及日志记录语句,并向自定义异常构造函数中添加了日志记录语句

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

我不确定这是否是最好的方法,但是现在我仅在一个地方进行了自定义异常日志记录,因此不必为每个异常重复log语句,也不必在日志中查看其堆栈跟踪或任何其他错误消息。


0
投票

警惕Spring Boot DevTools。

尽管NEVER是默认值,但如果包含Spring Boot DevTools,它会覆盖ALWAYS

请参阅此提交,它已成为2.1.0+的一部分

https://github.com/spring-projects/spring-boot/commit/cb621024e480fb08a79277273f81aa169aed14df

© www.soinside.com 2019 - 2024. All rights reserved.