Lesson 33 / 38
SLF4J & Structured Logging
Stop debugging with System.out.println — log through SLF4J against a real backend like Logback, pick the right level, and understand why that matters in production.
Why not System.out.println
println can't be turned off per class, can't be redirected to a file or log aggregator, carries no timestamp/level/thread info, and is effectively a synchronized call that can serialize your threads. A logging framework gives you all of that for free.
SLF4J: log against an interface
SLF4J is a facade — your code depends only on its Logger interface, and any backend (Logback, Log4j2) can be plugged in via the classpath, without touching a single log statement.
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
void place(Order o) {
log.debug("placing order {}", o.id());
try {
repo.save(o);
log.info("order {} placed for {}", o.id(), o.customerId());
} catch (Exception e) {
log.error("failed to place order {}", o.id(), e);
}
}Pick the right level
TRACE/DEBUG for developer detail (off in prod), INFO for significant business events, WARN for recoverable problems worth a look, ERROR for failures needing attention. Use {} placeholders, not string concatenation — SLF4J skips formatting entirely when the level is disabled.