Log Requests, Responses, Exceptions in Spring Boot

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. 

How to Log All Requests, Responses and Exceptions in a Single Place in Spring Boot
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

  1. @Aspect: This annotation indicates that the class is an aspect, which is a module that encapsulates a cross-cutting concern.
  2. @Component: This annotation allows Spring to detect the aspect during component scanning.</
  3. HttpServletRequest: We inject the HttpServletRequest to access request details.
  4. @Before: This advice runs before the execution of the specified methods. We log the incoming request method, URI, and parameters.
  5. @AfterReturning: This advice runs after the method execution and logs the response.
  6. @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.

Post a Comment

Previous Post Next Post