即使使用slf4j,你应该保护你的日志吗?

时间:2011-12-09 10:38:29

标签: java performance logging slf4j

在这里辩论帮助我.. :)

这里的slf4j站点http://www.slf4j.org/faq.html#logging_performance表示由于参数化日志记录,不需要日志记录保护。即而不是写作:

if(logger.isDebugEnabled()) {
  logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

你可以逃脱:

Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);

这是否真的没问题,或者是否会产生(虽然更低)创建传递给trace方法的静态字符串的成本..?

5 个答案:

答案 0 :(得分:45)

我会尝试从另一个角度来看待我的两分钱

参数化日志记录的好处是什么?

您只需推迟 toString()调用字符串连接,直到确实需要为止,这时您必须记录消息。这将在禁用特定日志记录操作时优化性能。如果不确定,请检查source code for SLF4J

参数化日志记录是否会使警卫在所有情况下都无用?

没有。

在哪些情况下,伐木卫兵会被使用?

当还有其他潜在的昂贵操作时。

例如(如果禁用此特定日志记录操作),如果我们没有日志记录保护

logger.debug("User name: {}", getUserService().getCurrentUser());
  1. 我们支付来自obj = getUserService().getCurrentUser()
  2. 的费用
  3. 我们会从"User name: " + obj.toString()
  4. 中节省费用

    如果我们使用日志记录保护

    if (logger.isDebugEnabled()) {
        logger.debug("User: {}", getUserService().getCurrentUser());
    }
    
    1. 我们支付 logger.isDebugEnabled()
    2. 的费用
    3. 我们保存 obj = getUserService().getCurrentUser()
    4. 的费用
    5. 我们会从"User name: " + obj.toString()
    6. 中节省费用

      在后一种情况下,当启用此特定日志记录操作时,我们会以检查isDebugEnabled()两次为代价来节省成本。

      注意:这只是一个例子,而不是在这里讨论好/坏做法。

答案 1 :(得分:17)

编写和阅读所有这些if(logger.isDebugEnabled()) {}可能会花费他们为您节省的时间。

当然,调用log方法并不是免费的,但调用isDebugEnabled()也是如此。因此,如果使用此模式,则为每个活动的日志语句支付更多费用(因为日志记录框架将检查级别两次)。

它也使代码混乱。

在实践中,我没有发现性能损失足以打扰。

如果日志记录对您来说太慢,请编写一个非阻塞appender,将日志事件推送到队列中,而不需要几次检查,并使用后台线程来处理它们。

背景:标准的appender都是同步的,因此登录多线程应用程序会导致许多小的暂停,所有线程都会等待将日志消息写入文件。

答案 2 :(得分:8)

由于字符串创建,未使用防护。

相反,它通常用于避免可能昂贵的参数表达式,如entry[i].retrieveExtendedDebugInformation().formatNicely()。为此,logback确保仅在实际打印日志消息时评估参数,而log4j在调用debug()之前始终评估参数。

这里唯一的候选人是String.valueOf(entry[i]),这也不是很贵,所以你可以说这个守卫是完全没必要的。

答案 3 :(得分:4)

像这样的日志记录语句的问题:

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

是要将值连接到String会做很多工作,如果调试日志记录关闭则不会使用它。因此,在这种情况下,检查调试日志记录是否在执行此行之前是有益的。当你只是传递参数时:

logger.debug("The entry is {}.", entry);

然后它不需要构建一个从未使用过的String,并且不需要检查;只是将参数传递给方法没有很高的开销。

请注意,如果在日志记录语句中对参数使用相对昂贵的表达式,则首先检查日志记录级别可能仍然有用。

答案 4 :(得分:3)

请不要使用if语句,因为每次我查看这样的代码

if (logger.isDebug()) {
   logger.debug("Of course it's debug {}", sadFace);
}
我哭了。

我希望创建静态字符串的成本非常低,对99%的用户来说都是微不足道的。