Какова лучшая практика для операторов отладки, в которых есть строковые операции? - PullRequest
2 голосов
/ 28 мая 2009

Я часто обнаруживаю, что добавляю либо конкатонированные строки, либо использую формататор строк в своих операторах отладки в log4net и log4j, если я окружу эти операторы отладки блоком "if debug", чтобы не тратить ресурсы впустую, обрабатывая эти параметры, даже если оператор отладки не будет распечатан?

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

Ответы [ 11 ]

7 голосов
/ 28 мая 2009

для Java вы можете попробовать log5j .

log4j:

log.debug("This thing broke: " + foo + " due to bar: " + bar + " on this thing: " + car);

log5j:

log.debug("This thing broke: %s due to bar: %s on this thing: %s", foo, bar, car);
log.debug("Exception #%d", aThrowable, exceptionsCount++); 
3 голосов
/ 29 мая 2009

На этот вопрос подробно дан ответ в FAQ по SLF4J . Короче говоря, используйте параметризованные сообщения. Например, entry - это объект, вы можете написать:

 Object entry = new SomeObject(); 
 logger.debug("The entry is {}.", entry);

После оценки, вести ли запись в журнал или нет, и только если решение положительное, реализация регистратора отформатирует сообщение и заменит пару '{}' строковым значением записи. Другими словами, эта форма не несет затрат на создание параметров в случае, если оператор журнала отключен.

Следующие две строки приведут к одинаковому результату. Однако вторая форма превзойдет первую форму как минимум в 30 раз в случае отключенного оператора ведения журнала.

  logger.debug("The new entry is "+entry+"."); 
  logger.debug("The new entry is {}.", entry);
3 голосов
/ 28 мая 2009

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

2 голосов
/ 29 мая 2009

Мы приняли практику определения частной статической логической переменной DEBUG только для чтения в каждом классе.

private static readonly log4net.ILogger LOG = log4net.LogManager.GetLogger();
private static readonly bool DEBUG = LOG.IsDebugEnabled;

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

if (DEBUG) LOG.Debug(...);

где ... может иметь произвольную сложность и оценивается только тогда, когда требуется отладка.

См .: http://logging.apache.org/log4net/release/faq.html, ответ на вопрос «Что ДЕЙСТВИТЕЛЬНО НАИБОЛЕЕ БЫСТРЫЙ способ (не) ведения журнала?»

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

Поскольку у нас есть по крайней мере один оператор отладки на вызов функции, мы чувствовали, что написать if (DEBUG) стоило усилий, чтобы добиться максимальной производительности при отключенной отладке. Мы провели некоторые измерения с включенной и выключенной отладкой и обнаружили увеличение производительности от 10 до 20%. Мы не измеряли, каков был эффект if (DEBUG).

Кстати: мы делаем это только для отладочных сообщений. Предупреждения, информационные сообщения и ошибки создаются непосредственно через LOG.Warn и т. Д.

2 голосов
/ 28 мая 2009

В log4j рекомендуется следующая практика:

if ( log.isDebugEnabled() )
{
 log.debug("my " + var + " message";
}

Это экономит системные ресурсы от конкатенации строк и т. Д. Вы правы в своем предположении, что программа может работать медленнее, когда включен уровень отладки, но этого следует ожидать: наблюдаемая система изменяется, потому что она находится под наблюдением , Проблемы синхронизации (в основном) связаны с неудачной синхронизацией или видимостью переменных между потоками, которые не будут напрямую затронуты изменением уровня отладки. Вам все равно нужно будет «поиграть» с системой, чтобы воспроизвести многопоточные проблемы.

2 голосов
/ 28 мая 2009

Попробуйте slf4j (http://www.slf4j.org/). Вы пишете такие заявления, как:

log.fine("Foo completed operation {} on widget {}", operation, widget);

Сообщение журнала не собирается внутри библиотеки, пока уровень журнала не будет определен как достаточно высокий. Я считаю, что это лучший ответ.

(Это очень похоже на решение log5j, приведенное выше.)

2 голосов
/ 28 мая 2009

Вы измерили, сколько дополнительного времени уходит на объединение этих строк? Принимая во внимание, что инфраструктура ведения журнала будет принимать результирующие сообщения, проверять, нужно ли их отправлять (возможно) нескольким приемникам, а затем, возможно, записывать с использованием некоторого ввода-вывода, тогда вы, возможно, ничего не получите. Мне кажется, что если ваш метод toString () работает медленно, это может быть слишком оптимизацией.

Я также настороженно отношусь к этому подходу на случай, если кто-то напишет что-то подобное (и мы знаем, что не должны, но я видел это раньше)

if (Log.isDebugEnabled()) {
   Log.debug("Received " + (items++) + " items");
}

, и это будет работать / не работать в зависимости от уровня ведения журнала.

1 голос
/ 28 мая 2009

С C # мы начали использовать делегатов для дорогих операторов журнала. Он вызывается только в том случае, если уровень журнала достаточно высок:

log.Debug(()=> "Getting the value " + SomeValue() " is expensive!");

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

if(log.Level == Level.Info)
    log.Debug("Getting the value " + SomeValue() " is expensive!");

и я нахожу это намного более читабельным.

[Редактировать] Если это было отвергнуто за то, что он не обращался к Log4Net - это тривиально , чтобы написать обертку вокруг Log4Net, чтобы сделать это.

0 голосов
/ 28 мая 2009

Ищите уровень внешнего журнала в файле конфигурации log4j. Таким образом, у вас есть возможность включать или выключать журналы в зависимости от среды (и избегать всех этих конкатенаций строк).

if(log.isDebugEnabled())
{
    log.debug("Debug message");
}
0 голосов
/ 28 мая 2009

Я склонен заключать все вызовы для отладки в оператор isDebug. Я не думаю, что это преждевременная оптимизация, это просто хорошая практика.

Беспокоиться о том, что приложение работает на разных скоростях, не очень разумно, поскольку нагрузка на процессор может / будет влиять на ваше приложение больше, чем код отладки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...