Почему сообщения журнала 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");