У меня есть такой код:
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 "";
}
}
В моем 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; }
}
}
У меня две проблемы с этим кодом.
- Я не могу использовать
{}
, обычно используемый для регистрации. - Это очень многословно.
Я проверил javadoc на наличие Message
, которые я мог бы использовать в лямбда-выражениях Java 8 (то есть только один абстрактный метод), но его нет.
Я думал о создании интерфейса ToStringable, который будет использоваться следующим образом.
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(); }
Это выполняет свою работу, но его трудно читать, и я не могу использовать лямбда Java 8 для этого (см. Ниже, обратите внимание, что этот код не компилируется).
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", () -> getText());
}
static String getText() {
// Expensive action using IO
return "";
}
}
interface ToStringable {@Override String toString(); }
Наконец, только старый добрый if (logger.isXxxxEnabled()) { 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 "";
}
}
Сталкивался ли кто-нибудь с этой проблемой, и если да, то как она была решена?
Заключительные слова: первые три фрагмента кода - это короткие, автономные, правильные примеры. Это означает, что они здесь только для того, чтобы показать проблему. Не думайте, пожалуйста, за пределами проблемы (имеется в виду: не говорите мне быть прагматичным и просто отпустите).
1 ответ
ОБНОВЛЕНИЕ (5 августа 2015 г.)
Рассмотрите возможность голосования за этот билет LOG4J2-599, чтобы обеспечить поддержку лямбда-выражений в Log4j 2. .
ОБНОВЛЕНИЕ (10 августа 2015 г.)
Следующая версия Log4J, 2.4, будет поддерживать лямбда-выражения. Пример использования:
// log message is not constructed if DEBUG level is not enabled
logger.debug("Result of some expensive operation is {}", () -> someLongRunningOperation());
На вопрос уже был дан ответ, это просто дополнительный совет на случай, если вы планируете использовать это с асинхронными регистраторами или асинхронным приложением:
- Вы упомянули, что создание результата сообщения - дорогостоящая операция. Я предполагаю, что вы хотите использовать асинхронные регистраторы / приложения для повышения пропускной способности и / или времени отклика вашего приложения. Имеет смысл. Имейте в виду, что если создание результата сообщения действительно дорого, тогда (в зависимости от того, сколько вы регистрируете) ваша очередь может заполниться; как только это произойдет, вы снова войдете в синхронный журнал. Вы можете настроить размер очереди, чтобы справиться с пакетами, но если постоянная скорость записи в журнал очень высока, вы можете столкнуться с этой проблемой. Log4j2 включает JMX MBeans (1, 2) можно использовать, чтобы узнать, насколько заполнена очередь.
- Результат журнала вывода будет отражать значение сообщения в момент, когда фоновый поток ввода-вывода вызвал
Message.getFormattedMessage
, а не значение сообщения в момент, когда поток вашего приложения вызвалLogger.info
. Если регистрируется много ленивых сообщений, временной интервал между этими двумя событиями может увеличиваться. Также имейте в виду, что ваш объект сообщения должен быть потокобезопасным. Вы, наверное, уже знаете это, но я подумал, что стоит указать на это.
Надеюсь, это будет полезно.
Похожие вопросы
Связанные вопросы
Новые вопросы
java
Java — это высокоуровневый объектно-ориентированный язык программирования. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег часто используется вместе с другими тегами для библиотек и/или фреймворков, используемых разработчиками Java.