首页 文章

使用ProGuard删除调试日志

提问于
浏览
1

在我们正在开发的应用程序中,有很多调试和跟踪日志记录,即使日志记录级别关闭它们,创建消息参数数组的唯一开销也成为我们的一些时间敏感算法的问题 . 现在,我们不想完全删除日志(因为它们在开发和测试环境中显然很有用),但我们确实希望以某种方式减少它们的运行时开销 . 我们考虑了几个选择:

  • 抛弃Slf4j API并将Log4j2与惰性日志记录一起使用需要过多的重构和手工劳动 . 自定义 Logger 包装器和使用if语句包装所有 Logger 调用也是如此 .

  • 代码后处理器可以自动用条件语句包装所有日志(因此永远不会创建参数数组)或完全删除它们 .

  • ProGuard可以删除所有 Logger 调用 .

由于我们没有找到任何可以开箱即用的代码后处理器,因此我们决定采用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配置实现这一目标,还是有现成的工具来实现这一目标?

1 回答

  • 0

    只是一个疯狂的想法:如何使用与slf4j相同的接口创建自己的接口和实现,但是使用展开的varargs?基本上你分叉slf4j以满足你的要求 .

    另一个想法是构建一个SLF4J-to-Log4j2迁移工具 . 如果您的公司同意您可以将此建议作为对Log4j2项目的贡献,那么您不必维护它 . :-)

相关问题