Fix Controller Level Exceptions Not Being Recorded in Spring Boot 3 HTTP Server Requests Metrics

How to Fix Controller Level Exceptions Not Being Recorded in Spring Boot 3 HTTP Server Requests Metrics

Is your Spring Boot 3 application experiencing issues with controller-level exceptions not appearing in HTTP server requests metrics? Follow this guide to troubleshoot and fix the problem.

Background

While studying how to migrate Spring Boot 2.x apps to Spring Boot 3.x, we discovered that controller level exceptions collected using ExceptionHandler were not being logged in the Spring Boot actuator HTTP Server Requests metrics. We brought this up with the Spring team, and they recommended one change after which exceptions began to surface in the metrics.

GitHub Issue: click here

Note:

This issue was only observed in case of Spring Boot 3.x. In case of Spring Boot 2.x. the exceptions are properly getting recorded in HTTP server requests metrics. The fix mentioned in this blog is only required in case of Spring Boot 3.x.


Understanding Issue with Example

Now, we will try to understand this issue with the help of one example.

We have created a very simple app with one controller which will throw an exception and this exception will be handled by ExceptionHandler. Also, there are two other classes for custom exception and response POJO.

import com.example.helloworld.exception.CustomException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

    @GetMapping("/hello")
    public ResponseEntity<String> sendGreetings() throws CustomException {
        throw new CustomException(500, "Something went wrong while processing a request");
       // return ResponseEntity.ok("Hello User!");
    }
}
HelloWorldController.java

HelloWorldController class is throwing a customized exception containing error code and error message.

public class CustomException extends Exception {

    private int errorCode;
    private String errorMessage;
    
    // Constructors, Getters and Setters
}  
CustomException .java

CustomException class is useful for customizing the exception as per the requirement of user.

import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.filter.ServerHttpObservationFilter;

@ControllerAdvice
public class CustomExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<ErrorResponse> handleException(HttpServletRequest request, CustomException ex) {
        // Log the exception
        logger.error("An error occurred: {}", ex.getMessage());

        // Return an error response to the client
        ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode(), ex.getErrorMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
CustomExceptionHandler.java

handleException method is logging the exception and sending back the customized response to the user.

public class ErrorResponse {

    private int errorCode;
    private String errorMessage;
    
     // Constructors, Getters and Setters
}
ErrorResponse.java

ErrorResponse class is useful for sending customized error response back to the user.

Output

Now, when http.server.requests actuator metrics endpoint will be called, in that case, values for exception tag will not appear even though the custom exception will be thrown but it will not be recorded in the metrics.



Solution

Fix for above problem is very simple. All we have to do is set the exception object as an error inside the observation context. When CustomException will be thrown during the processing of the current request, it will be recorded as an error in the HTTP server requests metrics.

import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.filter.ServerHttpObservationFilter;

@ControllerAdvice
public class CustomExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<ErrorResponse> handleException(HttpServletRequest request, CustomException ex) {
        // Log the exception
        logger.error("An error occurred: {}", ex.getMessage());

        ServerHttpObservationFilter.findObservationContext(request)
                .ifPresent(context -> context.setError(ex));

        // Return an error response to the client
        ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode(), ex.getErrorMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
CustomExceptionHandler.java

The code at line 20 and line 21 is ensuring that the controller-level exceptions are properly captured and recorded in the HTTP server requests metrics by the Spring Boot Actuator framework.

If case of multiple error handler methods, we need to add this code inside each and every error handler method.

Output

Now, when http.server.requests actuator metrics endpoint will be called, in that case, values for exception tag will be populated correctly.

Conclusion

To summarize, the blog post provides a step-by-step guide for developers to fix the issue of controller-level exceptions not being captured in the HTTP server requests metrics in Spring Boot 3 applications. By following the instructions provided in the article, developers can improve their application’s performance and error handling, and gain greater insight into the behavior of their application. This will be very useful while creating dashboards, charts and tables highlighting the different exceptions that were encountered while processing the requests.



Add a Comment

Your email address will not be published.