Почему сообщения журнала Level.FINE не отображаются?
JavaDocs для java.util.logging.Level
:
Уровни в порядке убывания:
-
SEVERE
(наибольшее значение)
-
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST
(самое низкое значение)
Источник
import java.util.logging.*;
class LoggingLevelsBlunder {
public static void main(String[] args) {
Logger logger = Logger.getAnonymousLogger();
logger.setLevel(Level.FINER);
System.out.println("Logging level is: " + logger.getLevel());
for (int ii=0; ii<3; ii++) {
logger.log(Level.FINE, ii + " " + (ii*ii));
logger.log(Level.INFO, ii + " " + (ii*ii));
}
}
}
Выход
Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevelsBlunder main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 2 4
Press any key to continue . . .
Описание проблемы
Мой пример устанавливает Level
в FINER
, поэтому я ожидал увидеть 2 сообщения для каждого цикла. Вместо этого я вижу одно сообщение для каждого цикла (сообщения Level.FINE
отсутствуют).
Вопрос
Что нужно изменить, чтобы увидеть вывод FINE
(, FINER
или FINEST
)?
Обновление (решение)
Благодаря ответу Vineet Reynolds эта версия работает в соответствии с моими ожиданиями. Он отображает сообщения 3x INFO
и сообщения 3x FINE
.
import java.util.logging.*;
class LoggingLevelsBlunder {
public static void main(String[] args) {
Logger logger = Logger.getAnonymousLogger();
// LOG this level to the log
logger.setLevel(Level.FINER);
ConsoleHandler handler = new ConsoleHandler();
// PUBLISH this level
handler.setLevel(Level.FINER);
logger.addHandler(handler);
System.out.println("Logging level is: " + logger.getLevel());
for (int ii=0; ii<3; ii++) {
logger.log(Level.FINE, ii + " " + (ii*ii));
logger.log(Level.INFO, ii + " " + (ii*ii));
}
}
}
Ответы
Ответ 1
Журналы регистрируют сообщение только, т.е. создают записи журнала (или протоколируют запросы). Они не публикуют сообщения в пункты назначения, о которых заботятся обработчики. Установка уровня регистратора приводит к тому, что он создает записи журнала, соответствующие этому уровню или выше.
Возможно, вы используете ConsoleHandler
(я не мог заключить, где ваш вывод - System.err или файл, но я бы предположим, что это первый), который по умолчанию публикует записи журнала уровня Level.INFO
. Вам нужно будет настроить этот обработчик, чтобы опубликовать записи журнала уровня Level.FINER
и выше для желаемого результата.
Я бы рекомендовал прочитать руководство Java Logging Overview, чтобы понять базовый дизайн. Руководство охватывает разницу между концепцией Logger и обработчиком.
Редактирование уровня обработчика
1. Использование файла конфигурации
Файл свойств java.util.logging(по умолчанию это файл logging.properties
в JRE_HOME/lib
) можно изменить, чтобы изменить уровень по умолчанию для ConsoleHandler:
java.util.logging.ConsoleHandler.level = FINER
2. Создание обработчиков во время выполнения
Это не рекомендуется, поскольку это приведет к переопределению глобальной конфигурации. Использование этого во всей базе кода приведет к возможно неуправляемой конфигурации регистратора.
Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);
Ответ 2
Почему
java.util.logging имеет корневой регистратор, который по умолчанию имеет значение Level.INFO
, и прикрепленный к нему консольныйHandler, который также по умолчанию имеет значение Level.INFO
.
FINE
меньше, чем INFO
, поэтому прекрасные сообщения не отображаются по умолчанию.
Решение 1
Создайте регистратор для всего вашего приложения, например. от имени вашего пакета или использовать Logger.getGlobal()
и подключить к нему свой собственный консольный журнал.
Затем либо попросите root logger заткнуться (чтобы избежать дублирования вывода сообщений более высокого уровня), либо попросите вашего регистратора не пересылать журналы в root.
public static final Logger applog = Logger.getGlobal();
...
// Create and set handler
Handler systemOut = new ConsoleHandler();
systemOut.setLevel( Level.ALL );
applog.addHandler( systemOut );
applog.setLevel( Level.ALL );
// Prevent logs from processed by default Console handler.
applog.setUseParentHandlers( false ); // Solution 1
Logger.getLogger("").setLevel( Level.OFF ); // Solution 2
Решение 2
В качестве альтернативы вы можете опустить панель корневого регистратора.
Вы можете установить их по коду:
Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler
Или с файлом конфигурации ведения журнала, если вы используете его:
.level = FINE
java.util.logging.ConsoleHandler.level = FINE
Уменьшая глобальный уровень, вы можете начать просмотр сообщений из основных библиотек, например, из некоторых компонентов Swing или JavaFX.
В этом случае вы можете установить Filter в корневом журнале для фильтрации сообщений не из вашей программы.
Ответ 3
почему мой java-журнал не работает
предоставляет файл jar, который поможет вам понять, почему ваш вход в систему работает не так, как ожидалось.
Это дает вам полную отдачу от того, какие регистраторы и обработчики были установлены и какие уровни установлены и на каком уровне в иерархии протоколирования.
Ответ 4
Я нашел свою актуальную проблему, и она не упоминалась ни в одном ответе: некоторые из моих модульных тестов приводили к тому, что код инициализации регистрации был запущен несколько раз в одном наборе тестов, испорчая регистрацию последующих тестов.
Ответ 5
Пробовал другие варианты, это может быть правильно
Logger logger = Logger.getLogger(MyClass.class.getName());
Level level = Level.ALL;
for(Handler h : java.util.logging.Logger.getLogger("").getHandlers())
h.setLevel(level);
logger.setLevel(level);
// this must be shown
logger.fine("fine");
logger.info("info");