5

我正在使用最新的 Eclipse 和 Sonar 插件

作为日志记录的答案,有以下行:

log.debug("Request body: {}", new String(body, "UTF-8"));

只有在调试级别时才应该创建字符串:

/**
 * Log a message at the DEBUG level according to the specified format
 * and argument.
 * <p/>
 * <p>This form avoids superfluous object creation when the logger
 * is disabled for the DEBUG level. </p>
 *
 * @param format the format string
 * @param arg    the argument
 */
public void debug(String format, Object arg);

但声纳将其标记为squid:S2629

“先决条件”和日志记录参数不应该需要评估 (squid:S2629)

并给出连接示例

logger.log(Level.DEBUG, "出了点问题:" + message); // 不合规的;即使日志级别太高而无法显示调试消息,也会执行字符串连接

这是误报声纳警告还是我错过了什么?

这不是这个问题的重复,该问题通常询问规则概念,即连接,但不使用创建对象进行格式化new String

答案的链接还说创建new Date()不会产生内置格式的问题:

public static void main(String[] args) {
    LOGGER.info("The program started at {}", new Date());
}

}

以这种方式记录,可以避免在实际不记录任何内容时字符串连接的性能开销。

4

2 回答 2

8

在非调试模式下,该行

log.debug("Request body: {}", new String(body, "UTF-8"));

代替

log.debug(MessageFormatter.format("Request body: {}", new String(body, "UTF-8")));

避免创建由 . 创建的字符串MessageFormatter.format(String messagePattern, Object arg),但不会创建由 . 创建的其他字符串new String(body, "UTF-8")

这意味着它不是误报,因为在调用日志记录方法之前首先计算参数。

只要SLF4J 不支持 lambda 表达式来延迟计算参数(参见ZhekaKozlov的评论),就可以使用以下实用方法作为解决方法:

private static Object lazyToString(final Supplier<String> stringSupplier) {
    return new Object() {
        @Override
        public String toString() {
            return stringSupplier.get();
        }
    };
}

这可用于将字节数组转换为字符串仅限于 DEBUG 模式:

log.debug("Request body: {}", lazyToString(() -> new String(body, StandardCharsets.UTF_8)));
于 2018-10-28T14:49:03.053 回答
2

虽然使用 lambda 或惰性 lambda 没问题,但仍然有旧的好isDebugEnabled方法:

if (log.isDebugEnabled()) {
  log.debug("Request body: {}", new String(body, StandardCharsets.UTF_8));
}

这不会修复String正在创建的内容(因为您毕竟想显示它),但是在禁用调试模式时不会消耗内存。

于 2018-10-28T18:14:20.630 回答