Почему уровень.FINE logging сообщения не отображаются?

на 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 to FINER, так что я ожидал увидеть 2 сообщения для каждого цикла. Вместо этого я вижу одно сообщение для каждого цикла (Level.FINE сообщения отсутствуют).

вопрос

что нужно изменить, чтобы увидеть FINE (, FINER или FINEST) выходной?

обновление (решение)

спасибо ответ Винета Рейнольдса, эта версия работает в соответствии с моими ожиданиями. Он отображает 3хINFO сообщения, & 3xFINE сообщения.

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));
        }
    }
}

7 ответов


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

вы можете использовать ConsoleHandler (Я не мог определить, где ваш выход является системой.err или файл, но я бы предположил, что это первый), который по умолчанию публикация записей журнала уровня Level.INFO. Вам нужно будет настроить этот обработчик, чтобы опубликовать записи журнала уровня Level.FINER и выше, для желаемого результата.

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

редактирование уровня обработчика

1. С помощью Файл конфигурации

java.утиль.файл свойств журнала (по умолчанию это на JRE_HOME/lib) можно изменить, чтобы изменить уровень по умолчанию ConsoleHandler:

java.util.logging.ConsoleHandler.level = FINER

2. Создание обработчиков во время выполнения

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

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);

Почему

java.утиль.ведение журнала имеет корневой регистратор, который по умолчанию Level.INFO, и ConsoleHandler, прикрепленный к нему, который также по умолчанию Level.INFO. FINE меньше INFO, поэтому мелкие сообщения по умолчанию не отображаются.


Решение 1

создайте регистратор для всего вашего приложения, например, из вашего имени пакета или используйте Logger.getGlobal(), и подключить свой собственный ConsoleLogger к нему. Затем попросите 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. В этом случае вы можете установить фильтр на корневом регистраторе, чтобы отфильтровать сообщения не из вашей программы.


почему мой журнал java не работает

предоставляет файл jar, который поможет вам понять, почему ваш вход в систему не работает должным образом. Это дает вам полный дамп того, какие регистраторы и обработчики были установлены и какие уровни установлены и на каком уровне в иерархии ведения журнала.


почему

как упоминалось @Sheepy, причина, по которой он не работает, заключается в том, что java.util.logging.Logger имеет корневой регистратор, который по умолчанию Level.INFO и ConsoleHandler прикрепленный к этому корневому регистратору также по умолчанию Level.INFO. Поэтому, чтобы увидеть FINE (, FINER или FINEST) выходной, вам нужно установить значение по умолчанию для корневого регистратора и его ConsoleHandler до Level.FINE следующим образом:

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);


проблема обновления (решение)

как упоминалось @mins, вы будете иметь сообщения, напечатанные дважды на консоли для INFO и выше: сначала анонимным регистратором, затем его родителем, корневым регистратором, который также имеет ConsoleHandler значение INFO по умолчанию. Чтобы отключить корневой регистратор, необходимо добавить следующую строку кода:logger.setUseParentHandlers(false);

существуют другие способы предотвратить обработку журналов консольным обработчиком по умолчанию корневого регистратора, упомянутого @Sheepy, например:

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );

но Logger.getLogger("").setLevel( Level.OFF ); не будет работать, потому что он блокирует только сообщение, переданное непосредственно корневому регистратору, а не сообщение от дочернего регистратора. Чтобы проиллюстрировать, как Logger Hierarchy работает, я рисую следующую диаграмму:

enter image description here

public void setLevel(Level newLevel) установите уровень журнала, указав, какие уровни сообщений будут регистрироваться этим регистратором. Уровни сообщений ниже этого значения будут отброшены. Значение уровня Уровень.OFF можно использовать для отключения ведения журнала. Если новый уровень равен null, это означает, что этот узел должен наследовать свой уровень от своего ближайшего предка с определенным (ненулевым) значением уровня.


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


попробовал другие варианты, это может быть правильным

    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");

это решение кажется мне лучше, Что касается ремонтопригодности и дизайна для изменения:

  1. создайте файл свойств журнала, встраивая его в папку проекта ресурса, который будет включен в файл jar:

    # Logging
    handlers = java.util.logging.ConsoleHandler
    .level = ALL
    
    # Console Logging
    java.util.logging.ConsoleHandler.level = ALL
    
  2. Загрузить файл свойств из кода:

    public static java.net.URL retrieveURLOfJarResource(String resourceName) {
       return Thread.currentThread().getContextClassLoader().getResource(resourceName);
    }
    
    public synchronized void initializeLogger() {
       try (InputStream is = retrieveURLOfJarResource("logging.properties").openStream()) {
          LogManager.getLogManager().readConfiguration(is);
       } catch (IOException e) {
          // ...
       }
    }