Enterprise Java

Spring Boot Centralize HTTP Logging Example

Effective logging is essential for debugging, monitoring, and maintaining applications. Let us delve into understanding how Spring Boot can centralize HTTP logging and how it helps track requests, responses, and exceptions effectively.

1. Introduction

Logging is a crucial part of any application. It helps developers track HTTP requests, responses, and exceptions to debug issues effectively. Proper logging ensures better maintainability and faster issue resolution.

  • Spring Boot Actuator: Provides built-in request logging and monitoring features.
  • Custom Filter: Implements a filter to log incoming requests and outgoing responses.
  • Global Exception Handler: Captures and logs exceptions across the application.

1.1 Best Practices for Effective Logging

  • Use appropriate log levels: TRACE, DEBUG, INFO, WARN, and ERROR.
  • Do not log sensitive information (e.g., passwords, tokens).
  • Implement structured logging for easy parsing and analysis.
  • Use external log aggregation tools like ELK (Elasticsearch, Logstash, Kibana) or Loki with Grafana.
  • Enable asynchronous logging to avoid performance bottlenecks.

1.2 What is Spring Boot Actuator?

Spring Boot Actuator provides production-ready features such as monitoring and logging. It offers various built-in endpoints to track application health, performance, and runtime configurations.

1.2.1 Common Actuator Endpoints

  • /actuator/health – Displays the application’s health status.
  • /actuator/loggers – Allows dynamic configuration of logging levels at runtime.
  • /actuator/httptrace – Logs recent HTTP requests and responses (needs to be enabled in properties).
  • /actuator/metrics – Provides application metrics such as memory usage, CPU load, and active threads.
  • /actuator/info – Displays custom application information (can be configured in application.properties).
  • /actuator/env – Shows the environment properties of the application.

1.2.2 Benefits of Using Spring Boot Actuator

  • Provides real-time insights into application performance.
  • Helps in proactive monitoring and debugging.
  • Supports integration with monitoring tools like Prometheus and Grafana.
  • Enables runtime configuration of logging levels without restarting the application.

Spring Boot Actuator is a powerful tool that enhances observability, making it easier to manage and debug applications in production.

2. Code Example

2.1 Maven Dependencies

To enable Actuator, add the following dependency in your pom.xml:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
</dependencies>

2.2 Enable Actuator in application.properties

To expose all Actuator endpoints for monitoring and debugging, add the following configuration to your application.properties or application.yml file:

1
2
3
4
5
6
# Expose all actuator endpoints
management.endpoints.web.exposure.include=*
# Enable the /actuator/loggers endpoint for runtime logging level changes
management.endpoint.loggers.enabled=true
# Enable detailed request logging for debugging
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG

With this setup, Spring Boot will log incoming requests at the DEBUG level.

2.3 Create a Custom Logging Filter

To log requests and responses in detail, create a custom filter:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@Component
public class LoggingFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
 
        logger.info("Incoming Request: [{}] {}", httpRequest.getMethod(), httpRequest.getRequestURI());
 
        chain.doFilter(request, response);
 
        logger.info("Outgoing Response: Status={}", httpResponse.getStatus());
    }
}

2.3.1 Code Explanation

The LoggingFilter class is a Spring Boot component that implements the Filter interface to log incoming HTTP requests and outgoing responses. Annotated with @Component, it is automatically detected as a Spring-managed bean. Inside the doFilter method, the request and response objects are cast to HttpServletRequest and HttpServletResponse, respectively. Before forwarding the request down the filter chain using chain.doFilter(request, response), it logs the HTTP method and request URI using SLF4J’s logger. After the request is processed, it logs the HTTP response status, helping with debugging and monitoring API traffic.

2.4 Create a Global Exception Handler

To log exceptions globally, create an exception handler using @ControllerAdvice:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
 
@RestControllerAdvice
public class GlobalExceptionHandler {
 
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception e) {
        logger.error("Exception occurred: {}", e.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("An error occurred: " + e.getMessage());
    }
}

2.4.1 Code Explanation

The GlobalExceptionHandler class is a centralized exception-handling component in a Spring Boot application, annotated with @RestControllerAdvice to provide global exception handling for all controllers. It defines a method handleException, which is annotated with @ExceptionHandler(Exception.class) to catch all exceptions of type Exception. When an exception occurs, it logs the error message using SLF4J’s logger and returns a ResponseEntity with an HTTP 500 (Internal Server Error) status and a response body containing the error message. This approach ensures consistent error responses and improves debugging by capturing exceptions centrally.

2.5 Testing the Implementation

Create a sample controller with an endpoint that triggers an exception:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RequestMapping("/api")
public class TestController {
 
    @GetMapping("/test")
    public String testEndpoint() {
        return "Hello, World!";
    }
 
    @GetMapping("/error")
    public String errorEndpoint() {
        throw new RuntimeException("Test Exception");
    }
}

2.5.1 Code Explanation

The TestController class is a Spring Boot REST controller, indicated by the @RestController annotation, which handles HTTP requests under the base path /api as defined by @RequestMapping("/api"). It defines two endpoints: /test and /error. The testEndpoint method, mapped to GET /api/test using @GetMapping("/test"), returns a simple “Hello, World!” response. The errorEndpoint method, mapped to GET /api/error, intentionally throws a RuntimeException with the message “Test Exception,” which would trigger global exception handling if configured, making this controller useful for testing request handling and error management in a Spring Boot application.

2.6 Output

2.6.1 Successful Request

When a request is made to the /api/test endpoint, the application logs an incoming request message, indicating that a GET request was received for /api/test. Since this endpoint successfully returns a “Hello, World!” response, the system logs an outgoing response message with an HTTP status code 200 (OK), signifying a successful request.

1
2
INFO  Incoming Request: [GET] /api/test
INFO  Outgoing Response: Status=200

2.6.2 Unsuccessful Request

When a request is made to the /api/error endpoint, the application logs an incoming request message, showing that a GET request was received for /api/error. However, since this endpoint deliberately throws a RuntimeException with the message “Test Exception,” the global exception handler catches the error and logs an exception message. As a result, the system logs an outgoing response message with an HTTP status code 500 (Internal Server Error), indicating that an error occurred while processing the request.

1
2
3
INFO  Incoming Request: [GET] /api/error
ERROR Exception occurred: Test Exception
INFO  Outgoing Response: Status=500

This logging output is useful for debugging and monitoring API behavior, as it provides clear visibility into both successful and failed request handling. By analyzing these logs, developers can quickly identify issues, trace errors, and ensure the application is functioning correctly.

3. Conclusion

By integrating Spring Boot Actuator, a custom logging filter, and a global exception handler, we can centralize logging for all requests, responses, and errors. This enhances observability, simplifies debugging, and ensures better monitoring for production-ready applications.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button