# SLF4J & Structured Logging — Advanced Java

Source: https://www.geekswithgeeks.com/en/advanced-java/adv-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.

```java
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.
