SLF4J:(不)记日志的最快的方法

(不)记日志的最快的方法?

SLF4J已经提供了很快捷的日志记录方法,这里需要讨论在使用SLF4J记日志,或者根据参数配置其不记日志时的性能改进可能。

原文来自:http://www.slf4j.org/faq.html#logging_performance

SLF4J提供一个名为参数化日志的高级特性,可以显著提高在配置为关闭日志的情况下的日志语句性能。

经常我们会写这样的调试语句:
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

在这个语句中,我们需要花费小小的性能代价用于构建调试消息的参数,上面的例子中包括转换整数i和entry[i]为字符串,连接临时字符串,这些操作无论最后该日志是否会记录下来都需要进行,如果在特殊情况下对应的参数构造时需要进行额外的操作,则可能造成更大的性能损耗。

避免相关参数构造开销的方法是在外面加一个判断,例如:

if(logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}
上面的这种方式在调试日志被禁用的情况下会避免参数的构造开销,但是从另外一方面来说,如果调试开关被打开,将会需要进行两次判断调试日志是否可用:一次是在debugEnable的判断中,一次是在debug方法的执行中。这个代价其实微乎其微,判断能否记日志的动作可能连最后记日志的时间的1%都不到。

更好的方法是使用参数化消息。

有一种基于消息格式化的非常方便的可选方案.假设entry是一个对象,你可以这样写:
Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);

在判断是否需要记日志之后,只有在需要的情况下,对应的日志信息转换才会发生,将会将“{}”替换成entry的字符串形式。也就是说,使用这种形式在日志被禁用的情况下并不会发生参数的构造。
下面的两行代码将会产生同样的输出,然而在禁用日志的情况下,后面的形式至少比前面的形式性能提高30倍。
logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);

同样支持两个参数,如下例:
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);


如果有三个或更多参数,可以使用Object...变量,例如:
logger.debug("Value {} was inserted between {} and {}.", newVal, below, above);
这种形式将会构造一个Object[](Object数组),这会有极小的隐藏性能代价。第一个和第二个参数不会导致这种隐藏性能付出。
如果仅使用Object...变量,slf4j-api将会更小、更整洁。

数组类型的参数,包括多维数组也可以支持。
SLF4J使用其自有的消息格式化实现,比Java平台的标准方法快10倍,但是这也同样导致了SLF4J的方式是非标准和扩展性降低。
关于 "{}"转义:

SLF4j仅支持在{后面紧跟},例如:

logger.debug("Set {1,2} differs from {}", "3");

将会输出:"Set {1,2} differs from 3". 
 
logger.debug("Set {1,2} differs from {{}}", "3");

将会输出:"Set {1,2} differs from {3}". 
如果要输出"{}"则仅需要在{前面加上转移符"\",例如: 
logger.debug("Set \\{} differs from {}", "3");

将会输出s "Set {} differs from 3".

注意在Java中反斜杠需要写作: '\\'.

例如:
logger.debug("File name is C:\\\\{}.", "file.zip");

将输出:"File name is C:\file.zip".

猜你喜欢

转载自caichaowei.iteye.com/blog/1684520