日志写入方法中的 Sonarlint 投诉

Sonarlint complaint in log writting method

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

Sonarlint 显示以下错误:

"Preconditions" and logging arguments should not require evaluation

Compliant Solution:

logger.log(Level.SEVERE, "Something went wrong: {0} ", message);

让我们试试看:

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

Printf-style format strings should be used correctly

Compliant Solution:

String.format("First %s and then %s", "foo", "bar");

我觉得 sonarlint 只是在嘲笑我。

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

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

有什么想法吗?

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

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

I don't really understand whats going or why he complaints in the first place:

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


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

(如果计算成本很高,你仍然有性能问题。你可以考虑使用 if (log.isInfoLevel()) { ... } 守卫,或者使表达式计算变得惰性的东西;例如 Supplier<String>。但是最好的解决方案可能是避免记录那个昂贵的表达式。)


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

  • In the first version with {} the type of {} is evaluated at runtime.
  • In the 2nd with %s, %d you define the type at compile time.

If possible you should use a type to avoid misuse of placeholder variables and allow java compiler to do some additional checks.

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

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


最后,这个版本:

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

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