Почему сообщения журнала Level.FINE не отображаются? - PullRequest
106 голосов
/ 11 июня 2011

Состояние 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)?

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

Благодаря ответу Винет Рейнольдс , эта версия работает в соответствии с моими ожиданиями. Он отображает 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));
        }
    }
}

Ответы [ 7 ]

118 голосов
/ 11 июня 2011

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

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

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

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

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);
24 голосов
/ 06 августа 2015

Почему

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


Решение 1

Создать регистратор для всего приложения, например от имени вашего пакета или используйте Logger.getGlobal() и подключите к нему свой собственный ConsoleLogger. Затем либо попросите корневой регистратор отключиться (чтобы избежать дублирования вывода сообщений более высокого уровня), либо попросите регистратор не пересылать журналы в корневой каталог.

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 в корневом логгере, чтобы отфильтровывать сообщения не из вашей программы.

4 голосов
/ 03 мая 2013

почему не работает логирование Java

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

3 голосов
/ 26 января 2018

ПОЧЕМУ

Как уже упоминалось @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) установите уровень журнала, указавкакие уровни сообщений будут регистрироваться этим регистратором.Уровни сообщений ниже этого значения будут отброшены.Значение уровня Level.OFF можно использовать для отключения регистрации.Если новый уровень равен нулю, это означает, что этот узел должен наследовать свой уровень от своего ближайшего предка с определенным (ненулевым) значением уровня.

0 голосов
/ 10 марта 2018

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

  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) {
          // ...
       }
    }
    
0 голосов
/ 15 августа 2017

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

    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");
0 голосов
/ 11 июня 2017

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

...