Logging is way more important than a junior developer might think at first glance.
Logs are like the application's "black box" that records every action it takes.
They help you:
- Track incoming requests and their parameters.
- Figure out what actually happened inside the app.
- Spot errors and their root causes.
- Understand how the app behaves under load.
- Make debugging faster and easier.
In real projects, REST APIs often interact with many client apps. Logs help not only developers but also DevOps engineers and sysadmins to figure out where and what went wrong.
Logging in Spring Boot
In Spring Boot, Logback is responsible for logging (by default). It's a powerful and flexible logging framework. It supports different logging levels, formatting, and even shipping logs to remote systems.
Logging levels
Every log message has a severity level, kind of like news being either breaking or regular updates. Let's break down the hierarchy:
TRACE— the most detailed level. It's like a microscope for your code, showing every tiny detail. Usually turned off in production so logs don't get flooded.DEBUG— your go-to helper while developing. Records all the interesting bits that help you understand what's going on inside the app.INFO— the default working level. Captures important events in the app's life: "Server started", "Database connected", "Received important request".WARN— warnings about potential issues. Like a yellow traffic light — not critical yet, but worth checking out.ERROR— the red alarm. Something went really wrong and needs immediate attention. Logs serious errors that break normal operation.
Configuring logging in Spring Boot
Spring Boot provides auto integration with Logback, and you can configure logging via application.properties or application.yml. For example, to enable verbose debug mode (DEBUG), just add:
logging.level.root=DEBUG
Main tools for logging requests and responses
In Spring Boot there are several ways to log requests and responses. We'll look at three main approaches:
- Logging via Filters.
- Logging using AOP.
- Integrating with centralized logging frameworks.
1. Logging via Filters
Filters let you intercept HTTP requests and responses at a low level before controllers handle them. It's a simple way to log incoming requests and outgoing responses in one place.
Let's create a custom filter for logging:
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class RequestResponseLoggingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(RequestResponseLoggingFilter.class);
@Override
public void doFilter(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Log the incoming request
logger.info("Incoming request: method = {}, URI = {}", httpRequest.getMethod(), httpRequest.getRequestURI());
// Continue executing the filter chain
chain.doFilter(request, response);
// Log the outgoing response
logger.info("Outgoing response: status = {}", httpResponse.getStatus());
}
}
Let's break down the code:
- This filter intercepts all HTTP requests and responses.
- We use
logger.infoto record incoming requests (HTTP method and URI) and the outgoing response (HTTP status). - By calling
chain.doFilterwe pass control further down the chain.
2. Logging using AOP
AOP (Aspect-Oriented Programming) makes logging smart and flexible. It's like installing an automatic watcher that turns on only in the spots you care about.
Instead of littering your code with log calls, you create special "hooks" that automatically monitor only the methods you want. The rest of the code stays clean and focused on its job.
Here's an example aspect:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// Log before controller method execution
@Before("execution(* com.example.demo.controller.*.*(..))")
public void logBeforeEachRequest() {
logger.info("A method in controller is about to be called...");
}
// Log after successful controller method execution
@AfterReturning("execution(* com.example.demo.controller.*.*(..))")
public void logAfterEachRequest() {
logger.info("A method in controller has been completed successfully.");
}
}
- The
@Aspectannotation marks this class as an aspect. - With the expressions inside
@Beforeand@AfterReturningwe define which methods get logging. For example, we're logging all methods in thecom.example.demo.controllerpackage. - In
logBeforeEachRequestandlogAfterEachRequestwe useINFOlogging to record messages before and after the method call.
3. Centralized logging (optional)
If your app runs in a distributed system, classic logging can be hard to analyze. In those cases you use centralized logging systems (for example, ELK Stack: Elasticsearch, Logstash, and Kibana).
Example configuration to send logs to Elasticsearch via Logback:
logback-spring.xml
<configuration>
<appender name="ELASTICSEARCH-APPENDER" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<root level="info">
<appender-ref ref="ELASTICSEARCH-APPENDER"/>
</root>
</configuration>
This snippet sends all logs at INFO level and above to Logstash, which then ships them to Elasticsearch. You can then visualize logs in Kibana.
Practical application
1. Which method to choose?
- Filters if you need to log every request and response in one place.
- AOP if you only need to log specific methods (for example, controller methods).
- Centralized logging is relevant for production, especially if you have multiple microservices.
2. Common mistakes
- Excessive logging: logging everything all the time isn't always a good idea. Logs can become noisy. Log only the info you actually need.
- Logging sensitive data: never log passwords, tokens, or other sensitive information.
- Wrong logging level: e.g., using
ERRORfor regular business logic is an anti-pattern.
3. What helps in an interview?
Being able to log requests and responses shows your interviewer that you know how to provide observability for an app. Understanding logging levels and centralized systems like ELK will earn you extra points.
Now you know how to add logging to a REST API. It not only helps with error handling but also nicely reveals the app's "insides." Logs are your eyes and ears.
GO TO FULL VERSION