java - 内置字符串格式与字符串连接作为日志记录参数

标签 java string logging concatenation sonarlint

我正在使用 SonarLint这向我显示了以下行中的一个问题。

LOGGER.debug("Comparing objects: " + object1 + " and " + object2);

旁注:包含此行的方法可能会被频繁调用。

这个问题的描述是

"Preconditions" and logging arguments should not require evaluation (squid:S2629)

Passing message arguments that require further evaluation into a Guava com.google.common.base.Preconditions check can result in a performance penalty. That's because whether or not they're needed, each argument must be resolved before the method is actually called.

Similarly, passing concatenated strings into a logging method can also incur a needless performance hit because the concatenation will be performed every time the method is called, whether or not the log level is low enough to show the message.

Instead, you should structure your code to pass static or pre-computed values into Preconditions conditions check and logging calls.

Specifically, the built-in string formatting should be used instead of string concatenation, and if the message is the result of a method call, then Preconditions should be skipped altoghether, and the relevant exception should be conditionally thrown instead.

Noncompliant Code Example

logger.log(Level.DEBUG, "Something went wrong: " + message);  // Noncompliant; string concatenation performed even when log level too high to show DEBUG messages

LOG.error("Unable to open file " + csvPath, e);  // Noncompliant

Preconditions.checkState(a > 0, "Arg must be positive, but got " + a); // Noncompliant. String concatenation performed even when a > 0

Preconditions.checkState(condition, formatMessage());  //Noncompliant. formatMessage() invoked regardless of condition

Preconditions.checkState(condition, "message: %s", formatMessage()); // Noncompliant

Compliant Solution

logger.log(Level.SEVERE, "Something went wrong: %s", message);  // String formatting only applied if needed

logger.log(Level.SEVERE, () -> "Something went wrong: " + message); //since Java 8, we can use Supplier , which will be evaluated lazily

LOG.error("Unable to open file {}", csvPath, e);

if (LOG.isDebugEnabled() {   LOG.debug("Unable to open file " + csvPath, e);  // this is compliant, because it will not evaluate if log level is above debug. }

Preconditions.checkState(arg > 0, "Arg must be positive, but got %d", a);  // String formatting only applied if needed

if (!condition) {   throw new IllegalStateException(formatMessage()); // formatMessage() only invoked conditionally }

if (!condition) {   throw new IllegalStateException("message: " + formatMessage()); }

我不能 100% 确定我是否理解正确。那么为什么这真的是一个问题。特别是关于使用字符串连接时性能影响的部分。因为我经常读到字符串连接比格式化要快。

编辑:也许有人可以解释一下

LOGGER.debug("Comparing objects: " + object1 + " and " + object2);

LOGGER.debug("Comparing objects: {} and {}",object1, object2);

在后台。因为我认为 String 在传递给方法之前会被创建。正确的?所以对我来说没有区别。但显然我错了,因为 SonarLint 在提示它

最佳答案

我相信你在那里有你的答案。

在条件检查之前计算连接。因此,如果您有条件地调用您的日志框架 10K 次并且所有这些都评估为 false,那么您将毫无理由地连接 10K 次。

同时检查 this topic .并查看 Icaro 的回答评论。

看看StringBuilder也是。

关于java - 内置字符串格式与字符串连接作为日志记录参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42388341/

相关文章:

string - Swift 如何使字符串右对齐

node.js - Winston:如何同时记录到控制台和系统日志传输?

java - 列表列表上的等于方法

java - 在 00 :00 format? 中创建一个以秒为单位的递增计时器

java - 如何正确调用这个方法呢?

python color-logs(与其他库)配置问题

Azure Log Analytics 1 个日志条目 = 1 行

java - Tomcat 9.0.34 的 Gradle 插件

c++ - 如何使用引用调用从 C++ 函数中获取 char** 类型变量的值?

r - 如何使用 R 将 rtf 字符串转换为纯文本?