我有一段代码如下,
List<String> someList = new ArrayList<>();
someList.add("abc1");
someList.add("abc2");
someList.add("abc3");
someList.add("abc4");
someList.add("abc5");
someList.forEach(logger::debug);
someList.forEach(l -> logger.debug(l));
在方法引用样式中,输出如下-
[com.some.pkg.AppContext:1249] abc1
[com.some.pkg.AppContext:1249] abc2
[com.some.pkg.AppContext:1249] abc3
[com.some.pkg.AppContext:1249] abc4
[com.some.pkg.AppContext:1249] abc5
而对于 lambda,输出是预期的。
[com.some.pkg.AppContext:36] abc1
[com.some.pkg.AppContext:36] abc2
[com.some.pkg.AppContext:36] abc3
[com.some.pkg.AppContext:36] abc4
[com.some.pkg.AppContext:36] abc5
模式是[%logger{36}:%L]
此外,如果我使用 %F
,则方法引用会打印 ArrayList.java
,但 lambda 会打印预期的类。
我不确定我是否遗漏了什么或者这是 log4j2 的错误/限制。
最佳答案
我认为从 log4j2
来看,这是预期的行为。区别在于方法引用和 lambda 表达式在 java 中的执行方式不同。
根据 log4j2 documentation -
If one of the layouts is configured with a location-related attribute like HTML locationInfo, or one of the patterns %C or %class, %F or %file, %l or %location, %L or %line, %M or %method, Log4j will take a snapshot of the stack, and walk the stack trace to find the location information.
简单来说,log4j
使用stack trace
来确定日志语句的位置信息。
当AbstraceLogger
类的info()
、debug()
等方法被调用时,会查找当前的堆栈跟踪
以确定调用者的位置。
在方法引用的情况下,stack trace
如下所示 -
注意从顶部开始的第 3 行 - ArrayList
,第 1380 行。我认为第 2 行被忽略,因为它没有给出文件名和行号的有效值。
在 lambda 表达式的情况下,堆栈跟踪
看起来像 -
如您所见,两种情况下 debug()
方法的最后一个调用者是不同的,因此行号也是不同的。
使用您提供的代码,我还收到以下日志 -
com.some.pkg.AppContext:1380
com.some.pkg.AppContext:1380
com.some.pkg.AppContext:1380
com.some.pkg.AppContext:1380
com.some.pkg.AppContext:1380
com.some.pkg.AppContext:36
com.some.pkg.AppContext:36
com.some.pkg.AppContext:36
com.some.pkg.AppContext:36
com.some.pkg.AppContext:36
%F
模式的输出差异也与此解释有关。对于 %F
模式,堆栈跟踪
用于查找文件名。 Logger
不需要堆栈跟踪
查找。
关于java - Log4j2 在方法引用调用中打印实用程序类行号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48329457/