我有一些Java代码,我想使用日志消息进行调试以进行调试。但是,最终(已编译)生产代码不应包含任何日志记录,因为它会减慢执行时间。 Java中有没有办法在编译时禁用记录器?
我并不害怕在运行时启用/禁用记录器的日志方法中添加检查的脚印。
if (logging==enabled) {// do logging}
但我想在生产代码中避免参数构造如下:
Logger.log("undefined state" + state + " @ " + new Date());
我正在使用Sun的Java编译器。
答案 0 :(得分:5)
您是否考虑过使用{} -placeholders的slf4j方法。这允许延迟构造toString(),这意味着如果禁用调试日志记录,log.debug(...)便宜。
log.debug("in loop() - a={}, b={}", a, b);
答案 1 :(得分:2)
if(logger.isDebugEnabled()) {
logger.debug(expression);
}
我使用的每个日志框架都要求您使用上述模式以避免对日志记录表达式进行不必要的评估。
答案 2 :(得分:2)
可以使用Proguard对java类文件进行后处理,并使用-assumenosideeffects
选项删除日志记录调用。这最常用于Android使用:
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
删除对Log.d(TAG, "message")
等的所有电话......
答案 3 :(得分:1)
没有内置的方法可以实现这一点。您可能想要使用Java Preprocessor。
答案 4 :(得分:1)
一种方法是在日志方法之外进行检查。几乎和你提到的一样,但是你自己做了:
if (LOGGER.isLoggable(Level.DEBUG)) {
LOGGER.log("undefined state" + state + " @ " + new Date());
}
此方法可用于任何日志记录级别。有关更多信息,请参阅Logger#isLoggable(Level)。 请注意,这是避免日志方法参数构建的推荐方法。
答案 5 :(得分:1)
答案 6 :(得分:0)
我不知道有关此的任何编译器功能,但您还可以做的是创建一个构建脚本。此脚本将复制原始(调试)Java源文件,将它们复制到临时位置,从中删除日志语句,然后编译新的源文件,然后不使用调试代码。
答案 7 :(得分:0)
可能有用的丑陋黑客是使用空实现隐藏Logger库的实现。优化器将内联它们并删除死码应删除参数构造。当参数构造包含副作用时,这将不起作用。
现在这是理论,我没有在实践中测试过这个。我对此很好奇。也许这需要一个单独的问题?
答案 8 :(得分:0)
你真的应该为你的日志消息使用Level指示器,Level.SEVERE - > Level.FINEST。
Logger中有预定义的方法,即:
Logger.info(msg);
Logger.finest(msg); // debug/trace message.
Logger.log(Level.CONFIG, "config message");
这将允许您在应用程序级别配置minumim日志记录级别,并使用命令行,配置文件或手动使用LogManager来打开/关闭低于配置级别的消息
答案 9 :(得分:0)
据我所知,Java编译器能够消除由编译时常量表达式保护的代码块。所以从理论上讲,你应该能够做到这样:
public class Logging {
public static final boolean ENABLED = true; // change to false
}
public class Something
....
if (Logging.ENABLED) {
logger.debug("hello mum");
}
}
不幸的是,每当更改其值时,都需要重新编译依赖于Logging.ENABLED标志的每个类。所以我更喜欢以下内容:
public class Something
....
if (logger.isDebugEnabled()) {
logger.debug("hello mum");
}
}
的优点是,您可以在配置时甚至在运行时对日志记录级别进行细粒度调整;例如使用调试器,JMX等。另外,在log4j中调用logger.isDebugEnabled()
的开销足够低,除非你的代码库中有大量的日志记录,否则它不太可能引人注意。