Log4j2:如何在不使用Throwable的情况下获得类名和行号?

nle07wnf  于 2022-11-06  发布在  其他
关注(0)|答案(3)|浏览(146)

我在Log4j 2上开发了一个 Package 器类。使用OSGi的声明性服务,我发布了一个自定义的日志服务,使用我自己的日志接口, Package 器类是实现。 Package 器类只用于编程地配置日志,消息格式化和添加一些方法,最后它调用Log4j 2的日志方法。
我想打印日志文件中请求的每个日志的源类/文件名和行号。选项%C/%F和%L只打印 Package 类中实际调用 log 方法的位置的信息。
因此,作为一种练习,我每次都将 new Throwable 作为参数传递,以便可以使用布局 %throwable{short.lineNumber}。但对于嵌入式应用程序来说,这是一个代价高昂的过程。
我的主要问题是获取行号,因为对于文件名,我至少可以从Log4j 2请求一个新的记录器,其中包含请求记录器服务的每个服务的名称,并将其保存在Map中。
有没有一个解决方案可以追溯调用者?我希望有一个类似的解决方案,可以用于那些不希望在记录器服务的每个使用者上都有LOG4j 2 jar的应用程序。仅供参考,我不想使用任何XML文件,所有的配置都是通过编程进行的。

2izufjch

2izufjch1#

您可以使用

StackTraceElement[] stes = Thread.currentThread().getStackTrace();

不过,我不确定这是否便宜得多。
我所做的是使每个消息都是唯一的(对于类),并避免包含行号。您可以在IDE中搜索唯一的消息以找到行号。类应该在记录器的名称中。

jpfvwuh4

jpfvwuh42#

Log4j2在内部遍历堆栈跟踪以提取位置信息。它通过为org.apache.logging.log4j.spi.ExtendedLogger#logMessage方法指定正确的FQCN(完全限定的类名)来知道在堆栈跟踪中的何处停止。
Log4j2包含一个为记录器 Package 器生成代码的工具。文档位于此处(在Custom Log Levels手册页中):http://logging.apache.org/log4j/2.x/manual/customloglevels.html#CustomLoggers
请尝试使用此工具生成记录器 Package ,并基于生成得代码创建自定义 Package .此生成得代码将使用正确得FQCN,并且能够生成正确得位置信息.

myss37ts

myss37ts3#

正如@ RemkoPopma所说,这里有一个简单的实现:
首先创建ExtendedLogger类:

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;

public class ExtLogWithLine extends ExtendedLoggerWrapper {
    private static final long serialVersionUID = 8239280349129059055L;

    // define your wrapper class here
    private static final String FQCN = WrapperLog.class.getName();

    private final ExtendedLoggerWrapper logger;

    private ExtLogWithLine(final Logger logger) {
        super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());
        this.logger = this;
    }

    public static ExtLogWithLine create(final String name) {
        final Logger wrapped = LogManager.getLogger(name);
        return new ExtLogWithLine(wrapped);
    }

    @Override
    public void debug(String info) {
        if (isDebugEnabled()) {
            logger.logIfEnabled(FQCN, Level.DEBUG, null, info, (Throwable) null);
        }
    }

    @Override
    public void info(String info) {
        if (isInfoEnabled()) {
            logger.logIfEnabled(FQCN, Level.INFO, null, info, (Throwable) null);
        }
    }

    @Override
    public void warn(String info) {
        if (isWarnEnabled()) {
            logger.logIfEnabled(FQCN, Level.WARN, null, info, (Throwable) null);
        }
    }

    @Override
    public void error(String info) {
        if (isErrorEnabled()) {
            logger.logIfEnabled(FQCN, Level.ERROR, null, info, (Throwable) null);
        }
    }
}

然后使用扩展记录器打印日志:

public class WrapperLog {

    public void testLog() {
       ExtLogWithLine logger = ExtLogWithLine.create("xxx");

       // log will print out with correct line number
       logger.info("see the line number");
    }
}

相关问题