【问题标题】:Sorrounding Logger with an If clause to avoid redundant String construction用 If 子句环绕 Logger 以避免多余的字符串构造
【发布时间】:2010-01-10 16:05:52
【问题描述】:

有人建议我在登录 java 时使用此语法:

if (logger.isLoggable(Log.FINE))
{
    logger.fine("bla"+" bla"+" bla");
}

这样做的原因是为了避免在日志级别低于“FINE”的情况下重复构建参数字符串。 (在上面的示例中 - 5 个冗余字符串对象。(“bla”X3、“bla bla”和“bla bla bla”)。

我想听听其他人对此做了什么,或者您是否认为这是必要的。

谢谢!!

【问题讨论】:

  • 由于这完全是见仁见智,因此应将其标记为“社区维基”。
  • 我不同意。我觉得这个可以客观的讨论一下。
  • 我不认为这是一个社区 wiki 的原因是我真的在寻找解决这个问题的最佳方法。一旦找到“最佳解决方案”,我会将其标记为答案。

标签: java logging


【解决方案1】:

一些较新的日志框架允许您将参数指定为参数,如果没有日志,则不会评估它们。

我找到的例子是 LogBack,Log4j 的继承者。信息如下:http://www.infoq.com/news/2007/08/logback

可以说,这为您提供了两全其美的体验。优雅的语法和良好的性能。


Log4j 代码示例:

if( logger.isDebugEnabled() ) {
  logger.debug( "User with account " + 
    user.getAccount() + " failed authentication; " +
    "supplied crypted password " + user.crypt(password) +
    " does not match." );
}

等效的LogBack代码:

logger.debug( "User with account {} failed authentication; " +
    "supplied crypted password {} does not match.",
    user.getAccount(), user.crypt(password) );

这会推迟消息组装的成本,直到 LOGBack 确定是否会查看此消息。它不会推迟检索昂贵参数的成本,例如上面示例中的密码加密。

【讨论】:

    【解决方案2】:

    字符串对象是不可变的,因此重复连接是一项昂贵的操作。它需要重复的内存分配、对象创建和迭代。考虑到每分钟可以调用数千或数百万次更精细日志级别的某些日志记录调用,按照您的说明进行操作可能会带来相当大的性能提升。不过,对于较小的应用程序,可能不值得付出额外的努力。

    附带说明:您可以节省更多性能,这对于使用如下常量非常重要:

    public static final boolean DEBUG = false;
    

    如果您现在将日志记录代码包装在这样的 if 块中,JVM 将能够在产品模式下运行时完全优化调试调用。这与 C#ifdef 一样接近。

    if (Globals.DEBUG) {
        // Logging call
    }
    

    【讨论】:

      【解决方案3】:

      对于调试类型的日志记录是绝对必要的。首先检查日志级别比创建字符串并丢弃它快 10 倍。

      【讨论】:

        【解决方案4】:

        这是一个改进(很好),但可以稍微改进一下。

        在用作配置的全局对象中为每个日志记录级别(FINE 等)设置最终标志,然后使用 StringBuffer 来构建您的调试输出——您甚至可以同时将数字格式化到流中。

        public class MyAppConfig {
          public final boolean FINE=true;
          // ... other fields
        }
        
        public class MyApp {
          void someFunction() {
            ...
            int imagesProcessed;
            imagesProcessed = processImages();
        
            if (MyAppConfig.FINE) logger.fine(new StringBuffer(35).
              append("Count of images processed: ").append(imagesProcessed).toString());
        
            ...
          }
        }
        

        这里的字符串缓冲区设置为 35 个字符的“初始​​容量”。如果您知道要生成多少个字符,您可以向 StringBuffer 提供提示。

        【讨论】:

        • 如果您不打算在不重新编译的情况下更改日志记录级别,那么这是一个很好的(没有双关语)解决方案。大多数日志框架允许您从配置文件动态更改此设置,或者至少只需要重新启动。在这种情况下,此解决方案消除了这种可能性。
        猜你喜欢
        • 1970-01-01
        • 2012-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-06
        • 1970-01-01
        • 2016-10-20
        • 1970-01-01
        相关资源
        最近更新 更多