如何使用 Java 和 log4j 在日志文件中写入调用者位置信息(Java 源文件和行),而不影响性能? log4j允许您在日志文件中写入此类信息,但它使用堆栈跟踪来获取该信息,每次发出日志语句时,这会导致性能下降。 我正在寻找一种性能友好的替代方案,例如在编译时而不是在运行时获取位置信息。可以使用注释来实现这一点吗?或者也许还有其他技术?
如何将其作为构建过程的一部分来替换某些占位符,例如此代码片段中的
$filename$
和 $linenumber$
。
logger.info("The original message... $filename$ $linenumber$");
要替换文件名,用您的版本控制系统进行关键字替换可能就足够了。免责声明:这只是我的想法,我自己从未尝试过。
我同意 Rob 的观点,一般来说这是没有必要的。通常,日志消息中会有一些不同的字符串,搜索它就能找到源头。有了一个好的 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)
对于任何寻求更新解决方案的人(如果您将 log4j/logback 与 slf4j 一起使用),我编写了一个 maven-plugin 来解决此问题,同时也不会产生任何性能问题: https://github.com/PhilKes/slf4j-caller-info-maven-plugin
此插件在编译时将类名、方法名称和源代码行号注入到所有 SLF4J 日志语句中(请参阅配置)。 您需要做的就是将
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>