How to Log All Requests, Responses and Exceptions in a Single Place in Spring Boot
Logging is an essential aspect of any application, especially in microservices architecture where tracking the flow of requests and responses can become complex. In this blog post, we will explore how to log all requests, responses, and exceptions in a single place in a Spring Boot application. This approach not only helps in debugging but also provides insights into the application's behavior in production.
![]() |
Log Requests, Responses, Exceptions in Spring Boot |
Why Centralized Logging?
Centralized logging allows developers and system administrators to monitor application behavior, troubleshoot issues, and analyze performance metrics. By logging all requests, responses, and exceptions in a single place, you can:
- Easily trace the flow of requests through your application.
- Identify performance bottlenecks.
- Capture and analyze exceptions for better error handling.
- Maintain a consistent logging format across your application.
Setting Up a Spring Boot Application
Before we dive into logging, let’s set up a simple Spring Boot application. You can create a new Spring Boot project using Spring Initializr (https://start.spring.io/) with the following dependencies:
- Spring Web
- Spring Boot DevTools (optional for development)
- Lombok (optional for reducing boilerplate code)
Project Structure
Your project structure should look something like this:
src └── main ├── java │ └── com │ └── example │ └── logging │ ├── LoggingApplication.java │ ├── controller │ │ └── SampleController.java │ └── aspect │ └── LoggingAspect.java └── resources └── application.properties
Sample Controller
Let’s create a simple REST controller that we will log requests and responses for.
package com.example.logging.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
Logging Aspect
To log requests, responses, and exceptions, we will use Spring AOP (Aspect-Oriented Programming). Create a new class called LoggingAspect
in the aspect
package.
package com.example.logging.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
private final HttpServletRequest request;
public LoggingAspect(HttpServletRequest request) {
this.request = request;
}
@Before("execution(* com.example.logging.controller..*(..))")
public void logRequest(JoinPoint joinPoint) {
logger.info("Incoming request: {} {} from IP: {}", request.getMethod(), request.getRequestURI(), request.getRemoteAddr());
logger.info("Request parameters: {}", request.getParameterMap());
}
@AfterReturning(pointcut = "execution(* com.example.logging.controller..*(..))", returning = "result")
public void logResponse(JoinPoint joinPoint, Object result) {
logger.info("Outgoing response from method: {} with result: {}", joinPoint.getSignature().getName(), result);
}
@AfterThrowing(pointcut = "execution(* com.example.logging.controller..*(..))", throwing = "exception")
public void logException(JoinPoint joinPoint, Throwable exception) {
logger.error("Exception in method: {} with message: {}", joinPoint.getSignature().getName(), exception.getMessage());
}
}
Explanation of the Logging Aspect
@Aspect
: This annotation indicates that the class is an aspect, which is a module that encapsulates a cross-cutting concern.@Component
: This annotation allows Spring to detect the aspect during component scanning.</HttpServletRequest
: We inject theHttpServletRequest
to access request details.@Before
: This advice runs before the execution of the specified methods. We log the incoming request method, URI, and parameters.@AfterReturning
: This advice runs after the method execution and logs the response.@AfterThrowing
: This advice runs if a method throws an exception, allowing us to log the exception details.
Configuring Logging
In your application.properties
, you can configure the logging level and format. For example:
logging.level.root=INFO
logging.level.com.example.logging=DEBUG
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %m%n
Testing the Application
To test the logging functionality, run your Spring Boot application and make a request to the /hello
endpoint. You can use tools like Postman or curl to send requests. You should see logs in the console that detail the incoming request, outgoing response, and any exceptions that may occur.
Conclusion
In this blog post, we have implemented a centralized logging mechanism for requests, responses, and exceptions in a Spring Boot application using AOP. This approach not only simplifies debugging but also enhances the observability of your application. By following these steps, you can ensure that your application logs are comprehensive and useful for monitoring and troubleshooting.