log4j 如何使用Java在日志文件中写入调用者位置信息,而不影响性能?

6tdlim6h  于 8个月前  发布在  Java
关注(0)|答案(4)|浏览(64)

如何使用Java和log4j在日志文件中写入调用者位置信息(Java源文件和行),而不影响性能?log4j允许你在日志文件中写入这样的信息,但是它使用堆栈跟踪来获取它的信息,每次发出一条日志语句,什么会导致性能下降。我正在寻找一个性能友好的替代方案,比如在编译时获取位置信息,而不是在运行时。是否可以使用注解来实现这一点?或者是其他的技术?

mv1qrgav

mv1qrgav1#

在构建过程中替换某些占位符(如此代码段中的$filename$$linenumber$),如何?

logger.info("The original message... $filename$ $linenumber$");

要替换文件名,在版本控制系统中使用关键字替换就足够了。免责声明:这是我的第一次尝试,我自己从来没有尝试过。

imzjd6km

imzjd6km2#

如果你在slf 4j中使用log4j/logback,对于任何寻找更新解决方案的人来说,我写了一个maven-plugin来解决这个问题,同时也不会产生任何性能问题:https://github.com/PhilKes/slf4j-caller-info-maven-plugin
此插件在编译时将类名、方法名和源代码行号注入所有SLF 4J日志语句(参见配置)。你所需要做的就是将callerInformation MDC参数添加到你的日志模式中,并将插件添加到你的pom.xml中:

<plugin>
 <groupId>io.github.philkes</groupId>
 <artifactId>slf4j-caller-info-maven-plugin</artifactId>
 <version>1.1.0</version>
 <executions>
   <execution>
     <goals>
        <goal>inject</goal>
     </goals>
   </execution>
 </executions>
</plugin>
h5qlskok

h5qlskok3#

我同意罗布的观点,这通常是不必要的。通常在日志消息中有一些不同的字符串,搜索它将到达源。有了好的IDE,这真的很快。
现在,考虑到这个问题,这是一个可能的解决方案:

Class Foo
    void bar()
        new Logger(){} . warn("blah");

对于运行时的每个日志操作,都会创建一个新对象-这不是问题。
对于包含这样的日志语句的源代码的每一行,创建一个新类。可能太多了
魔术是这样的:

abstract public class Logger
    static Map<Class, String> sourceInfo = new ...
    public Logger()
        Class thisClass = this.getClass();
        String info = sourceInfo.get(thisClass);
        if(info==null)
             info = ... // init from stack trace
             sourceInfo.put(thisClass,info)
        this.info = info

     public void warn(msg)
        log(WARN, this.info,msg)
7ivaypg9

7ivaypg94#

如果您正在寻找与Phil's SLF4J plugin对应的Log4j API,那么从Log4j API 2.10开始,就有一个LogBuilder#withLocation方法,它允许工具将位置信息注入字节码。
最近,我们发布了log4j-maven-transform-plugin,它对类文件进行后处理,并取代了经典的日志调用,例如:

public void helloLog() {
    logger.info(MarkerManager.getMarker("NET"), "Sending {} bytes of data.", 1000);
}

插入到LogBuilder调用中并注入位置:

private static final StackTraceElement[] locations = {
        new StackTraceElement("org.apache.logging.log4j.HelloWorld", "HelloWorld.java", "helloLog", 1234)
};

public void helloLog() {
    logger.atInfo()
          .withLocation(locations[0])
          .withMarker(MarkerManager.getMarker("NET"))
          .log("Sending {} bytes of data.", 1000);
}

这是非常简单的使用,你只需要添加:

<plugin>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-transform-maven-plugin</artifactId>
        <version>0.1.0</version>
        <executions>
          <execution>
            <goals>
              <goal>process-classes</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

您的Maven插件。

相关问题