@Slf4j Logging
@Slf4j generates a configured SLF4J Logger as a private static final field named log, so you can start logging without the repetitive LoggerFactory.getLogger(...) declaration. SLF4J is the logging facade that Spring Boot uses by default (over Logback), making @Slf4j the natural choice for Spring applications.
The generated log field
Adding @Slf4j to a class gives you an immediately usable log reference:
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class PaymentService {
public void charge(String orderId) {
log.info("Charging order {}", orderId);
}
}
Lombok generates exactly the field you would otherwise write by hand:
private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(PaymentService.class);
Because it is static final and keyed to the class, it follows the standard logging convention and is correctly named in your log output.
Parameterized logging
Always use SLF4J’s {} placeholders instead of string concatenation. The arguments are only converted to strings if the log level is actually enabled, which avoids wasted work in hot paths.
@Slf4j
@Service
public class OrderService {
public Order place(OrderRequest request) {
log.debug("Placing order for customer={} items={}",
request.getCustomerId(), request.getItemCount());
try {
return process(request);
} catch (PaymentException ex) {
// pass the exception as the LAST argument to log the stack trace
log.error("Payment failed for customer={}", request.getCustomerId(), ex);
throw ex;
}
}
}
Tip: Do not write
log.debug("order " + request)— the concatenation runs even when debug is disabled. The{}form defers it. To log an exception’s stack trace, pass theThrowableas the final argument (no placeholder for it).
Output:
2026-06-13T10:42:11.220+05:30 INFO 5120 --- [nio-8080-exec-1] c.e.app.OrderService : Placing order for customer=42 items=3
2026-06-13T10:42:11.880+05:30 ERROR 5120 --- [nio-8080-exec-1] c.e.app.OrderService : Payment failed for customer=42
com.example.app.PaymentException: card declined
at com.example.app.OrderService.process(OrderService.java:51)
...
Log levels
The log field exposes the five standard SLF4J levels. Guard truly expensive message construction with an isXxxEnabled() check.
| Method | Use for |
|---|---|
log.error(...) | failures that need attention |
log.warn(...) | recoverable problems, deprecations |
log.info(...) | high-level lifecycle / business events |
log.debug(...) | diagnostic detail for development |
log.trace(...) | very fine-grained tracing |
if (log.isDebugEnabled()) {
log.debug("Computed report: {}", expensiveToString());
}
Configure thresholds per package in application.yml — see Logging Configuration:
logging:
level:
root: INFO
com.example.app: DEBUG
Other logger annotations
Lombok offers one annotation per logging framework. They all generate the same log field but bind to a different backend; choose based on the facade/implementation on your classpath. With Spring Boot, @Slf4j is almost always the right one.
| Annotation | Backing API |
|---|---|
@Slf4j | SLF4J (recommended for Spring Boot) |
@CommonsLog | Apache Commons Logging |
@Log4j2 | Apache Log4j 2 |
@Log | java.util.logging |
@Flogger | Google Flogger |
You can also rename the field with @Slf4j(topic = "audit") to log under a specific category:
@Slf4j(topic = "AUDIT")
@Component
public class AuditLogger {
public void record(String action) {
log.info("action={}", action); // logger named "AUDIT"
}
}
Note:
@Slf4jonly declares the logger; it does not configure output format or appenders. Those are controlled by Logback (logback-spring.xml) or properties, covered in Logging Configuration.