Запретить ведение журнала трассировки стека для настраиваемого исключения в 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);
}

Я не уверен, что это лучший подход, но теперь у меня есть настраиваемая регистрация исключений только в одном месте и не нужно повторять оператор журнала для каждого исключения или видеть его трассировку стека или любое другое сообщение об ошибке в журналы.

Ответ 3

Если вам не нужна трассировка стека, вы можете подавить трассировку стека, переопределив fillInStackTrace в вашем классе исключения.

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

Когда вы вызываете e.printStackTrace(), трассировка стека не будет напечатана.

См. также этот пост в блоге.