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 "";
}
}
在mylog4j2.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; }
}
}
我对这段代码有两个问题
{}
消息
(意思是,只有一个抽象方法),但是没有
我考虑过创建一个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
方法有两个问题
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());