Best Practices for Using SLF4J Logging in Java
This guide explains why to use the SLF4J façade with Logback, when to log, proper parameterized message formats, level‑specific conventions for ERROR, WARN, INFO, DEBUG, and TRACE, and provides concrete code examples for clean, performant logging in Java applications.
Using SLF4J
Using a façade logging framework helps maintain consistency across classes.
The implementation is standardized on the Logback framework.
Correct Way to Log
When to Log
When debugging a problem, add logs so the issue can be diagnosed from log files.
At the start of each conditional branch (if/else, switch) to identify which path is taken.
Before committing code, ensure logs can show the entire functional flow.
Basic Format
Always use parameterized logging:
logger.debug("Processing trade with id:[{}] and symbol:[{}]", id, symbol);For DEBUG level, check if debug is enabled before logging:
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}Avoid string concatenation in log statements because it creates many temporary String objects and hurts performance.
Using [] for Parameter Isolation
When there are parameters, write the log as:
logger.debug("Processing trade with id:[{}] and symbol:[{}]", id, symbol);This format improves readability and aids troubleshooting.
Usage of Different Log Levels
ERROR
Basic Concept
Errors that affect normal program execution or the current request:
Failure to open configuration files.
Third‑party integration errors, including error codes returned by external services.
All exceptions that impact functionality, such as SQLException, RuntimeException, and generic Exception (excluding business exceptions).
Do not log situations that are not truly errors, e.g., Azure image upload timeout when Azure does not respond.
If a Throwable is present, log the full stack trace:
log.error("Error retrieving user [{}] information", userName, e);Note
If the exception is re‑thrown, avoid logging it here; let the final handler record it.
WARN
Basic Concept
Situations that do not affect program execution but indicate potential problems:
Errors that are handled by fault‑tolerance mechanisms.
Missing configuration files that the system can auto‑create.
Approaching resource limits, e.g., cache pool reaching a warning threshold.
Business exceptions that should be recorded when an API throws them.
INFO
Basic Concept
System operational information:
State changes in service methods (system or business).
Step‑by‑step progress of major logic.
External interface details:
Client request parameters (REST/WS).
Parameters and results when calling third‑party services.
Note
Not every simple service needs entry/exit logs; only complex services or jobs (which need start and end logs).
Complex business flows (e.g., order creation) should have detailed logs.
All API endpoints should log input parameters.
When the service follows an SOA architecture, treat it as an external provider and log inputs.
Calls to third‑party services must log both request and response for traceability.
DEBUG
Basic Concept
Log all relevant information needed for debugging, with meaningful context and parameters.
Disable DEBUG logs in production.
If DEBUG must be enabled in production, control it with a switch.
Note
Example of sub‑optimal logging:
//1. Get user basic salary
//2. Get user leave information
//3. Calculate user payable salaryOptimized version with parameterized logs:
logger.debug("Start fetching basic salary for employee [{}] year [{}]", employee, year);
logger.debug("Fetched basic salary for employee [{}] year [{}]: [{}]", employee, year, basicSalary);
logger.debug("Start fetching leave info for employee [{}] year [{}] month [{}]", employee, year, month);
logger.debug("Employee [{}][{}] year [{}] month leave: annual/[{}] sick/[{}] unpaid/[{}]", employee, year, month, annualLeaveDays, sickLeaveDays, noPayLeaveDays);
logger.debug("Start calculating salary for employee [{}] year [{}] month [{}]", employee, year, month);
logger.debug("Calculated salary for employee [{}] year [{}] month [{}]: [{}]", employee, year, month, actualSalary);TRACE
Basic Concept
Very detailed system execution information; generally avoid using TRACE in business code unless there is a special need—use DEBUG instead.
Standard Example
@Override
@Transactional
public void createUserAndBindMobile(@NotBlank String mobile, @NotNull User user) throws CreateConflictException {
boolean debug = log.isDebugEnabled();
if (debug) {
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 (debug) {
log.debug("User creation succeeded. insertedUser=[{}]", LogObjects.toString(user));
}
UserMobileRelationship relationship = new UserMobileRelationship();
relationship.setMobile(mobile);
relationship.setOpenId(user.getOpenId());
relationship.setCreateTime(new Date());
relationship.setUpdateTime(new Date());
userMobileRelationshipRepository.insertOnDuplicateKey(relationship);
if (debug) {
log.debug("Mobile binding succeeded. relationship=[{}]", LogObjects.toString(relationship));
}
log.info("Created user and bound mobile. userId=[{}],openId=[{}],mobile=[{}]", user.getId(), user.getOpenId(), mobile); // mask mobile if needed
} catch (DuplicateKeyException e) {
log.info("Failed to create user and bind mobile; 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 Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java 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.
