Java记录API开销

| 我已经阅读了一些有关使用Java记录调试消息的各种方式的信息,而从C背景出发,我的担心如下: 这些库在禁用日志记录的情况下(例如生产环境)要求最小的开销,但是由于仍会评估其“ 0”函数的参数,因此我担心的是,在实际情况下的开销实际上是可以忽略不计的。 例如,
log(myobject.toString(), \"info message\")
仍然有计算
myobject.toString()
的开销,即使log函数本身不执行任何操作,其开销也可能很大。 有谁能解决这个问题? PS:对于那些想知道为什么我提到C背景的人:C使您可以使用预处理器宏和编译时指令,这些指令将完全删除与编译时调试相关的所有代码,包括宏参数(根本不会出现)。 编辑: 阅读了第一批答案后,似乎Java显然没有任何可以解决这个问题的方法(请考虑在每个CPU都至关重要的移动环境中,将大数的余弦记录在一个大循环中)。因此,我补充说,我什至会寻求基于IDE的解决方案。我的最后一招是构建类似“查找全部/替换”宏的内容。 我首先认为,也许从面向方面的框架中获取一些东西会有所帮助... 任何人 ?     
已邀请:
我认为log4j FAQ很好地解决了这个问题:   对于某些记录器l来说,
l.debug(\"Entry number: \" + i + \" is \" + String.valueOf(entry[i]));
     产生了构造消息参数的成本,该消息参数将整数i和entry [i]都转换为字符串,并连接中间字符串。这与是否记录消息无关。      如果您担心速度,请写
 if(l.isDebugEnabled()) {
     l.debug(\"Entry number: \" + i + \" is \" + String.valueOf(entry[i]));
 }
     这样,如果禁用了记录器l的调试,则不会产生参数构造的成本。另一方面,如果记录器启用了调试,则将产生两次评估该记录器是否启用的成本:一次在debugEnabled中,一次在调试中。这是微不足道的开销,因为评估记录器所需的时间不到实际记录一条语句的时间的1%。 在这里,使用保护子句是避免字符串构造的通用方法。 其他流行的框架(例如slf4j)采用使用格式化的字符串/参数化消息的方法,因此除非需要,否则不会忽略消息。     
现代日志记录框架具有变量替换。然后,您的日志记录如下所示:
log.debug(\"The value of my first object is %s and of my second object is %s\", firstObject, secondObject).
然后,仅在将日志记录设置为调试时才执行给定对象的toString()。否则,它将仅忽略参数并返回。     
答案很简单:不要在日志调用本身中调用昂贵的方法。另外,如果无法避免,请在记录调用周围使用防护措施。
 if(logger.isDebugEnabled()) {
    logger.debug(\"this is an \"+expensive()+\" log call.\");
 }
就像其他人指出的那样,如果您的日志记录框架中有可用的格式设置(例如,如果您使用的是一种足够现代的格式来支持它,那么应该是其中的每一种,但不是),则应该依靠有助于在记录时支付费用。如果您选择的框架尚不支持格式设置,请切换或编写自己的包装器。     
没错,评估ѭ0调用的参数可能会增加不必要的开销,并且可能会很昂贵。 这就是为什么大多数理智的日志记录框架还提供一些字符串格式化功能的原因,因此您可以编写如下内容:
log.debug(\"Frobnicating {0}\", objectWithExpensiveToString);
这样,您唯一的开销就是调用
debug()
。如果取消激活该级别,则不执行任何操作;如果已激活该级别,则解释格式字符串,调用
objectWithExpensiveToString()
上的
toString()
,并将结果插入到格式字符串中,然后记录。 一些日志语句使用
MessageFormat
样式占位符(
{0}
),其他日志语句使用
format()
样式占位符(
%s
),而另一些则可能采用第三种方法。     
您可以使用带有断言的有趣方式(尽管有点冗长)。断言打开时,将有输出和开销,断言关闭时,将没有输出,并且绝对没有开销。
public static void main(String[] args) {
    assert returnsTrue(new Runnable() {
        @Override
        public void run() {
            // your logging code
        }
    });
}

public static boolean returnsTrue(Runnable r) {
    r.run();
    return true;
}
这里需要returnTrue()函数,因为我不知道使表达式返回true的更好方法,并且assert需要一个布尔值。     

要回复问题请先登录注册