Eclipse-Sonar S2629使用新的String可能会误报

时间:2018-10-28 13:06:37

标签: java eclipse sonarqube sonarlint-eclipse

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

answer中记录以下行:

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

只有在DEBUG级别时才应创建String:

/**
 * 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);

但是Sonar将其标记为squid:S2629

  

“前提条件”和日志记录参数不应该求值(squid:S2629)

并举例说明串联

  

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

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

这不是this question的副本,后者通常是在询问规则概念,它是串联的,但不能通过创建对象为new String来格式化

也有link的回答说创建new Date()并不会产生内置格式的问题:

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

}
     

以这种方式记录日志,可以避免在实际上不应该记录任何内容的情况下避免字符串连接的性能开销。

2 个答案:

答案 0 :(得分:4)

在非调试模式下,线路

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 does not support lambda expression to lazy evaluate arguments(请参阅comment by ZhekaKozlov),以下实用程序方法就可以用作解决方法:

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

这只能用于将字节数组转换为字符串的方式仅限于调试模式:

log.debug("Request body: {}", lazyToString(() -> new String(body, StandardCharsets.UTF_8)));

答案 1 :(得分:2)

尽管可以使用lambda或lazy lambda,但仍然有一种不错的旧isDebugEnabled方式:

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

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