Lesson 32 / 35

SLF4J & Structured Logging

Replace System.out.println with SLF4J and Logback, choose the right log levels and see why it 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.