Spring Boot Controller Validation Metrics

186 views Asked by At

I'm utilizing Spring Boot 3 with starter validation / Jakarta Validation via the Controller methods, and @Valid and @Validated annotations, and am using actuator for metrics.

There is a lot of "Spring Magic" for free metrics with a lot of these spring boot libraries.

I was wondering, is there a metric available by default in spring boot 3 / spring boot starter validation, where I can see a metric for number of requests rejected (400 error) due to json serialization or validation error?

Basically I need a metric for # of 400 errors that occurred, where the request never entered the Controller due to a validation error or a serialization error. This is different from the request entering the controller, and then manually returning a 400 due to domain-level validation errors.

What I've tried:

  • Starting the app and looking for validation metrics specifically via localhost:8080/metrics. (don't see any)
  • Checking actuator documentation

If this isn't available by default, can I add a hook to the code for API level validation failures so that I can increment my own metric?

Thanks for any help finding existing/free spring boot metrics, or how to add one for this use case.

1

There are 1 answers

0
Toni On

As far as I know, no such metric is available by default, but you can register your own as shown below:

@Component
public class FailedRequestsCounter {
  private final Counter counter;

  public FailedRequestsCounter(MeterRegistry registry) {
    counter = Counter.builder("failed_requests.count")
        .description("Number of requests failed due to json serialization or validation error.")
        .register(registry);
  }

  public void increment(){
    counter.increment();
  }
}

Then use the FailedRequestsCounter component to increment the counter wherever you handle exceptions caused by validation and serialization errors. Ideally, you would have a @ControllerAdvice that handles exceptions globally, for example:

@ControllerAdvice
public class GlobalExceptionHandler {
  @Autowired
  private FailedRequestsCounter failedRequestsCounter;

  // Validation errors - RequestParam
  @ExceptionHandler(ConstraintViolationException.class)
  ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
    failedRequestsCounter.increment();
    return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
  }

  // Validation errors - RequestBody and PathVariable
  @ExceptionHandler(MethodArgumentNotValidException.class)
  ResponseEntity<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
    failedRequestsCounter.increment();
    return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
  }

  // Serialization errors
  @ExceptionHandler(HttpMessageNotReadableException.class)
  ResponseEntity<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
    failedRequestsCounter.increment();
    return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
  }
}