我有一段代码如下,
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的错误/限制。
答案 0 :(得分:1)
我认为从log4j2
开始,这是预期的行为。由于在java中执行方法引用和lambda表达式的方式不同,因此存在差异。
根据log4j2 documentation -
如果其中一个布局配置了与位置相关的属性 像HTML locationInfo,或其中一个模式%C或%class,%F或 %file,%l或%location,%L或%line,%M或%方法,Log4j将采用 堆栈的快照,并遍历堆栈跟踪以查找位置 信息。
简单来说,log4j
使用stack trace
来确定日志语句的位置信息。
当调用info()
类的debug()
,AbstraceLogger
等任何方法时,它会查找当前stack trace
以确定调用方的位置。
如果是方法参考,stack trace
如下所示 -
注意顶部的第3行 - ArrayList
,第1380行。我认为第2行被忽略,因为它没有给出文件名和行号的有效值。
如果是lambda表达式,stack trace
看起来像 -
正如您所看到的,两种情况下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
模式,stack trace
用于查找文件名。 Logger
不需要stack trace
查询。