Master Java Logging with SLF4J, Logback, and Lombok @Slf4j
This tutorial explains why System.out.println() is unsuitable for production logging, shows how to add SLF4J and Logback dependencies, configure logback.xml, use Lombok's @Slf4j annotation to generate a logger, and provides practical code examples for unified API logging and exception tracking.
Why Use a Logging Framework Instead of System.out.println()
Printing directly to the console with System.out.println() leads to poor performance, makes log management difficult, and provides no level distinction or standardized format, which hampers debugging and production issue tracing.
Setting Up SLF4J and Logback
Include the SLF4J API and Logback implementation in your Maven pom.xml:
<dependencies>
<!-- SLF4J core API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<!-- Logback classic implementation -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency>
<!-- Logback core -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.6</version>
</dependency>
</dependencies>Then create src/main/resources/logback.xml to define the output format and root level:
<configuration>
<!-- Console appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- Pattern: timestamp - level [thread] logger - message -->
<pattern>%d{yyyy-MM-dd HH:mm:ss} - %5p [%t] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Root logger at DEBUG level (change to ERROR in production) -->
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>The pattern prints the time, log level, thread name, logger name, and the actual message. Setting the root level to DEBUG logs all messages at DEBUG and higher; in production you would typically raise this to ERROR.
Using Lombok @Slf4j Annotation
Instead of manually creating a Logger instance, annotate the class with Lombok's @Slf4j. Lombok generates a static log field automatically.
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LogExample {
public static void main(String[] args) {
log.info("This is an info message");
log.debug("This is a debug message");
log.error("This is an error message");
log.warn("This is a warning message");
}
}With @Slf4j, you can call log.info(), log.debug(), etc., without any boilerplate.
Practical Example: Unified API Logging
In a Spring Boot controller, you can log incoming requests and responses uniformly:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
public class APIController {
@GetMapping("/api/test")
public String testAPI() {
log.info("API request received for /api/test");
String response = "Hello, world!";
log.info("API response: {}", response);
return response;
}
}This demo shows how log.info() records both the request arrival and the response content, and you can switch the log level (e.g., DEBUG, ERROR) as needed.
Exception Tracking Logging
When an exception occurs, logging the stack trace is crucial for rapid diagnosis. Using the same logger, you can capture the exception details:
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ExceptionHandler {
public void handleException() {
try {
int result = 10 / 0; // Simulate an error
} catch (Exception e) {
// The second argument prints the stack trace automatically
log.error("An error occurred: ", e);
}
}
}By logging the exception with log.error(), the full stack trace appears in the logs, enabling developers to pinpoint the root cause quickly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
