Запретить ведение журнала трассировки стека для настраиваемого исключения в Spring Прикладной загрузке
Есть ли способ в 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;
}
}
Теперь проблема заключается в том, что я вижу не только запись журнала, но и трассировку стека для пользовательских исключений и не может найти способ предотвращения этого.
Я думаю, что проблема вызвана тем, что она снова выбрасывает ее. Возможным решением может быть создание настраиваемого класса для исключения, которое я верну вместо этого, но мне не нравится идея, так как исключение marshalling похоже работает нормально.
Любые подсказки? Спасибо.
Ответы
Ответ 1
Решение было оставить обработку исключений в spring boot, так что пользовательское исключение не регистрируется и любое другое регистрируется по умолчанию. Я удалил @ControllerAdvice, а также операторы протоколирования из остального контроллера и добавленного оператора журнала для настраиваемого конструктора исключений.
public DuplicateFoundException(String message) {
super(message);
LOGGER.warn(message);
}
Я не уверен, что это лучший подход, но теперь у меня есть настраиваемая регистрация исключений только в одном месте и не нужно повторять оператор журнала для каждого исключения или видеть его трассировку стека или любое другое сообщение об ошибке в журналы.
Ответ 2
Я использую 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
Ответ 3
Если вам не нужна трассировка стека, вы можете подавить трассировку стека, переопределив fillInStackTrace
в вашем классе исключения.
public class DuplicateFoundException extends RuntimeException {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
Когда вы вызываете e.printStackTrace()
, трассировка стека не будет напечатана.
См. также этот пост в блоге.
Ответ 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