Skip to main content

4.3 Logging with SLF4J & Logback

← Back to Chapter 4: Exception Handling, Logging & Production Support

Production microservices require structured, efficient, and traceable logs. Spring Boot utilizes SLF4J (Simple Logging Facade for Java) backed by Logback by default.


Logging​

Logging means recording what is happening inside the application.

For example:

Customer verification started
Customer ID = C123
Verification request sent
Government API response received
Verification completed

Logs help developers and support teams understand what happened.

Logging Levels​

The major logging levels are:

TRACE
DEBUG
INFO
WARN
ERROR

From less severe to more severe:

TRACE
↓
DEBUG
↓
INFO
↓
WARN
↓
ERROR

1. Logging Levels & Thresholds​

TRACE < DEBUG < INFO < WARN < ERROR < OFF
▲ ▲
Verbose execution details System failures
  • TRACE: Low-level step-by-step method and query traces.
  • DEBUG: Diagnostic data valuable during development and troubleshooting.
  • INFO: High-level operational events (service startup, batch job completed).
  • WARN: Potential issues (slow database query, retry triggered, deprecated API hit).
  • ERROR: Actionable faults requiring engineer investigation.

Configuring Levels in application.yml:​

logging:
level:
root: INFO
org.springframework.web: WARN
org.hibernate.SQL: DEBUG
com.codewithsarvy: DEBUG

2. Structured Logging with MDC (Mapped Diagnostic Context)​

In multi-threaded and distributed systems, tracing requests across concurrent threads is impossible without a unique correlation identifier. Logback's MDC stores thread-local contextual data:

@Component
public class CorrelationIdFilter extends OncePerRequestFilter {

public static final String CORRELATION_ID_KEY = "correlationId";
public static final String CORRELATION_ID_HEADER = "X-Correlation-Id";

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String correlationId = request.getHeader(CORRELATION_ID_HEADER);
if (correlationId == null || correlationId.isBlank()) {
correlationId = UUID.randomUUID().toString();
}

try {
MDC.put(CORRELATION_ID_KEY, correlationId);
response.setHeader(CORRELATION_ID_HEADER, correlationId);
chain.doFilter(request, response);
} finally {
MDC.remove(CORRELATION_ID_KEY); // Mandatory to prevent thread pool leakage!
}
}
}

3. Logback Configuration (logback-spring.xml)​

For production environments (e.g., streaming to Elasticsearch / Splunk / Datadog), JSON logging is standard:

<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{correlationId}] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

SLF4J​

In Spring Boot applications, you'll commonly see:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Example:

private static final Logger log =
LoggerFactory.getLogger(CustomerService.class);

public void verifyCustomer(String customerId) {

log.info("Starting verification for customerId={}", customerId);

try {
// verification logic
} catch (Exception ex) {
log.error("Verification failed for customerId={}",
customerId, ex);
throw ex;
}
}

Why Use SLF4J?​

SLF4J is a logging abstraction.

It allows your application code to use a common logging API while the actual logging implementation can be something like Logback.

In Spring Boot, Logback is commonly used by default with the standard logging setup.

SLF4J provides a common logging API, and Spring Boot commonly uses Logback as the underlying logging implementation.