如何打印调用的根调用 class 名称?
how to print the root invoke class name of the invoke?
在log4j2中,有2个classes:
Common.java
public class Common {
protected static Logger logger = LogManager.getLogger("mts_logger");
public static void sayHi(String hi){
logger.info(hi);
}
}
Demo1.java:
public class Demo1 {
@Test
public void test1(){
Common.sayHi("hello");
}
}
打印的日志是:
2021-04-09 12:10:27.652 INFO -utils.Common.sayHi(Common.java:14) mts_logger Common.java - world
log4j2.xml 模式是:
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level -%l %c - %msg%n" />
我们可以看到日志只打印了Common.java,没有打印Demo1的class名字,我只是希望日志能显示调用的原始class名字方法“sayHi”,在这个例子中,class 名称是 Demo1。
如何配置 log4j2 然后它也可以显示“原始”调用class名称“Demo1”?
总之,如何在日志中打印出Demo1?
像这样实现Common.java
:
package com.mypackage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.StackLocatorUtil;
class Common {
protected static Logger logger = LogManager.getLogger("mts_logger");
public static void sayHi(String msg){
//using API available in log4j get the caller location
//use Fully qualified name of the Common class.
StackTraceElement ste = StackLocatorUtil.calcLocation("com.mypackage.Common");
logger.info(ste.toString() + ": " + msg);
}
}
根据您当前的模式,它将像这样记录:
2021-04-09 11:08:37.230 INFO -Common.sayHi(Test.java:20) -sayHi mts_logger - Demo1.test1(Test.java:26): hello
您可以删除 -%l
以避免打印 -Common.sayHi(Test.java:20) -sayHi
虽然您已经接受了 Onkar 的回答,但这并不是最好的方法。根据您的操作,有两种更好的方法。
正在创建记录器“包装器”。 Log4j 实际上在几个地方自己做了这个,例如,将 SLF4J 绑定到 Log4J 的 Log4jLogger。如果您查看 class,您会看到它声明了一个名为 FQCN 的变量。这被设置为包装器的名称 class,然后传递给所有 Logger 方法。 Log4j 将使用它来查找调用该 class 的堆栈帧。这将导致您继续使用现有模式,但具有正确的 class 名称。这类似于 Onkar 的回答,但它使用了一种接受 FQCN 的日志记录方法,因此您不必自己格式化堆栈跟踪元素。
你只需要为这件事包括调用者。为此,请使用 Log4j 2.13.0 中添加的 LogBuilder。为此你应该这样做:
package com.mypackage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.StackLocatorUtil;
public class Common {
protected static Logger logger = LogManager.getLogger("mts_logger");
public static void sayHi(String msg) {
StackTraceElement ste = StackLocatorUtil.getStackTraceElement(3);
logger.atInfo().withLocation(ste).log(msg);
}
}
与第一个选项一样,这也会导致 Log4j 在将这些信息包含在您的模式中时包含正确的 class、行和方法信息。如果您使用 Java 11,则可以使用 StackWalker 而不是 Log4j 的 StackLocatorUtil。
传递给 getStackTraceElement 的数字是相关堆栈帧需要上升的级别数。值为 1 将产生 StackLocatorUtil 的框架。值为 2 将 return 调用 SayHi 中 StackLocatorUtil 的堆栈帧,值为 3 应该是 sayHi 的调用者。此方法比搜索 FQCN 快得多,但这是您不知道堆栈帧数时的唯一选择。
在log4j2中,有2个classes:
Common.java
public class Common {
protected static Logger logger = LogManager.getLogger("mts_logger");
public static void sayHi(String hi){
logger.info(hi);
}
}
Demo1.java:
public class Demo1 {
@Test
public void test1(){
Common.sayHi("hello");
}
}
打印的日志是:
2021-04-09 12:10:27.652 INFO -utils.Common.sayHi(Common.java:14) mts_logger Common.java - world
log4j2.xml 模式是:
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level -%l %c - %msg%n" />
我们可以看到日志只打印了Common.java,没有打印Demo1的class名字,我只是希望日志能显示调用的原始class名字方法“sayHi”,在这个例子中,class 名称是 Demo1。 如何配置 log4j2 然后它也可以显示“原始”调用class名称“Demo1”?
总之,如何在日志中打印出Demo1?
像这样实现Common.java
:
package com.mypackage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.StackLocatorUtil;
class Common {
protected static Logger logger = LogManager.getLogger("mts_logger");
public static void sayHi(String msg){
//using API available in log4j get the caller location
//use Fully qualified name of the Common class.
StackTraceElement ste = StackLocatorUtil.calcLocation("com.mypackage.Common");
logger.info(ste.toString() + ": " + msg);
}
}
根据您当前的模式,它将像这样记录:
2021-04-09 11:08:37.230 INFO -Common.sayHi(Test.java:20) -sayHi mts_logger - Demo1.test1(Test.java:26): hello
您可以删除 -%l
以避免打印 -Common.sayHi(Test.java:20) -sayHi
虽然您已经接受了 Onkar 的回答,但这并不是最好的方法。根据您的操作,有两种更好的方法。
正在创建记录器“包装器”。 Log4j 实际上在几个地方自己做了这个,例如,将 SLF4J 绑定到 Log4J 的 Log4jLogger。如果您查看 class,您会看到它声明了一个名为 FQCN 的变量。这被设置为包装器的名称 class,然后传递给所有 Logger 方法。 Log4j 将使用它来查找调用该 class 的堆栈帧。这将导致您继续使用现有模式,但具有正确的 class 名称。这类似于 Onkar 的回答,但它使用了一种接受 FQCN 的日志记录方法,因此您不必自己格式化堆栈跟踪元素。
你只需要为这件事包括调用者。为此,请使用 Log4j 2.13.0 中添加的 LogBuilder。为此你应该这样做:
package com.mypackage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.util.StackLocatorUtil; public class Common { protected static Logger logger = LogManager.getLogger("mts_logger"); public static void sayHi(String msg) { StackTraceElement ste = StackLocatorUtil.getStackTraceElement(3); logger.atInfo().withLocation(ste).log(msg); } }
与第一个选项一样,这也会导致 Log4j 在将这些信息包含在您的模式中时包含正确的 class、行和方法信息。如果您使用 Java 11,则可以使用 StackWalker 而不是 Log4j 的 StackLocatorUtil。
传递给 getStackTraceElement 的数字是相关堆栈帧需要上升的级别数。值为 1 将产生 StackLocatorUtil 的框架。值为 2 将 return 调用 SayHi 中 StackLocatorUtil 的堆栈帧,值为 3 应该是 sayHi 的调用者。此方法比搜索 FQCN 快得多,但这是您不知道堆栈帧数时的唯一选择。