Master SLF4J Logging: Best Practices and Real‑World Java Examples
This article explains why SLF4J with Logback is the preferred logging façade for Java back‑ends, when to log, how to format messages using parameterized placeholders, and the correct usage of each log level with clear do‑and‑don’t code examples.
Using SLF4J for Effective Logging
Adopting a façade‑based logging framework such as SLF4J standardises log handling across a Java backend and simplifies future changes of the underlying implementation.
Why Use SLF4J?
Facade pattern unifies logging APIs, making maintenance easier.
Common implementation choice: Logback.
When to Write Logs
During troubleshooting, logs help pinpoint problems when debugging is insufficient.
At the entry of each conditional branch (if/else, switch) to confirm the executed path.
Before committing code, ensure the entire workflow can be reconstructed from logs.
Basic Log Format
Always use parameterised messages to avoid unnecessary string concatenation and object creation.
logger.debug("Processing trade with id:[{}] and symbol:[{}]", id, symbol);For DEBUG level, guard the call with logger.isDebugEnabled() when the message construction is expensive.
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}Avoid concatenating strings directly as it creates many temporary String objects.
Using Parameter Placeholders []
logger.debug("Processing trade with id:[{}] and symbol:[{}]", id, symbol);This improves readability and aids troubleshooting.
Log Level Guidelines
ERROR
Log situations that prevent normal operation or indicate serious failures, such as configuration file loading errors or third‑party service failures (including SQLExceptions and unchecked exceptions).
log.error("Failed to get user [{}] info", userName, e);Do not log and re‑throw the same exception as an error; let the outer handler manage it.
WARN
Log recoverable issues that do not affect the current request, e.g., missing optional config files that can be auto‑created, or resource usage approaching warning thresholds.
INFO
Record normal operational events such as service method entry/exit, key business state changes, request parameters, and third‑party call inputs/outputs.
log.info("Creating user and binding mobile. userId=[{}], openId=[{}], mobile=[{}]", user.getId(), user.getOpenId(), mobile);Do not log trivial service calls; only complex or business‑critical flows need INFO points.
DEBUG
Include detailed information useful for developers, but disable in production. Use meaningful messages with relevant parameters.
logger.debug("Start fetching employee [{}] basic salary for year [{}]", employee, year);
logger.debug("Employee [{}] basic salary for year [{}] is [{}]", employee, year, basicSalary);TRACE
Very fine‑grained messages; generally avoid in business code unless a special need exists, preferring DEBUG instead.
Sample Implementation
@Override
@Transactional
public void createUserAndBindMobile(@NotBlank String mobile, @NotNull User user) throws CreateConflictException {
if (log.isDebugEnabled()) {
log.debug("Start creating user and binding mobile. args[mobile=[{}], user=[{}]]", mobile, LogObjects.toString(user));
}
try {
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
userRepository.insertSelective(user);
if (log.isDebugEnabled()) {
log.debug("User created successfully. insertedUser=[{}]", LogObjects.toString(user));
}
UserMobileRelationship rel = new UserMobileRelationship();
rel.setMobile(mobile);
rel.setOpenId(user.getOpenId());
rel.setCreateTime(new Date());
rel.setUpdateTime(new Date());
userMobileRelationshipRepository.insertOnDuplicateKey(rel);
if (log.isDebugEnabled()) {
log.debug("Mobile bound successfully. relationship=[{}]", LogObjects.toString(rel));
}
log.info("Created user and bound mobile. userId=[{}], openId=[{}], mobile=[{}]", user.getId(), user.getOpenId(), mobile);
} catch (DuplicateKeyException e) {
log.info("Failed to create user; duplicate exists. openId=[{}], mobile=[{}]", user.getOpenId(), mobile);
throw new CreateConflictException("User creation conflict, openid=[%s]", user.getOpenId());
}
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
