Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在log4j2中创建惰性消息_Java_Logging_Java 8_Log4j2 - Fatal编程技术网

Java 在log4j2中创建惰性消息

Java 在log4j2中创建惰性消息,java,logging,java-8,log4j2,Java,Logging,Java 8,Log4j2,我有以下代码: import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Test { private static final Logger logger = LogManager.getLogger(); public static void main (String[] args) { logger.info("Text: {}", get

我有以下代码:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
  private static final Logger logger = LogManager.getLogger();
  public static void main (String[] args) {
    logger.info("Text: {}", getText());
  }
  static String getText() {
    // Expensive action using IO
    return "";
  }
}
在my
log4j2.json
中,记录器设置为
ERROR

我希望在不需要时,根本不调用
getText()
。为此,我使用了消息API,并编写了以下内容:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.Message;
public class Test {
  private static final Logger logger = LogManager.getLogger();
  public static void main (String[] args) {
    logger.info(new TextMessage());
  }
  static String getText() {
    // Expensive action using IO
    return "";
  }
  static class TextMessage implements Message {
    @Override public String getFormat() { return null; }
    @Override public String getFormattedMessage() {
        return String.format("text: %s", getText());
    }
    @Override public Object[] getParameters() { return null; }
    @Override public Throwable getThrowable() { return null; }
  }
}
我对这段代码有两个问题

  • 我不能使用通常用于日志记录的
    {}
  • 它非常冗长
  • 我在中检查了可以在Java8的lambda表达式中使用的
    消息
    (意思是,只有一个抽象方法),但是没有

    我考虑过创建一个ToString接口,用作以下内容

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    public class Test {
      private static final Logger logger = LogManager.getLogger();
      public static void main (String[] args) {
        logger.info("Text: {}", new ToStringable() { public String toString() { return getText();}});
      }
      static String getText() {
        // Expensive action using IO
        return "";
      }
    }
    interface ToStringable { @Override String toString(); }
    
    这就完成了任务,但它几乎不可读,我不能在上面使用Java8的lambda(请参见下文,注意此代码无法编译)

    最后,只有好的
    if(logger.isxxenabled()){logger.xxxx(…)}
    可靠地解决了这个问题,但是使用现代的惰性记录器有什么意义呢

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    public class Test {
      private static final Logger logger = LogManager.getLogger();
      public static void main (String[] args) {
        if (logger.isInfoEnabled()) {
          logger.info("Text: {}", getText());
        }
      }
      static String getText() {
        // Expensive action using IO
        return "";
      }
    }
    
    那么有没有人遇到过这个问题?如果有,是如何解决的


    最后一句话:前三段代码是。这意味着他们来这里只是为了说明问题。请不要想问题之外的事情(意思是:不要告诉我要实事求是,放手就行了)。

    你的
    ToStringable
    方法有两个问题

  • 当您将内部类转换为lambda表达式时,您删除了对编译器的任何提示,即lambda表达式应该实现
    toString
    。接收器类型是
    Object
    (或者,不管编译器在尝试log4japi的重载方法时会尝试什么)。lambda表达式需要一个目标类型,换句话说,如果没有将其分配给适当类型的变量,并且参数类型不合适,则必须插入一个类型强制转换,如
    (ToStringable)(->”
  • 但这在这里没有帮助,因为您正试图覆盖
    java.lang.Object
    中声明的方法。Lambda表达式无法重写从
    java.lang.Object
    继承的方法
  • 为了解决这个问题,您需要一个助手方法,使用良好的旧内部类方法重写
    Object.toString()
    委托给另一个
    接口
    ,该接口可以通过lambda表达式实现:

    import java.util.function.Supplier;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class Log4jTest {
    
      private static final Logger logger = LogManager.getLogger();
      public static void main (String[] args) {
        logger.info("Text: {}", lazy( ()->getText() ));
        logger.error("Text: {}", lazy(Log4jTest::getText));
      }
      // reusable helper method
      static Object lazy(Supplier<String> s) {
        return new Object() {
          @Override
          public String toString() {
              return s.get();
          }
        };
      }
      static String getText() {
        System.out.println("very long computation");
        return "";
      }
    }
    
    导入java.util.function.Supplier;
    导入org.apache.logging.log4j.LogManager;
    导入org.apache.logging.log4j.Logger;
    公共类Log4jTest{
    私有静态最终记录器Logger=LogManager.getLogger();
    公共静态void main(字符串[]args){
    info(“Text:{}”,lazy(()->getText());
    error(“Text:{}”,lazy(Log4jTest::getText));
    }
    //可重用辅助方法
    静态对象延迟(个){
    返回新对象(){
    @凌驾
    公共字符串toString(){
    返回s.get();
    }
    };
    }
    静态字符串getText(){
    System.out.println(“超长计算”);
    返回“”;
    }
    }
    
    本例使用lambda表达式和方法引用同时显示了这两种情况,但当然,行为上的差异源于不同的日志记录级别。只要log4j不提供像这样的函数接口输入,就不可避免地要使用带有一个内部类的helper方法。但是您只需要实现一次,而所有调用者都可以使用lambda表达式。

    更新(2015年8月5日)

    考虑投票支持这张票,将lambda表达式的支持带到log4j2


    更新(2015年8月10日)

    Log4J的下一个版本2.4将支持lambda。用法示例:

    // log message is not constructed if DEBUG level is not enabled
    logger.debug("Result of some expensive operation is {}", () -> someLongRunningOperation());
    

    问题已经得到了回答,这只是一些额外的建议,以防您计划将其用于异步记录器或异步附加器:

    • 您提到创建消息结果是一项昂贵的操作。我假设您希望使用异步记录器/附加器来提高应用程序的吞吐量和/或响应时间。有道理。请注意,如果创建消息结果非常昂贵,那么(取决于您的日志记录量),您的队列可能会被填满;一旦发生这种情况,您就可以再次同步地进行日志记录。您可以调整队列大小以帮助您处理突发事件,但是如果持续的日志记录率非常高,您可能会遇到此问题。Log4j2包括JMX MBean(,),您可以使用它来查询队列的满度
    • 输出日志结果将反映后台I/O线程调用
      message.getFormattedMessage
      时消息的值,而不是应用程序线程调用
      Logger.info
      时消息的值。如果记录了许多延迟消息,则这两个事件之间的时间间隔可能会增大。还要注意,消息对象需要是线程安全的。你可能已经知道了,但我认为值得指出

    我希望这是有用的。

    非常有用,感谢您解释了我对lambdas的错误用法,并展示了一个完全合适的示例!
    // log message is not constructed if DEBUG level is not enabled
    logger.debug("Result of some expensive operation is {}", () -> someLongRunningOperation());