Java 如何打印调用的根调用类名?

Java 如何打印调用的根调用类名?,java,log4j2,Java,Log4j2,在log4j2中,有两个类: 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

在log4j2中,有两个类:

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的类名,我只是希望日志能够显示调用方法“sayHi”的原始类名,在本例中,类名是Demo1。 如何配置log4j2,然后它也可以显示“原始的”调用类名“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
根据您当前的模式,它将如下记录:

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的。如果查看该类,您将看到它声明了一个名为FQCN的变量。这被设置为包装类的名称,然后传递给所有记录器方法。Log4j将使用它来查找调用该类的堆栈帧。这将导致您继续使用现有模式,但具有正确的类名。这与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在模式中包含正确的类、行和方法信息时包含这些信息。如果您使用的是Java11,那么可以使用StackWalker而不是Log4j的StackLocatorUtil


    传递给GetStackTraceeElement的数字是相关堆栈帧所需的级别数。值为1将生成StackLocatorUtil的帧。值为2将返回调用SayHi中StackLocatorUtil的堆栈帧,值为3将是SayHi的调用方。此方法比搜索FQCN快得多,但当您不知道堆栈帧数时,这是唯一的选择。

    谢谢您,onkar,这是最好的答案,您救了我的命!!