在我们正在开发的应用程序中,有很多调试和跟踪日志记录,即使日志级别关闭它们,创建消息参数数组的唯一开销也会成为我们某些时间的问题敏感算法。现在,我们不想完全删除日志(因为它们在开发和测试环境中显然是有用的),但我们确实想要以某种方式减少它们的运行时间开销。我们考虑了几个选项:使用ProGuard删除调试日志
- 开沟Slf4j API和使用Log4j2与惰性日志记录需要太多的重构和手工劳动。代码后处理器可以自动用条件语句包裹所有日志(因此永远不会创建参数数组),或者将它们全部删除。
- ProGuard可以删除所有记录器呼叫。
由于我们还没有发现任何可以将开箱即用的代码后置处理器,我们决定采用ProGuard解决方案。这是我们基本的ProGuard设置:
-optimizations code/removal/simple,code/removal/advanced
-dontobfuscate
-dontshrink
-keep class *
-keepclassmembers class * {
*;
}
-assumenosideeffects class org.slf4j.Logger {
void trace(...);
void debug(...);
}
该解决方案部分工作。大多数调试日志确实被删除,但调试日志参数上调用的所有方法都不受影响。例如,该行:
log.debug("Evidence {} is unverifiable for product {}", evidence, product.getData().getName());
...将被改造成这样:
product.getData().getName()
讽刺的是,这也使所有的对象数组灌顶:
log.debug("{} {} {}", first, second, third);
// ...becomes:
Object[] var10000 = new Object[]{first, second, third};
现在,我知道这类事情应该通过JIT(未使用的变量删除)进行优化 - 我更担心第一种情况,所有调用的方法都不会随着日志记录一起被删除。这些可能范围从无害(简单的getter调用)到稍差(并发集合上的size()
调用)。
目前的ProGuard解决方案“足够好”,但我想知道是否可以彻底删除日志记录调用(及其副作用)。我们可以通过ProGuard配置实现吗?还是有现成的工具可以实现这一点?
自定义日志记录界面正是我们试图避免的那种事情 - 这可能需要过多的手动重构工作。切换到Log4j2 API将解决我们的一些问题,但我会研究它。 – JustACluelessNewbie
幸运的是,slf4j API很小,我想它主要是导入,代码用LogManager代替LoggerFactory,用ThreadContext代替MDC。 –
是的,它应该只是使用查找替换的问题,也许重构一些潜在的昂贵的日志来使用“供应商”。由于ProGuard解决方案已经有效(有点,有点),配对这两个应该足够了。我希望。 – JustACluelessNewbie