В log4j проверка isDebugEnabled перед ведением журнала повышает производительность?



Я использую настройки log4j в моем приложении для входа. Ранее я использовал отладочный вызов, например:



Вариант 1:



logger.debug("some debug text");


но некоторые ссылки предполагают, что лучше проверить isDebugEnabled() во-первых, как:



Вариант 2:



boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
logger.debug("some debug text");
}


так что мой вопрос "вариант 2 улучшает производительность каким-либо образом?".



потому что в любом случае рамки Log4J имеют такая же проверка для debugEnabled. Для варианта 2 может быть полезно, если мы используем несколько операторов отладки в одном методе или классе, где платформа не должна вызывать isDebugEnabled() метод несколько раз (при каждом вызове); в этом случае он называет isDebugEnabled() метод только один раз, и если Log4J настроен на уровень отладки, то на самом деле он вызывает isDebugEnabled() метод дважды:




  1. в случае присвоения значения переменной debugEnabled, и

  2. фактически вызвано регистратором.отлаживать() метод.


Я не думаю, что если мы напишем несколько logger.debug() оператор в методе или классе и вызов debug() метод согласно варианту 1, то это накладные расходы для log4j framework по сравнению с вариантом 2. Так как isDebugEnabled() это очень маленький метод (с точки зрения кода), он может быть хорошим кандидатом для встраивания.

762   15  

15 ответов:

в данном конкретном случае, Вариант 1 лучше.

заявление охранника (проверка isDebugEnabled()) есть ли возможность предотвратить потенциально дорогостоящее вычисление сообщения журнала, когда оно включает вызов toString() методы различных объектов и объединение результатов.

в данном примере сообщение журнала является постоянной строкой, поэтому позволить регистратору отбросить его так же эффективно, как проверить, включен ли регистратор, и это снижает сложность код, потому что есть меньше ветвей.

еще лучше использовать более современную структуру ведения журнала, где операторы журнала принимают спецификацию формата и список аргументов, которые должны быть заменены регистратором, но "лениво", только если регистратор включен. Это подход slf4j.

посмотреть мой ответ на соответствующий вопрос для получения дополнительной информации и примера выполнения чего-то подобного с log4j.

поскольку в варианте 1 строка сообщения является константой, нет абсолютно никакого выигрыша в обертывании оператора logging с условием, наоборот, если оператор log включен debug, вы будете оценивать дважды, один раз в isDebugEnabled() метод и один раз в debug() метод. Стоимость вызова isDebugEnabled() в порядке от 5 до 30 наносекунд, которые должны быть незначительными для большинства практических целей. Таким образом, вариант 2 нежелателен, потому что он загрязняет ваш код и не предоставляет другого прибыль.

С помощью isDebugEnabled() зарезервировано для создания сообщений журнала путем объединения строк:

Var myVar = new MyVar();
log.debug("My var is " + myVar + ", value:" + myVar.someCall());

однако в вашем примере нет увеличения скорости, поскольку вы просто регистрируете строку и не выполняете такие операции, как конкатенация. Поэтому вы просто добавляете раздувание в свой код и затрудняете его чтение.

Я лично использую вызовы формата Java 1.5 в классе String следующим образом:

Var myVar = new MyVar();
log.debug(String.format("My var is '%s', value: '%s'", myVar, myVar.someCall()));

Я сомневаюсь, что есть много оптимизации но это легче читать.

обратите внимание, что большинство API ведения журнала предлагают форматирование, подобное этому, из коробки: slf4j, например, предоставляет следующее:

logger.debug("My var is {}", myVar);

что еще легче читать.

короткая версия: вы также можете сделать логическую проверку isDebugEnabled ().

причины:
1 - Если сложная логика / строка конкат. добавляется к вашей инструкции отладки вы уже будете иметь чек на месте.
2-вам не нужно выборочно включать оператор в "сложные" отладочные операторы. Все заявления включены таким образом.
3-журнал вызовов.debug выполняет следующие действия перед ведением журнала:

if(repository.isDisabled(Level.DEBUG_INT))
return;

этот это в основном то же самое, что и вызов журнала. или кошка. isDebugEnabled().

однако! Это то, что думают разработчики log4j (как и в их javadoc, и вы, вероятно, должны пойти по нему.)

Это метод

public
  boolean isDebugEnabled() {
     if(repository.isDisabled( Level.DEBUG_INT))
      return false;
    return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel());
  }

Это javadoc для этого

/**
*  Check whether this category is enabled for the <code>DEBUG</code>
*  Level.
*
*  <p> This function is intended to lessen the computational cost of
*  disabled log debug statements.
*
*  <p> For some <code>cat</code> Category object, when you write,
*  <pre>
*      cat.debug("This is entry number: " + i );
*  </pre>
*
*  <p>You incur the cost constructing the message, concatenatiion in
*  this case, regardless of whether the message is logged or not.
*
*  <p>If you are worried about speed, then you should write
*  <pre>
*    if(cat.isDebugEnabled()) {
*      cat.debug("This is entry number: " + i );
*    }
*  </pre>
*
*  <p>This way you will not incur the cost of parameter
*  construction if debugging is disabled for <code>cat</code>. On
*  the other hand, if the <code>cat</code> is debug enabled, you
*  will incur the cost of evaluating whether the category is debug
*  enabled twice. Once in <code>isDebugEnabled</code> and once in
*  the <code>debug</code>.  This is an insignificant overhead
*  since evaluating a category takes about 1%% of the time it
*  takes to actually log.
*
*  @return boolean - <code>true</code> if this category is debug
*  enabled, <code>false</code> otherwise.
*   */

Вариант 2 лучше.

по сути это не улучшает производительность. Но это гарантирует, что производительность не ухудшается. Вот как это делается.

обычно мы ожидаем лесоруб.debug (someString);

но обычно, по мере роста приложения, меняется много рук, особенно начинающих разработчиков, вы можете увидеть

регистратор.отладка (str1 + str2 + str3 + str4);

и тому подобное.

даже если уровень журнала установлен на ошибку или фатальный, конкатенация строк так бывает ! Если приложение содержит много сообщений уровня отладки с конкатенациями строк, то это, безусловно, требует повышения производительности, особенно с jdk 1.4 или ниже. (Я не уверен, что более поздние версии JDK internall делают какой-либо stringbuffer.добавлять.))(

вот почему Вариант 2 является безопасным. Даже конкатенации строк не происходят.

Как уже упоминалось, использование оператора guard действительно полезно только в том случае, если создание строки занимает много времени. Конкретные примеры этого при создании строки вызовет некоторую ленивую загрузку.

стоит отметить, что этой проблемы можно избежать, используя простой фасад ведения журнала для Java или (SLF4J) -http://www.slf4j.org/manual.html . Это позволяет вызывать такие методы, как:

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

Это только преобразует прошло в параметрах к строкам, если включена отладка. SLF4J, как следует из его названия, является только фасадом, и вызовы журнала могут быть переданы log4j.

вы также можете очень легко "свернуть свою собственную" версию этого.

надеюсь, что это помогает.

в Java 8, вы не должны использовать isDebugEnabled() для повышения производительности.

https://logging.apache.org/log4j/2.0/manual/api.html#Java_8_lambda_support_for_lazy_logging

import java.util.logging.Logger;
...
Logger.getLogger("hello").info(() -> "Hello " + name);

как @erickson это зависит. Если я правильно помню,isDebugEnabled уже встроен в debug() метод настройки log4j.
Пока вы не выполняете некоторые дорогостоящие вычисления в своих отладочных операторах, таких как цикл по объектам, выполнение вычислений и объединение строк, вы в порядке, на мой взгляд.

StringBuilder buffer = new StringBuilder();
for(Object o : myHugeCollection){
  buffer.append(o.getName()).append(":");
  buffer.append(o.getResultFromExpensiveComputation()).append(",");
}
log.debug(buffer.toString());

было бы лучше как

if (log.isDebugEnabled(){
  StringBuilder buffer = new StringBuilder();
  for(Object o : myHugeCollection){
    buffer.append(o.getName()).append(":");
    buffer.append(o.getResultFromExpensiveComputation()).append(",");
  }
  log.debug(buffer.toString());
}

это улучшает скорость, потому что это обычно для объединения строк в отладочном тексте, который является дорогим, например:

boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
    logger.debug("some debug text" + someState);
}

на один строка, Я использую троичный внутри сообщения журнала, таким образом, я не делаю конкатенацию:

ej:

logger.debug(str1 + str2 + str3 + str4);

Я:

logger.debug(logger.isDebugEnable()?str1 + str2 + str3 + str4:null);

но несколько строк код

ej.

for(Message mess:list) {
    logger.debug("mess:" + mess.getText());
}

Я:

if(logger.isDebugEnable()) {
    for(Message mess:list) {
         logger.debug("mess:" + mess.getText());
    }
}

log4j2 поддерживает s (в настоящее время их собственная реализация, но согласно документации планируется использовать интерфейс поставщика Java в версии 3.0). Вы можете прочитать немного больше об этом в руководство. Это позволяет поместите дорогостоящее создание сообщения журнала в поставщика, который создает сообщение только в том случае, если оно будет зарегистрировано:

LogManager.getLogger().debug(() -> createExpensiveLogMessage());

Если вы используете вариант 2, Вы делаете логическую проверку, которая выполняется быстро. В первом варианте вы выполняете вызов метода (толкая материал в стеке), а затем выполняете логическую проверку, которая все еще быстра. Проблему я вижу последовательность. Если некоторые из ваших инструкций debug и info обернуты, а некоторые нет, это не согласованный стиль кода. Плюс кто-то позже может изменить оператор отладки, чтобы включить конкатенацию строк, что все еще довольно быстро. Я обнаружил это, когда мы закончили отладку и информация заявление в большом приложении и профилировал его мы сохранили несколько процентных пунктов в производительности. Не много, но достаточно, чтобы это стоило работы. Теперь у меня есть несколько макросов, настроенных в IntelliJ, чтобы автоматически генерировать обернутые инструкции debug и info Для меня.

по состоянию на 2.x, Apache Log4j имеет эту встроенную проверку, поэтому имея isDebugEnabled() больше не надо. Просто сделайте debug() и сообщения будут подавлены, если не включена.

Log4j2 позволяет форматировать параметры в шаблон сообщения, похожий на String.format(), таким образом избавляясь от необходимости делать isDebugEnabled().

Logger log = LogManager.getFormatterLogger(getClass());
log.debug("Some message [myField=%s]", myField);

пример простой log4j2.свойства:

filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d %-5p: %c - %m%n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = debug
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

Я бы рекомендовал использовать Вариант 2 как де-факто для большинства, поскольку это не очень дорого.

корпус 1: бревно.отладка("одна строка")

случай 2: бревно.отладка("одна строка" + "две строки" + объект.toString + object2.toString)

в момент вызова любого из них, строка параметра в журнале.отладка (будь то случай 1 или Случай 2) должна быть оценена. Вот что все подразумевают под "дорогой".'Если у вас есть условие перед ним,' isDebugEnabled ()', эти не нужно оценивать, где сохраняется производительность.

Comments

    Ничего не найдено.