Java 日志写入法中的声纳投诉

Java 日志写入法中的声纳投诉,java,sonarlint,Java,Sonarlint,Sonarint显示以下错误: “前提条件”和日志参数不应要求求值 合规解决方案: log(Level.SEVERE,“出错:{0}”,消息) 让我们试试: log.info(String.format("Execution of method %s finished in %d ms", pointcut.getSignature().getName(), ms)) 应正确使用Printf样式格式字符串 合规解决方案: 格式(“先是%s,然后是%s”,“foo”,“bar”) 我觉得索纳林特

Sonarint显示以下错误:

“前提条件”和日志参数不应要求求值

合规解决方案:

log(Level.SEVERE,“出错:{0}”,消息)

让我们试试:

log.info(String.format("Execution of method %s finished in %d ms", pointcut.getSignature().getName(), ms))
应正确使用Printf样式格式字符串

合规解决方案:

格式(“先是%s,然后是%s”,“foo”,“bar”)

我觉得索纳林特只是在嘲笑我

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

log.info("Execution of method {0} finished in {1} ms", pointcut.getSignature().getName(), ms);
有什么想法吗?

  • 在具有{}的第一个版本中,{}的类型在运行时进行计算
  • 在第二个示例中,使用%s,%d可以在编译时定义类型
如果可能,您应该使用一个类型来避免占位符变量的误用,并允许java编译器执行一些额外的检查

我真的不明白到底发生了什么,也不明白他为什么抱怨:

log.info("Execution of method {0} finished in {1} ms", pointcut.getSignature().getName(), ms);
第一个示例中出现投诉的原因是您正在无条件地进行大量工作来构造日志消息。如果日志级别高于INFO,则工作将被浪费


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

(如果计算代价高昂,则仍然存在性能问题。您可以考虑使用
If(log.isInfoLevel()){…}
guard,或者使用某种方法使表达式计算变得懒惰;例如
供应商
。但最好的解决方案可能是避免记录代价高昂的表达式。)


第二个示例中的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不够聪明,无法解决这个问题。

使用SLF4J占位符,
LOGGER.info(“方法{}的执行在{}ms内完成”,variableOne,VariableTwo)
如果您使用的是SLF4J,则大括号内的索引是不必要的,Sonar的建议是使用java.util.logging包的代码
java.util.logging.Logger
使用字符串。其他日志框架则没有;他们使用空的
{}
占位符,正如其他评论所说。可能类似于
log.info(()->String.format(“方法%s的执行在%d ms中完成”,pointcut.getSignature().getName(),ms))
(不确定Sonar对此有何看法)的投票结果,但是,我认为你应该把问题的标题改成更能描述你的问题。