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

41zrol4v  于 2023-04-04  发布在  Java
关注(0)|答案(6)|浏览(112)

在这里帮我一个忙:)
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方法的静态字符串的成本(尽管更低)?

hsvhsicv

hsvhsicv1#

我会试着从另一个Angular 提出我的看法

参数化日志究竟有什么好处?

您只需将**toString()调用字符串连接**延迟到真正需要的时候,也就是您真正需要记录消息的时候。这样可以在禁用特定日志记录操作时优化性能。如果不确定,请检查source code for SLF4J

参数化日志是否会使guards在所有情况下都无用?

不知道

在哪些情况下日志保护会有用?

当存在其他潜在的昂贵操作时。
例如(在禁用此特定日志记录操作的情况下),如果我们有 no logging guard

logger.debug("User name: {}", getUserService().getCurrentUser());

1.我们将支付obj = getUserService().getCurrentUser()开始的费用
1.我们将保存成本从"User name: " + obj.toString()
如果我们 * 使用logging guard*:

if (logger.isDebugEnabled()) {
    logger.debug("User: {}", getUserService().getCurrentUser());
}

1.我们将支付logger.isDebugEnabled()的费用
1.我们将从obj = getUserService().getCurrentUser()保存成本
1.我们将保存成本从"User name: " + obj.toString()
在后一种情况下,当启用这个特定的日志记录操作时,我们将以检查isDebugEnabled()两次的代价来保存这两种成本。
注意:这只是一个例子,并不试图在这里讨论好的/坏的做法。

3gtaxfhh

3gtaxfhh2#

写和阅读所有这些if(logger.isDebugEnabled()) {}可能花费的时间和它们保存的时间一样多。
当然,调用log方法不是免费的,但调用isDebugEnabled()也是如此。因此,如果使用这种模式,您将为每个活动的log语句支付更多费用(因为日志框架将检查级别两次)。
它也会使代码变得混乱。
在实践中,我还没有发现性能损失大到足以让人烦恼。
如果日志记录对您来说太慢,那么编写一个非阻塞的appender,它将日志事件推入队列,而不需要进行一些检查,并使用后台线程来处理它们。
背景:标准的appender都是同步的,因此在多线程应用程序中进行日志记录可能会导致许多小的暂停,其中所有线程都在等待将日志消息写入文件。

vxf3dgd4

vxf3dgd43#

由于创建了字符串,因此未使用保护。
相反,它通常用于避免潜在的昂贵参数表达式,例如entry[i].retrieveExtendedDebugInformation().formatNicely()。为此,logback确保仅在实际打印日志消息时才计算参数,而log4j总是在调用debug()之前计算参数。
这里唯一的候选者是String.valueOf(entry[i]),它也不是很昂贵,所以你可以说这个保护是完全不必要的。

k3bvogb1

k3bvogb14#

像这样的日志语句的问题是:

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

它将做大量的工作来将值连接到String中,如果调试日志记录关闭,则永远不会使用String。因此,在这种情况下,在执行这一行之前检查调试日志记录是否打开是有益的。当您只是传递参数时:

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

则不需要建立一个从未使用过的String,不需要检查;仅仅将参数传递给方法并不具有非常高的开销。
请注意,如果日志记录语句中的参数表达式相对昂贵,则首先检查日志记录级别可能仍然是有益的。

2nbm6dog

2nbm6dog5#

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

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

我哭了。
我希望创建静态字符串的成本低到对99%的用户来说微不足道。

wn9m85ua

wn9m85ua6#

logger.isDebug()的另一种替代方法是使用“lazy logging”或传递lambda表达式[ link ]:

logger.trace("The user {} has {} dollars available", 
    () -> person.id(), 
    () -> remoteService.getBalance(person));

相关问题