【问题标题】:Sonarlint complaint in log writting method日志写入方法中的 Sonarlint 投诉
【发布时间】:2020-02-12 23:23:00
【问题描述】:
log.info(String.format("Execution of method %s finished in %d ms", pointcut.getSignature().getName(), ms))

Sonarlint 显示以下错误:

“前提条件”和日志记录参数不应要求评估

合规解决方案:

logger.log(Level.SEVERE, "出了点问题:{0} ", message);

让我们试试吧:

log.info("Execution of method {0} finished in {1} ms", pointcut.getSignature().getName(), ms);

正确使用Printf风格的格式字符串

合规解决方案:

String.format("先 %s 后 %s", "foo", "bar");

我觉得 sonarlint 只是在嘲笑我。

这是我的判断,但我真的不明白发生了什么或为什么他首先抱怨:

String logMessage = String.format("Execution of method %s finished in %d ms", pointcut.getSignature().getName(), ms);
log.info(logMessage);

有什么想法吗?

【问题讨论】:

  • 使用 SLF4J 占位符,LOGGER.info("Execution of method {} finished in {} ms", variableOne, VariableTwo)slf4j.org/faq.html#logging_performance
  • 如果你使用的是 slf4j,那么大括号内的索引是不必要的,它不会用参数替换索引,它会按原样打印数字。
  • Sonar 的建议是针对使用 java.util.logging 包的代码。 java.util.logging.Logger 使用 MessageFormat 字符串。其他日志框架没有;正如其他 cmets 所说,他们使用空的 {} 占位符。
  • 可能类似于 log.info(() -> String.format("Execution of method %s finished in %d ms", pointcut.getSignature().getName(), ms))(不确定 Sonar 对此有何看法
  • 赞成,但是,我认为您应该将问题的标题编辑为更能描述您的问题的内容。

标签: java sonarlint


【解决方案1】:

我真的不明白发生了什么,或者他为什么首先抱怨:

第一个示例中的投诉原因是您无条件地做了大量工作来构建日志消息。如果日志级别高于 INFO,工作将被浪费。


第二个示例比第一个示例更好,因为仅当日志级别为 INFO 或更低时,才会从模板创建日志消息字符串。 pointcut.getSignature().getName() 表达式仍会无条件评估,但这可能是不可避免的,具体取决于您使用的特定日志记录 API。

(如果评估成本很高,您仍然会遇到性能问题。您可以考虑使用 if (log.isInfoLevel()) { ... } 保护,或使表达式评估变得懒惰的东西;例如 Supplier<String>。但最好的解决方案可能是避免记录那个昂贵的表达式。)


第二个示例中的 Sonar 投诉似乎与您在消息/格式字符串中使用的特定语法有关。 @C.Lechner 的回答是这样解释的:

  • 在第一个带有 {} 的版本中,{} 的类型是在运行时评估的。
  • 在第二个 %s, %d 中,您在编译时定义类型。

如果可能,您应该使用类型以避免误用占位符 变量并允许 java 编译器做一些额外的检查。

我并不完全相信 Java 编译器会进行检查。 (JLS 肯定不需要。)但是编译器或(智能)静态代码分析器可以检查肯定是合理的。

无论哪种方式,都会在运行时(再次)检查格式字符串。


最后,这个版本:

String logMessage = String.format("Execution of method %s finished in %d ms",
                                  pointcut.getSignature().getName(), ms);
log.info(logMessage);

与第一个版本有相同的性能问题,但我怀疑 Sonar 不够聪明,无法解决这个问题。

【讨论】:

    【解决方案2】:
    • 在第一个带有 {} 的版本中,{} 的 type运行时 进行评估。
    • 在第二个 %s, %d 中,您在 编译时 定义 type

    如果可能,您应该使用类型来避免滥用占位符变量并允许 java 编译器进行一些额外的检查。

    【讨论】:

      猜你喜欢
      • 2012-10-17
      • 2011-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-04
      • 1970-01-01
      • 2021-01-05
      相关资源
      最近更新 更多