Spring Boot(mvc)中有没有办法记录一个自定义异常并抛出它而不在日志文件中看到它的堆栈跟踪?但是对于任何其他异常仍然会看到堆栈跟踪。
冗长的解释:
我正在使用spring boot来创建一个简单的休息服务。 我喜欢自定义异常,默认情况下日志中没有堆栈跟踪,并且使用基本异常详细信息(状态,错误,消息)创建了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;
}
}
现在的问题是我不仅看到了日志条目,还看到了自定义异常的堆栈跟踪,并且找不到如何防止这种情况的方法。 我认为问题是再次抛出它引起的。一个可能的解决方案可能是创建一个异常的自定义类,我将返回,但我不喜欢这个想法,因为异常编组似乎工作正常。
任何提示?感谢。
答案 0 :(得分:9)
如果您不需要堆栈跟踪,则可以通过覆盖异常类中的fillInStackTrace
来抑制堆栈跟踪。
public class DuplicateFoundException extends RuntimeException {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
当您调用e.printStackTrace()
时,不会打印堆栈跟踪。
答案 1 :(得分:6)
我正在使用Spring Boot 2+ 只需将此行添加到您的application.properties:
server.error.include-stacktrace =从不
答案 2 :(得分:4)
警惕Spring Boot DevTools。
尽管NEVER
是server.error.include-stacktrace
的默认设置,但如果包含Spring Boot DevTools,它会覆盖ALWAYS
。
查看此提交,该提交成为2.1.0+的一部分
https://github.com/spring-projects/spring-boot/commit/cb621024e480fb08a79277273f81aa169aed14df
答案 3 :(得分:1)
解决方法是将异常处理保留为spring boot ,这样就不会记录自定义异常,并且默认情况下会记录任何其他异常。我删除了@ControllerAdvice以及来自其余控制器的日志记录语句和添加的日志记录语句到自定义异常构造函数。
public DuplicateFoundException(String message) {
super(message);
LOGGER.warn(message);
}
我不确定这是否是最佳方法,但现在我只在一个地方进行自定义异常日志记录,并且不必为每个异常重复日志语句或查看其堆栈跟踪或任何其他错误消息日志。
答案 4 :(得分:0)
调用重载的超级构造函数以避免在响应中显示堆栈跟踪。
public class ProductCustomException extends Exception{
private static final long serialVersionUID = -291211739734090347L;
public ProductCustomException(String message) {
super(message,null,false,false);
}
}
来自异常类的超加载构造函数
protected Exception(String message, Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}