Как удалить инструкции отладки из производственного кода на Java
-
09-06-2019 - |
Вопрос
Возможно ли, чтобы компилятор удалял инструкции, используемые для целей отладки (например, ведения журнала), из производственного кода?Инструкции debug нужно было бы как-то пометить, возможно, с помощью аннотаций.
Легко установить свойство (debug = true) и проверять его при каждой инструкции debug, но это может снизить производительность.Было бы неплохо, если бы компилятор просто заставил инструкции debug исчезнуть.
Решение
Две рекомендации.
Первый: для реального ведения журнала используйте современный пакет ведения журнала, такой как log4j или собственный встроенный в Java пакет ведения журнала.Не беспокойтесь так сильно о производительности, проверка уровня ведения журнала занимает порядка наносекунд.(это целочисленное сравнение).
И если у вас есть более одного оператора log, защитите весь блок:
(log4j, например:)
if (logger.isDebugEnabled()) {
// perform expensive operations
// build string to log
logger.debug("....");
}
Это дает вам дополнительную возможность контролировать ведение журнала во время выполнения.Необходимость перезапуска и запуска отладочной сборки может быть очень неудобной.
Второй:
Вы можете найти утверждения это больше того, что вам нужно.Утверждение - это оператор, который выдает логический результат с необязательным сообщением:
assert (sky.state != FALLING) : "The sky is falling!";
Всякий раз, когда утверждение приводит к false, утверждение завершается ошибкой и выдается AssertionError, содержащий ваше сообщение (это непроверенное исключение, предназначенное для выхода из приложения).
Самое приятное, что они обрабатываются JVM особым образом и могут переключаться во время выполнения вплоть до уровня класса, используя параметр виртуальной машины (перекомпиляция не требуется).Если этот параметр не включен, накладные расходы равны нулю.
Другие советы
public abstract class Config
{
public static final boolean ENABLELOGGING = true;
}
import static Config.*;
public class MyClass
{
public myMethod()
{
System.out.println("Hello, non-logging world");
if (ENABLELOGGING)
{
log("Hello, logging world.");
}
}
}
Компилятор удалит блок кода с надписью "Hello, logging world". в нем if ENABLE_LOGGING имеет значение true, потому что это статическое конечное значение.Если вы используете обфускатор, такой как proguard, то класс Config тоже исчезнет.
Обфускатор также допускал бы вместо этого подобные вещи:
public class MyClass
{
public myMethod()
{
System.out.println("Hello, non-logging world");
Log.log("Hello, logging world.");
}
}
import static Config.*;
public abstract class Log
{
public static void log(String s)
{
if (ENABLELOGGING)
{
log(s);
}
}
}
Метод Log#log сведется к нулю в компиляторе и будет удален обфускатором вместе с любыми вызовами этого метода, и в конечном итоге даже сам класс Log будет удален.
Другая возможность заключается в том, чтобы поместить оператор if в вашу функцию ведения журнала, таким образом, вы получите меньше кода, но за счет некоторых дополнительных вызовов функций.
Я также не большой поклонник полного удаления отладочного кода.Как только вы начнете работать, вам, вероятно, понадобится доступ к отладочным сообщениям, если что-то пойдет не так.Если вы удалите всю отладку на уровне кода, то это невозможно.
Использование Препроцессор Java?(google foo low, но это ссылка на старые форумы Джоэла, обсуждающие это)
Java содержит какой-то собственный препроцессор.Это называется ПОДХОДЯЩИЙ.Он обрабатывает и генерирует код.На данный момент я не уверен, как это должно работать (я еще не пробовал).Но, похоже, он используется для подобных вещей.
Я бы также настоятельно рекомендовал использовать систему ведения журнала.
Тот Самый logger.IsDebugEnabled()
это не обязательно, просто так может быть быстрее проверить, находится ли система на уровне отладки перед входом в систему.
Использование платформы ведения журнала означает, что вы можете настраивать уровни ведения журнала "на лету", не перезапуская приложение.
Вы могли бы вести журнал следующим образом:
logger.error("Something bad happened")
logger.debug("Something bad happend with loads more detail")
Это "трюк" похоже, что ваши отладочные инструкции исчезли
public static final boolean DEBUG = false;
if (DEBUG) { //disapeared on compilation }
Тот Самый Публикация сказал , что javac
достаточно умен, чтобы проверить static final boolean
и исключите инструкции debug.(Я лично этого не пробовал)
Что касается ведения журнала, то лично мне не нравится видеть код, подобный:
if (logger.isDebugEnabled()) {
logger.debug("....");
}
realImportantWork();
Ведение журнала отвлекает меня от realImportantWork()
.Правильный путь для меня - это:
logger.debug("....");
realImportantWork()
плюс конфигурация, которая исключает все отладочные сообщения на производстве.
Я имею в виду, что logger.isDebugEnabled()
контроль должен быть обязанностью фреймворка ведения журнала, а не моей работой.Большинство фреймворков ведения журнала поддерживают такие понятия, как "logger", "LogLevel"..что может сделать свое дело.
Чтобы прямо ответить на ваш вопрос:Я не знаю.
Но вот еще одно решение вашей проблемы:На мой взгляд, здесь есть два утверждения, которые противоречат друг другу:"инструкции отладки" и "производственный код".
Какова цель отладочных инструкций?Помогите избавиться от ошибок во время (модульного) тестирования.Если часть программного обеспечения должным образом протестирована и работает в соответствии с требованиями, инструкции debug являются не чем иным, как УСТАРЕВШИМИ.
Я категорически не согласен с оставлением каких-либо отладочных инструкций в производственном коде.Бьюсь об заклад, никто не мешает тестировать побочные эффекты отладочного кода в производственном коде.Код, вероятно, делает то, что он должен делать, но делает ли он нечто большее?Все ли ваши #defines работают правильно и действительно извлекают ВЕСЬ отладочный код?Кто анализирует 100000 строк предварительно обработанного кода, чтобы увидеть, все ли отладочные материалы исчезли?
Если у нас нет другого определения производственного кода, вам следует рассмотреть возможность удаления инструкций debug после тестирования кода и покончить с этим.