如何使用 Java 和 log4j 在日志文件中写入调用者位置信息(Java 源文件和行),而不影响性能?
log4j允许您在日志文件中写入此类信息,但它使用堆栈跟踪来获取该信息,每次发出日志语句时,这会导致性能下降。
我正在寻找一种性能友好的替代方案,例如在编译时而不是在运行时获取位置信息。可以使用注释来实现这一点吗?或者也许还有其他技术?
How can I write caller location information (Java source file and line), in a log file using Java and log4j, but without hurting performance?
log4j allow you to write such information in the log file, but it uses the stack trace to get that it information, every time a log statement is issued, what causes performance degradation.
I'm looking for a performance friendly alternative, like getting the location information at compile time instead at runtime. It is possible to use annotations to accomplish that? Or maybe some other technique?
发布评论
评论(4)
如何将其作为构建过程的一部分来替换某些占位符,例如此代码段中的
$filename$
和$linenumber$
。要替换文件名,用您的版本控制系统进行关键字替换可能就足够了。免责声明:这只是我的想法,我自己从未尝试过。
How about making it part of the build process to replace certain placeholders, like
$filename$
and$linenumber$
in this snippet.To replace the filename, it may suffice to have keyword substitution with your revision control system. Disclaimer: this is just from the top of my head, I never tried it myself.
对于任何寻求更新解决方案(如果您将 log4j/logback 与 slf4j 结合使用)的人,我编写了一个 maven-plugin 来解决此问题,同时也不会产生任何性能问题:
https://github.com/PhilKes/slf4j-caller-info-maven-插件
该插件在编译时将类名、方法名称和源代码行号注入到所有 SLF4J 日志语句中(请参阅配置)。
您需要做的就是将
callerInformation
MDC 参数添加到您的日志模式中,并将插件添加到您的pom.xml
中:For anyone looking for a more current solution if you use log4j/logback with slf4j, I wrote a maven-plugin addressing this issue, while not generating any performance issues either:
https://github.com/PhilKes/slf4j-caller-info-maven-plugin
This plugin injects the class name, optionally also the method name and source code line number into all SLF4J log statements at compile time (see configuration).
All you need to do is to add the
callerInformation
MDC parameter to your log-pattern and add the plugin in yourpom.xml
:我同意罗布的观点,一般来说这是没有必要的。通常,日志消息中会有一些不同的字符串,搜索它即可找到源头。有了一个好的 IDE,这确实很快。
现在,鉴于问题所在,这是一个可能的解决方案:
对于运行时的每个日志操作,都会创建一个新对象 - 这不是问题。
对于包含此类日志语句的每一行源代码,都会创建一个新类。那可能太多了。
魔法是这样运作的:
I agree with Rob that it is generally unnecessary. Usually there's some distinct string in a log message, searching for it will get to the source. With a good IDE this is really fast.
Now, given the question as is, this is a possible solution:
for each log action at runtime, a new object is created - that's not a problem.
for each line of source containing such log statement, a new class is created. that can be too many.
here's how the magic works:
如果您正在寻找 Phil 的 SLF4J 插件 的 Log4j API 对应项,从 Log4j API 2.10 开始,就有一个
LogBuilder#withLocation
方法,允许工具将位置信息注入字节码。最近我们发布了
log4j-maven-转换插件
,后处理类文件并替换传统的日志记录调用,例如:到带有注入位置的
LogBuilder
调用中:使用起来非常简单,您只需要添加:
到你的 Maven 插件。
If you are looking for a Log4j API counterpart to Phil's SLF4J plugin, since Log4j API 2.10 there is a
LogBuilder#withLocation
method that allows tools to inject location information into byte-code.Recently we published
log4j-maven-transform-plugin
that postprocesses class file and replaces classical logging calls like:into a
LogBuilder
call with injected location:It is pretty straightforward to use, you just need to add:
to your Maven plugins.