java Log4j 2日志记录-保护子句还是参数化日志记录?

ars1skjm  于 2023-04-04  发布在  Java
关注(0)|答案(2)|浏览(179)

我检查了应用程序中的日志记录,发现其中很多都非常混乱,因为我使用了带有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);
h43kikqp

h43kikqp1#

在构造日志消息时,您使用StringBuilder进行了优化,但代码的可读性下降了。更重要的是,通过配置日志级别,日志消息可能会被完全丢弃,这意味着构造String完全是浪费时间。
您可以应用保护子句,如

//random other code

if (LOGGER.isDebugEnabled()) {
    StringBuilder globalSB = new StringBuilder();

     //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());
}

但这会在源代码中添加更多分散注意力的代码。
使用参数化日志,所有这些都被发送到日志库中。虽然log4j 1.x不知道参数化日志,但log4j2和slf4j都知道。

j8yoct9x

j8yoct9x2#

SLF4J和Log4j 2.x API:

  • 支持参数化日志记录,这其实是SLF4J引入的功能之一,之前的API(Jakarta Commons Logging,java.util.logging和Log4j 1.x)中没有的。
    *字符串连接如果消息级别不够具体,则不执行,
    *字符串串拼接不进行,除非配置了appender来发送消息(appender也可以有过滤器)。如果使用Log4j 2.x Core作为实现(使用任一API)和无垃圾日志记录,实际上没有创建拼接字符串:模式和参数被直接附加到每线程StringBuilder
  • 如果参数是Supplier s,则仅在记录消息时才计算它们。从Log4j 2.4(在LoggerLogBuilder中)和SLF4J 2.0(仅在LoggingEventBuilder中)起,可以使用供应商。

关于if (logger.isDebugEnabled())保护子句:它们不是必需的,实际上可以改变日志逻辑。
假设您为所有与网络相关的消息使用标记:

private static final Marker NET = MarkerManager.getMarker("NET");

Logback和Log4j 2.x Core都允许你记录所有至少像INFO一样具体或包含NET标记的内容(这需要Logback中的turbofilters和Log4j 2.x Core中的全局过滤器)。在这样的配置下,下面的语句将记录任何内容(DEBUG被禁用):

if (logger.isDebugEnabled()) {
    logger.debug(NET, "Receiving incoming message: {}", message);
}

同时将记录以下消息(应记录NET消息):

logger.debug(NET, "Receiving incoming message: {}", message);

相关问题