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.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Master Java Logging: 12 Essential Practices for Clean, Efficient Logs

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"}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performancebest practicesError Handlingslf4j
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.