Java 即使使用slf4j,您是否应该保护日志记录?

Java 即使使用slf4j,您是否应该保护日志记录?,java,performance,logging,slf4j,Java,Performance,Logging,Slf4j,在这里的辩论中帮助我……) 这里的slf4j站点表明,由于参数化日志记录,日志保护是不必要的。也就是说,不要写: if(logger.isDebugEnabled()) { logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); } 你可以逃脱: Object entry = new SomeObject(); logger.debug("The entry is {}.", entry); 这真的没

在这里的辩论中帮助我……)

这里的slf4j站点表明,由于参数化日志记录,日志保护是不必要的。也就是说,不要写:

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

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

这真的没问题吗,还是会导致创建传递给跟踪方法的静态字符串的成本(尽管更低)?

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

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


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

如果(logger.isDebugEnabled()){}编写和读取所有这些
if(logger.isDebugEnabled()){}
可能会花费与它们节省您同样多的时间

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

它还使代码混乱

在实践中,我还没有发现对表现的惩罚会大到足以令人烦恼的程度

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


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

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

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
将值连接到
字符串
,这将做大量工作,如果调试日志记录处于关闭状态,则永远不会使用该字符串。因此,在这种情况下,在执行这一行之前检查调试日志记录是否打开是有益的。当您只是传递参数时:

logger.debug("The entry is {}.", entry);
这样就不必构建一个从未使用过的
字符串
,也不需要进行检查;仅仅将参数传递给方法不会有很高的开销


请注意,如果日志语句中的参数表达式相对昂贵,那么最好先检查日志记录级别。

由于创建了字符串,因此未使用保护

相反,它通常用于避免潜在的昂贵参数表达式,如
entry[i].retrieveextendededebuginformation().formatwelly()
。为此,logback确保只有在实际打印日志消息时才计算参数,而log4j总是在调用debug()之前计算参数


这里唯一的候选者是
String.valueOf(entry[i])
,它也不是很贵,因此您可以提出一个论点,即这个防护完全不必要。

我将试着从另一个角度讲我的两分钱

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

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

参数化日志记录是否会使防护在所有情况下都无效?

没有

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

当存在其他潜在的昂贵操作时

例如(在禁用此特定日志操作的情况下),如果我们没有日志保护

  • 我们将
    obj=getUserService().getCurrentUser()
  • 我们可以通过
    “用户名:”+obj.toString()
  • 如果我们使用日志保护:

  • 我们将支付
    logger.isDebugEnabled()
  • 我们将节省
    obj=getUserService().getCurrentUser()的成本
  • 我们可以通过
    “用户名:”+obj.toString()
  • 在后一种情况下,如果启用此特定日志记录操作,我们将以两次检查
    isDebugEnabled()
    为代价节省这两项成本


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

    谢谢,我也是这么想的。。在我给你一个加号之前,我将等待着看一下一般用户的想法:)我喜欢关于附加器的提示,这对我们来说可能是个问题。我认为,通过一些JIT优化,“调用日志方法”和“调用isDebugEnabled()”实际上都是免费的。我不确定,但如果是为sl4jf提供实际高性能实现的人,我会在禁用级别的rutime中放置一个没有op方法的实现,以便JIT可以删除调用。好的-这是有意义的,这是另一种观点。所以在你看来,这是一个判断是否需要保护的决定,而保护只应用于相对罕见(昂贵)的操作?。。参数的引入减少了这些操作的数量。是的,并且取决于操作的成本,通常只有在循环内跟踪语句时才有意义。有人甚至可能会争辩说,如果您的调试语句非常昂贵,以至于即使在更高的日志级别上,它们也会减慢类的速度,那么您没有正确地使用log.debug,特别是,您可能在(condition){log.debug(complexidexpression);doSomething();}
    的同时(condition){log.debug(complexing);doSomething();},而您应该在执行
    log.debug(complexidexpression);while(condition){log.trace(simpleExpression);doSomething();}
    。但我不是狂热者,我承认我经常写一个守卫。“不是很贵”对于一个有大量日志语句的程序来说,仍然是非常昂贵的。logback如何防止在方法调用之前对参数求值?在log4j的
    log.debug(“条目是:”+Entry);
    中,必须在调用
    l之前构造参数
    
    logger.debug("User name: {}", getUserService().getCurrentUser());
    
    if (logger.isDebugEnabled()) {
        logger.debug("User: {}", getUserService().getCurrentUser());
    }