С текущими каркасами ведения журналов вопрос является спорным
Текущие структуры ведения журналов, такие как slf4j или log4j 2, в большинстве случаев не требуют защитных операторов. Они используют параметризованный оператор журнала, чтобы событие можно было регистрировать безоговорочно, но форматирование сообщения происходит только в том случае, если событие включено. Построение сообщения выполняется по мере необходимости регистратором, а не в приоритетном порядке приложением.
Если вам нужно использовать античную библиотеку журналов, вы можете читать дальше, чтобы получить больше информации и способ дооснастить старую библиотеку параметризованными сообщениями.
Действительно ли охранные операторы добавляют сложности?
Подумайте об исключении инструкций охранников из расчета цикломатической сложности.
Можно утверждать, что из-за своей предсказуемой формы проверки условного журналирования действительно не способствуют сложности кода.
Негибкие метрики могут сделать хорошего программиста плохим. Будьте осторожны!
Предполагая, что ваши инструменты для расчета сложности не могут быть адаптированы к этой степени, следующий подход может предложить обходной путь.
Необходимость условного ведения журнала
Я предполагаю, что ваши защитные заявления были введены, потому что у вас был такой код:
private static final Logger log = Logger.getLogger(MyClass.class);
Connection connect(Widget w, Dongle d, Dongle alt)
throws ConnectionException
{
log.debug("Attempting connection of dongle " + d + " to widget " + w);
Connection c;
try {
c = w.connect(d);
} catch(ConnectionException ex) {
log.warn("Connection failed; attempting alternate dongle " + d, ex);
c = w.connect(alt);
}
log.debug("Connection succeeded: " + c);
return c;
}
В Java каждый из операторов журнала создает новый StringBuilder
и вызывает метод toString()
для каждого объекта, присоединенного к строке. Эти методы toString()
, в свою очередь, могут создавать собственные экземпляры StringBuilder
и вызывать методы toString()
их членов и т. Д. Для потенциально большого графа объектов. (До Java 5 он был еще дороже, поскольку использовался StringBuffer
, и все его операции синхронизированы.)
Это может быть относительно дорого, особенно если оператор журнала находится в каком-то интенсивно выполняемом пути кода. И, как написано выше, это дорогостоящее форматирование сообщений происходит, даже если регистратор обязан отбросить результат из-за слишком высокого уровня журнала.
Это приводит к введению охранных заявлений вида:
if (log.isDebugEnabled())
log.debug("Attempting connection of dongle " + d + " to widget " + w);
С помощью этой защиты оценка аргументов d
и w
и конкатенация строк выполняются только при необходимости.
Решение для простой и эффективной регистрации
Однако, если регистратор (или оболочка, которую вы пишете вокруг выбранного вами пакета журналирования) принимает форматировщик и аргументы для форматера, создание сообщения может быть отложено до тех пор, пока не будет уверено, что оно будет использовано, при одновременном устранении защиты высказывания и их цикломатическая сложность.
public final class FormatLogger
{
private final Logger log;
public FormatLogger(Logger log)
{
this.log = log;
}
public void debug(String formatter, Object... args)
{
log(Level.DEBUG, formatter, args);
}
… &c. for info, warn; also add overloads to log an exception …
public void log(Level level, String formatter, Object... args)
{
if (log.isEnabled(level)) {
/*
* Only now is the message constructed, and each "arg"
* evaluated by having its toString() method invoked.
*/
log.log(level, String.format(formatter, args));
}
}
}
class MyClass
{
private static final FormatLogger log =
new FormatLogger(Logger.getLogger(MyClass.class));
Connection connect(Widget w, Dongle d, Dongle alt)
throws ConnectionException
{
log.debug("Attempting connection of dongle %s to widget %s.", d, w);
Connection c;
try {
c = w.connect(d);
} catch(ConnectionException ex) {
log.warn("Connection failed; attempting alternate dongle %s.", d);
c = w.connect(alt);
}
log.debug("Connection succeeded: %s", c);
return c;
}
}
Теперь, , ни один из каскадных toString()
вызовов с их распределением буферов не произойдет , если они не нужны! Это эффективно устраняет снижение производительности, которое привело к защитным заявлениям. Одним небольшим штрафом в Java будет автоматическая упаковка любых аргументов примитивного типа, передаваемых в регистратор.
Код, ведущий запись в журнал, возможно, даже чище, чем когда-либо, так как неубранная конкатенация строк исчезла. Это может быть даже чище, если строки формата выводятся наружу (с использованием ResourceBundle
), что также может помочь в обслуживании или локализации программного обеспечения.
Дальнейшие улучшения
Также обратите внимание, что в Java вместо "format" String
может использоваться объект MessageFormat
, который дает вам дополнительные возможности, такие как выбор формата для более аккуратной обработки кардинальных чисел. Другой альтернативой может быть реализация вашей собственной возможности форматирования, которая вызывает некоторый интерфейс, который вы определяете для «оценки», а не базовый метод toString()
.