Master Java Logging: 12 Essential Practices for Clean, Efficient Logs
This article presents twelve practical guidelines for Java logging, covering interface‑layer usage, avoiding separator lines, preventing logging‑induced exceptions, leveraging Fastjson features, preserving exception stacks, limiting message length, merging stack traces, skipping costly placeholders, avoiding console output, discarding redundant utilities, and adhering to Alibaba's logging specification.
1. Always Use Interface Layer
When writing code or integrating third‑party tools, record logs only at the interface layer. If a third‑party tool is exposed, mark the implementation and adapter layers as optional in the dependency.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency> <scope>runtime</scope>: the package is ignored at compile time, assuming the runtime already provides it. <optional>true</optional>: the dependency is not transitively passed on; Maven will not install it automatically.
2. Avoid Printing Separator Lines
Do not log lines that contain only separators such as log.info("========== start =========="), because they provide no useful context in large log streams. Instead, use meaningful keywords, e.g., log.info("FooBarProcessor start, request={}", request), which can be quickly filtered with grep or SLS.
Markers can also improve semantic clarity, though they add some complexity.
3. Prevent Exceptions When Logging
Never call a method on a possibly null object directly in a log statement; this can cause a NullPointerException.
Object result = rpcResource.call();
// If result is null, NPE will be thrown
log.info("result.userId={}", result.getUserId());This common pitfall is omitted for brevity.
4. Two Fastjson Parameters
4.1 IgnoreErrorGetter
If a getter throws an exception during serialization, the whole process is aborted. Use SerializerFeature.IgnoreErrorGetter to ignore such exceptions.
public class Foo {
private Long userId;
@Deprecated
private Long accountId;
// getter throws exception
public Long getAccountId() {
throw new RuntimeException("请使用 userId");
}
}
log.info("foo={}", JSON.toJSONString(foo, SerializerFeature.IgnoreErrorGetter));4.2 IgnoreNonFieldGetter
When a getter does not correspond to an actual field (e.g., isError() in a Result wrapper), it can produce misleading keys like "error":false. Use SerializerFeature.IgnoreNonFieldGetter to skip such getters.
@Data
public class Result<T> {
private boolean success;
private T data;
public boolean isError() { return !success; }
}
log.info("result={}", JSON.toJSONString(result, SerializerFeature.IgnoreNonFieldGetter));5. Do Not Omit Exception Stack
When logging an exception, ensure the stack trace is not lost. Use a separate placeholder for the message and pass the exception as an additional argument. log.error("exception={}", e.getMessage(), e); This prints the message followed by the full stack trace.
6. Limit Log Output Length
6.1 Limit Message Length
For very large POJOs, truncate the logged message, e.g., %.-2000message, to avoid performance impact and unwieldy logs.
6.2 Limit Stack Trace Depth
Logback supports depth limiting with %exception{50}, which prints only the first 50 frames.
7. Merge Stack Trace Into One Line
Use Logback’s %replace conversion word to replace line‑breaks, carriage returns, and tabs with spaces, then suppress the original exception output with %nopex. %replace(%exception){'[\r\n\t]+', ' '}%nopex Combine this with length limits if needed, e.g., %.-10000replace(%exception{50}){'[\r\n\t]+', ' '}%nopex.
8. Avoid %method and %line
Including method name and line number requires stack trace generation, which is CPU‑intensive. Prefer hard‑coded identifiers in the log message.
log.info("queryUserInfo, request={}, result={}", request, result);9. Do Not Log to Console
Console output is useless in production and wastes resources. Use file appenders or other persistent destinations instead of System.out.println or ConsoleAppender.
10. Discard Custom LogUtil
A custom LogUtil often re‑implements features already provided by Slf4j/Logback (parameter handling, JSON conversion, length truncation, stack merging, dynamic switches, traceId injection). Remove it and rely on the native API.
11. Read the Logging Specification
Refer to the “Log Specification” chapter of the Alibaba Java Development Manual for comprehensive guidelines.
12. Small Detail: Colon vs Equal Sign
When logging key‑value pairs, match the separator with the format: use a colon after the key when the value is an object (e.g., log.info("foo:{}", foo)), and an equal sign when the value is JSON (e.g., log.info("foo={}", JSON.toJSONString(foo))).
// Example 1
log.info("foo:{}", foo); // prints foo:Foo{bar=baz}
// Example 2
log.info("foo={}", JSON.toJSONString(foo)); // prints foo={"bar":"baz"}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.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
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.
