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
, andERROR
. - 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 inapplication.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.