How to log validation errors in Spring boot application
Asked Answered
A

3

6

I'm using SpringBoot (spring-boot-starter-web 1.5.16.RELEASE) and hibernate-validator 6.0.11.Final in my REST service.

DTO objects annotated with proper validation constrains (UPDATE: I'm using @Valid annotation on controller's parameter) and validation works as expected.

I'd like to have all validation errors (that were send to the clients) logged in log files.

I assume there should be some simple way to enable that kind of messages (e.g. flag in app properties) but I can't find it anywhere.

Any suggestions would be appreciated.

Anticathexis answered 16/10, 2018 at 17:12 Comment(0)
A
6

It turned out that org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver does log the validation errors by default (and that is what I exactly need), e.g.

2018-10-18 12:54:25.552  WARN 22760 --- [nio-8092-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for 

The reason why I haven't seen these messages was in log aggregation tool filters (i.e. I haven't seen messages in Kibana but they appear on local machine).

For those who will not see messages locally - check the logging configuration and ensure that Spring logs are not muted there.

Anticathexis answered 18/10, 2018 at 10:10 Comment(1)
to complete: logging.level.org.springframework.web.servlet.mvc=DEBUGTompkins
A
4

Update: In that case you can use BindingResult object defined after @Valid bean declration in controller method, like

@RequestMapping(value = "/foo")
public String foo(@Valid POJO object, BindingResult result) {
   List<FieldError> errors = result.getFieldErrors();
   for (FieldError error : errors ) {
     log.error(error.getDefaultMessage());
   } 
}

OR you better off using @ExceptionHandler for exception type MethodArgumentNotValidException


old answer: If you are validating beans like

Set<ConstraintViolation<POJO>> violations = validator.validate(pojo);

then you can iterate over violations and log them, like

for (ConstraintViolation<POJO> violation : violations) {
   log.error(violation.getMessage()); 
}

Copied from: https://www.baeldung.com/javax-validation

Antemundane answered 16/10, 2018 at 17:38 Comment(1)
I'm using @Valid annotation in my controllerAnticathexis
D
3

You have to define Global Exception handler using @ControllerAdvice to catch all the JSR 303 related errors. Even you define exception handlers for your own business exception here and log them as needed.

 @ControllerAdvice
    class ApiException{
     @ExceptionHandler(MethodArgumentNotValidException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ResponseBody
        public ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {
            BindingResult result = ex.getBindingResult();
            List<FieldError> fieldErrors = result.getFieldErrors();

          //log errors here

            return processFieldErrors(fieldErrors);
        }

      private ValidationErrorDTO processFieldErrors(List<FieldError> fieldErrors) {
            ValidationErrorDTO dto = new ValidationErrorDTO();

            for (FieldError fieldError: fieldErrors) {
                String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);
                dto.addFieldError(fieldError.getField(), localizedErrorMessage);
            }

            return dto;
        }

    }

    public class ValidationErrorDTO {

        private List<FieldErrorDTO> fieldErrors = new ArrayList<>();

        public ValidationErrorDTO() {

        }

        public void addFieldError(String path, String message) {
            FieldErrorDTO error = new FieldErrorDTO(path, message);
            fieldErrors.add(error);
        }

    }
Dvorak answered 16/10, 2018 at 17:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.