在编译时禁用 Java 中的日志记录
我有一些 Java 代码,我想使用日志消息来检测它们以进行调试。然而,最终(编译后的)生产代码不应包含任何日志记录,因为它会减慢执行时间。 Java 有没有办法在编译时禁用记录器?
我并不担心运行时启用/禁用记录器的日志方法内的检查会增加足迹。
if (logging==enabled) {// do logging}
但我想避免在我的生产代码中进行如下参数构造:
Logger.log("undefined state" + state + " @ " + new Date());
我正在使用 Sun 的 Java 编译器。
I have some Java code that I'd like to instrument with log messages for debugging purposes. The final (compiled) production code, however, should not contain any logging as it would slow down the execution time. Is there any way in Java to disable a logger at compile time?
I am not afraid of the footprint a check inside the log method of a run-time enabled/disabled logger would add.
if (logging==enabled) {// do logging}
But I'd like to avoid parameter construction like the following in my production code:
Logger.log("undefined state" + state + " @ " + new Date());
I am using Sun's Java Compiler.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
您是否考虑过使用 {} 占位符的 slf4j 方法。这允许延迟构建 toString() ,这意味着如果禁用调试日志记录,则 log.debug(...) 的成本很低。
Have you considered the slf4j approach with {}-placeholders. That allows for delayed construction of the toString() meaning that log.debug(...) is cheap if debug logging is disabled.
我使用过的每个日志框架都要求您使用上述模式,以避免对日志表达式进行不必要的评估。
Every logging framework I've used requires you to use the above pattern to avoid unnecessary evaluation of the logging expression.
可以使用 Proguard 后处理 java 类文件并使用
-assumenosideeffects
删除日志记录调用的选项。对于 Android,此操作最常使用:删除对 Log.d(TAG, "message") 等的所有调用...
It is possible to post-process the java class files using Proguard and use the
-assumenosideeffects
option to remove the logging calls. This is done most commonly for Android using:to remove all calls to
Log.d(TAG, "message")
, etc ...没有任何内置方法可以实现这一点。您可能需要使用 Java 预处理器。
There is no built-in way that makes this possible. You may want to use a Java Preprocessor.
这似乎就是您正在寻找的:
当我们打开或关闭某些日志位置时,log4j 实际上在做什么?
This would seem to be what you're looking for:
what's log4j actually doing when we turn on or off some log places?
一种方法是在日志方法之外进行检查。与您提到的几乎相同的检查,但您自己执行:
此方法可用于任何日志记录级别。请参阅 Logger#isLoggable(Level) 了解更多信息。
请注意,这是避免日志方法参数构造的推荐方法。
One way is to do a check outside of the log method. Almost the same check as you mentioned, but you do it yourself:
This method can be used with any logging level. see Logger#isLoggable(Level) for more infos.
Notice it is the recommanded way to avoid log method parameter construction.
我不知道有关此的任何编译器功能,但您还可以做的是创建一个构建脚本。该脚本将复制原始(调试)Java 源文件,将它们复制到临时位置,从中删除日志记录语句,然后编译新的源文件,然后这些文件将不含调试代码。
I don't know about any Compiler functionality about this, but what you also could do is create a build-script. This script would copy the original (debug) Java source files, copy them to a temporary location, strip the logging statements from them and then compile the new source files which are then without debug code.
一个可能有效的丑陋黑客方法是用空实现隐藏 Logger 库的实现。优化器将内联它们,并且死代码删除应该删除参数构造。当参数构造包含副作用时,这将不起作用。
现在这是理论,我还没有在实践中测试过这一点。我对此很好奇。也许这需要一个单独的问题?
A ugly hack that might work is to hide the implementation of the Logger library with an empty implementation. The optimizer will inline them and deadcode removal should remove the parameter construction. This will not work when the parameter construction contains side-effects.
Now this is theory, I have not tested this in practice. I am curious about this though. Maybe this warrants a separate question?
您确实应该为日志消息使用级别指示器,Level.SEVERE ->水平.最好的.
记录器中有为此目的预定义的方法,即:
这将允许您在应用程序级别配置最小日志记录级别,并使用命令行、配置文件或手动使用 LogManager 打开/关闭低于配置级别的消息
You really should be using a Level indicator for your log messages, Level.SEVERE -> Level.FINEST.
There are predefined methods in the Logger for this i.e:
this will allow you to configure minumim logging level at the application level and switch on/off those messages below the configured level, using the command line, configuration files or manually using the LogManager
据我所知,Java 编译器能够消除由编译时常量表达式保护的代码块。因此从理论上讲,您应该能够通过以下方式执行此操作:
不幸的是,每当您更改其值时,您都需要重新编译依赖于 Logging.ENABLED 标志的每个类。所以我更喜欢以下内容:
它的优点是您可以在配置时甚至运行时对日志记录级别进行细粒度的调整;例如使用调试器、JMX 等。此外,在 log4j 中调用 logger.isDebugEnabled() 的开销足够低,除非您的代码库中有大量的日志记录,否则不太可能被注意到。
I understand that the Java compiler is able to eliminate blocks of code that are guarded by a compile time constant expression. So in theory, you should be able to do this with something like this:
Unfortunately, you need to recompile every class that depends on the Logging.ENABLED flag whenever you change its value. So I much prefer the following:
which has the advantage that you can make fine-grained adjustments to the logging levels at configuration time or even at runtime; e.g. using a debugger, JMX, etc. Also, the overhead of calling
logger.isDebugEnabled()
in log4j is low enough that it is unlikely to be noticeable unless you have an insane amount of logging in your codebase.