Logging
The Logging Facade Pattern
The benefit of the facade layer is that library authors can log against SLF4J without forcing every consumer of their library to use one specific logging backend — the application assembling everything picks the implementation once, at the very end.
Log Levels
Every log message is tagged with a severity level. The logging configuration then decides, per level, whether a message is printed, ignored, or sent somewhere specific — without changing a single line of application code.
Level | Typical Use |
TRACE | Extremely fine-grained detail, rarely enabled outside deep debugging sessions |
DEBUG | Diagnostic information useful during development, usually off in production |
INFO | Routine, expected events worth recording — a service starting up, a request completing |
WARN | Something unexpected happened but the application can continue |
ERROR | A failure that likely needs attention — an operation could not complete |
Using SLF4J
Logging with SLF4J's Logger
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
public void login(String username) {
log.info("User {} logged in", username);
try {
authenticate(username);
} catch (AuthenticationException e) {
log.error("Authentication failed for user {}", username, e);
}
}
private void authenticate(String username) {
// authentication logic
}
}A Logger is created once per class, typically as a private static final field, and named after that class so log output can be traced back to its source.
Prefer a stable logging facade (SLF4J) over calling a specific implementation directly in application code
Configure log levels per environment — verbose in development, quieter in production
Always log the exception object itself (not just its message) so a full stack trace is captured
Never log sensitive data — passwords, tokens, full credit card numbers — even at DEBUG level