我检查了应用程序中的日志记录,发现其中很多都非常混乱,因为我使用了带有append和guard子句的StringBuilders来检查是否要构建字符串。
ie
StringBuilder globalSB = new StringBuilder();
//random other code
//place that needs to be logged
globalSB.setLength(0);
globalSB.append("something").append("other something").().().().append("end"); //<--imagine theres a lot of appending of variables/objects etc
LOGGER.info(globalSB.toString());
我最近遇到了这个问题,answer建议使用参数化日志记录,尽管不清楚是slf 4j还是log4j。许多其他答案建议直接使用slf 4j,因为它会在实际构建字符串之前检查是否需要发生字符串连接(日志级别);或者由于检查调试级别的开销是微不足道的,所以不管怎样都直接使用保护子句。
我有点想知道log4j 2 * 能做什么,而不是slf 4j * 能做什么,所以我检查了一些其他的问题/答案/评论,发现一些建议log4j 2的新版本支持类似于slf 4j的行为和懒惰(?)字符串构建(使用参数化日志记录)以及Java 8 lambda对懒惰日志记录的支持。
是否必须使用保护子句(然后使用stringbuilder等),或者对于昂贵的方法调用,使用lambdas的参数化日志记录也提供相同的行为(除非日志级别指示需要,否则不创建字符串)?我希望得到答案,因为许多其他帖子似乎有不同的意见。
byte[] rawIp; //assume it has some value
int port; //assume it has some value
String msgReceived;//assume it has some value
LOGGER.debug("{},{} sent {}", ()->rawIp.convertToString(), port, msgReceived);
2条答案
按热度按时间h43kikqp1#
在构造日志消息时,您使用StringBuilder进行了优化,但代码的可读性下降了。更重要的是,通过配置日志级别,日志消息可能会被完全丢弃,这意味着构造String完全是浪费时间。
您可以应用保护子句,如
但这会在源代码中添加更多分散注意力的代码。
使用参数化日志,所有这些都被发送到日志库中。虽然log4j 1.x不知道参数化日志,但log4j2和slf4j都知道。
j8yoct9x2#
SLF4J和Log4j 2.x API:
java.util.logging
和Log4j 1.x)中没有的。*字符串连接如果消息级别不够具体,则不执行,
*字符串串拼接不进行,除非配置了appender来发送消息(appender也可以有过滤器)。如果使用Log4j 2.x Core作为实现(使用任一API)和无垃圾日志记录,实际上没有创建拼接字符串:模式和参数被直接附加到每线程
StringBuilder
,Supplier
s,则仅在记录消息时才计算它们。从Log4j 2.4(在Logger
和LogBuilder
中)和SLF4J 2.0(仅在LoggingEventBuilder
中)起,可以使用供应商。关于
if (logger.isDebugEnabled())
保护子句:它们不是必需的,实际上可以改变日志逻辑。假设您为所有与网络相关的消息使用标记:
Logback和Log4j 2.x Core都允许你记录所有至少像
INFO
一样具体或包含NET
标记的内容(这需要Logback中的turbofilters和Log4j 2.x Core中的全局过滤器)。在这样的配置下,下面的语句将不记录任何内容(DEBUG
被禁用):同时将记录以下消息(应记录
NET
消息):