Creating and Using a Logger with SLF4J
Fast recall
Quick revision
Core answer
LoggerFactory.getLogger(MyClass.class) and call parameterized methods such as log.info("Created order {}", orderId). A private static final field is the common one-logger-per-class convention, not a correctness requirement. Passing the declaring class gives the logger a stable class/package name for configuration.Interview-ready guide
Interview answer
I obtain an SLF4J logger with LoggerFactory.getLogger(OrderService.class). I commonly store it in a private static final field so instances share the reference and it is not reassigned, although an instance field is also valid. Passing the declaring class gives a stable name that follows the package hierarchy. I write parameterized events such as log.info("Created order {}", orderId), which lets the provider skip formatting when the event is disabled. For an unexpected failure, I pass the exception object at the layer responsible for recording it: log.error("Order {} failed", orderId, ex).
Creating and Using a Logger with SLF4J
Direct Answer
Create a logger with LoggerFactory.getLogger(MyClass.class) and call parameterized methods such as log.info("Created order {}", orderId). A private static final field is the common one-logger-per-class convention, not a correctness requirement. Passing the declaring class gives the logger a stable class/package name for configuration.
Deep Dive & Architecture
SLF4J loggers are obtained from LoggerFactory. Passing OrderService.class names the logger after that class, so package or class-level configuration can select it.
A common declaration is private static final Logger log = LoggerFactory.getLogger(OrderService.class);. static final avoids storing an identical logger reference in every instance and prevents reassignment, but SLF4J also supports instance logger fields. The important part is a stable, accurate logger name.
Use parameterized calls such as log.info("Created order {}", orderId) instead of concatenating values. Pass an exception object when its stack trace belongs on the event: log.error("Order {} failed", orderId, ex).
Code Example
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PaymentService {
// one logger per class, named com.app.PaymentService
private static final Logger log = LoggerFactory.getLogger(PaymentService.class);
public void pay(long orderId, double amount) {
log.info("Charging order {} for {}", orderId, amount); // parameterized, no '+'
if (amount <= 0) {
log.warn("Non-positive amount {} for order {}", amount, orderId);
return;
}
try {
gateway.charge(amount);
} catch (Exception e) {
log.error("Charge failed for order {}", orderId, e); // exception last = stack trace
}
}
}
Common Mistakes & Pitfalls
- Non-static logger:
private final Logger log = ...per instance creates needless objects; usestatic. - Hardcoded name:
getLogger("PaymentService")as a string breaks on rename and loses package config; usePaymentService.class. - Concatenation:
log.debug("x=" + obj)builds the string even when DEBUG is off; uselog.debug("x={}", obj).
Check your understanding
Answer these without looking back at the article.
- What is SLF4J and why is it used instead of logging directly with a framework?
- How do you configure logging in a Spring Boot application?
- How do you add SLF4J logging to a Java class and write your first log statement?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.