在 Spring 引导应用程序中防止自定义异常的堆栈跟踪日志记录

Prevent stack trace logging for custom exception in Spring Boot application

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

详细解释:

我正在使用 spring 启动来创建一个简单的休息服务。 我喜欢自定义异常,默认情况下日志中没有堆栈跟踪并且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 ...");
}

有更多异常会导致在每次抛出之前放置日志语句,我认为这是一种糟糕的方法。我已经尝试从服务方法中删除所有日志语句并创建 @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;
    }
}

现在的问题是,我不仅看到了日志条目,还看到了自定义异常的堆栈跟踪,但找不到如何防止这种情况发生的方法。 我认为问题是再次抛出引起的。一个可能的解决方案是为异常创建一个自定义 class,我将 return 代替,但我不喜欢这个想法,因为异常编组似乎工作正常。

有什么提示吗?谢谢

如果您不需要堆栈跟踪,您可以通过覆盖异常中的 fillInStackTrace 来抑制堆栈跟踪 class。

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

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

另见 this blog post

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

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

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

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

server.error.include-stacktrace=从不

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

警惕 Spring Boot DevTools。

尽管 NEVERserver.error.include-stacktrace 的默认设置,但如果您包含 Spring Boot DevTools,它会覆盖 ALWAYS

如果您对更多细节感兴趣,请参阅 this commit,它已成为 Spring Boot 2.1.0+ 的一部分

调用重载的超级构造函数以避免在响应中显示堆栈跟踪。

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

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

}

从异常中超级加载构造函数Class

 protected Exception(String message, Throwable cause,
                        boolean enableSuppression,
                        boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
    
}