0

java.util.logging.Logger не учитывает уровень java.util.logging.Level?

17

В обычной среде Java SE 6:

Logger l = Logger.getLogger("nameless");
l.setLevel(Level.ALL);
l.fine("somemessage");

В консоли Eclipse ничего не отображается. Вызовы l.info("") и выше работают нормально, но всё, что ниже уровня fine, просто не показывается. В чем может быть проблема? Заранее благодарю.

5 ответ(ов)

0

Да, вы правы. Даже если уровень логгирования (Logger level) установлен на ALL, обработчик консоли (ConsoleHandler), который по умолчанию используется в логгере, имеет уровень по умолчанию INFO. Это поведение определяется настройками в файле logging.properties, который располагается в директории JAVA_HOME/jre/lib.

Чтобы изменить уровень логгирования для ConsoleHandler на более детальный, вам нужно explicitly установить его уровень. Вы можете сделать это следующим образом:

import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MyLogger {
    private static final Logger logger = Logger.getLogger(MyLogger.class.getName());

    static {
        // Устанавливаем уровень логгирования для конкретного handler'а
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setLevel(Level.ALL);
        logger.addHandler(consoleHandler);
        logger.setLevel(Level.ALL);
    }

    public void logMessages() {
        logger.severe("Severe message");
        logger.warning("Warning message");
        logger.info("Info message");
        logger.config("Config message");
        logger.fine("Fine message");
        logger.finer("Finer message");
        logger.finest("Finest message");
    }

    public static void main(String[] args) {
        new MyLogger().logMessages();
    }
}

Таким образом, вы гарантированно увидите все сообщения, начиная с уровня ALL, включая более детальные уровни DEBUG и TRACE. Не забудьте, что если вы используете другие обработчики или конфигурации в вашем приложении, вам может потребоваться обновить их соответствующим образом.

0

Вместо того чтобы перебор всех обработчиков и установки уровня логирования, я предпочитаю установить уровень только для консольного обработчика. Вот пример кода на Java, который демонстрирует этот подход:

// Получаем корневой логгер
Logger topLogger = java.util.logging.Logger.getLogger("");

// Обработчик для консоли (повторно используем, если он уже существует)
Handler consoleHandler = null;

// Проверяем, есть ли уже консольный обработчик
for (Handler handler : topLogger.getHandlers()) {
    if (handler instanceof ConsoleHandler) {
        // Найден консольный обработчик
        consoleHandler = handler;
        break;
    }
}

if (consoleHandler == null) {
    // Консольный обработчик не найден, создаем новый
    consoleHandler = new ConsoleHandler();
    topLogger.addHandler(consoleHandler);
}

// Устанавливаем уровень логирования для консольного обработчика на FINEST:
consoleHandler.setLevel(java.util.logging.Level.FINEST);

В этом коде мы сначала пытаемся найти существующий консольный обработчик, чтобы избежать создания нового, если он уже есть. Если он не найден, мы создаем новый и добавляем его к корневому логгеру, а затем устанавливаем требуемый уровень логирования. Такой подход позволяет более эффективно управлять обработчиками логирования.

0

В вашем вопросе правильно подмечено, что оба уровня логирования — уровень логгера и уровень обработчика — важны для того, чтобы сообщения лога отображались корректно. Давайте разберемся подробнее.

Когда вы устанавливаете уровень логгера и обработчика на FINEST, это позволяет сообщениям с этим уровнем и выше проходить через оба фильтра (логгер и обработчик). Если хотя бы один из уровней ниже необходимого, сообщение будет заблокировано.

Примеры:

  1. Если у вас есть Logger myLogger с уровнем FINEST и обработчик ConsoleHandler myHandler с уровнем INFO:

    • При вызове myLogger.fine("foo") сообщение успешно проходит через фильтр логгера, но блокируется фильтром обработчика, так как уровень INFO выше, чем FINE. В результате ничего не выводится.
    • При вызове myLogger.info("foo") сообщение проходит оба фильтра, и "foo" выводится.
  2. Теперь, если у вас Logger myLogger с уровнем INFO и обработчик ConsoleHandler myHandler с уровнем FINEST:

    • Вызов myLogger.fine("foo") будет заблокирован фильтром логгера (уровень INFO не допускает FINE), и, следовательно, ничего не выводится.
    • Вызов myLogger.info("foo") проходит оба фильтра, и "foo" выводится.
  3. Наконец, когда и у логгера, и у обработчика уровень установлен на FINEST:

    • Вызов myLogger.fine("foo") проходит оба фильтра и выводит "foo".
    • Вызов myLogger.info("foo") также проходит оба фильтра, и "foo" выводится.

Итог:

Вы должны убедиться, что оба уровня логирования (логгера и обработчика) соответствуют или ниже уровня сообщения, которое вы хотите вывести. Если вы хотите, чтобы все уровни выводились, просто установите оба уровня на FINEST.

0

Чтобы настроить уровень логирования в Java, необходимо установить уровень логирования как для обработчиков (handlers), так и для самого логгера. Логирование будет выполняться на самом "грубом" из этих уровней. Ниже представлен класс для логирования, который решает эту задачу.

import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class Log {

    private static final Logger logger = Logger.getGlobal();

    private static Level logLevel = Level.INFO;
    static {
        // Удаляем все обработчики по умолчанию (обычно это один консольный обработчик)
        Logger rootLogger = Logger.getLogger("");
        Handler[] rootHandlers = rootLogger.getHandlers();
        for (Handler handler : rootHandlers) {
            rootLogger.removeHandler(handler);
        }

        // Добавляем собственный обработчик
        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel(logLevel);
        handler.setFormatter(new LogFormatter());
        logger.addHandler(handler);
        logger.setLevel(logLevel);
    }

    public static class LogFormatter extends Formatter {
        @Override
        public String format(LogRecord record) {
            String stackTrace = "";
            Throwable thrown = record.getThrown();
            if (thrown != null) {
                StringWriter stacktraceWriter = new StringWriter();
                try (PrintWriter writer = new PrintWriter(stacktraceWriter)) {
                    thrown.printStackTrace(writer);
                }
                stackTrace = stacktraceWriter.toString();
            }
            return ZonedDateTime.ofInstant(Instant.ofEpochMilli(record.getMillis()), ZoneId.of("UTC"))
                    .format(DateTimeFormatter.ISO_ZONED_DATE_TIME) + "\t" + record.getLevel()
                    + "\t" + record.getMessage() + "\n" + stackTrace;
        }
    }

    private static final String classname = Log.class.getName();

    private static String callerRef() {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        if (stackTraceElements.length < 4) {
            return "";
        } else {
            int i = 1;
            for (; i < stackTraceElements.length; i++) {
                if (stackTraceElements[i].getClassName().equals(classname)) {
                    break;
                }
            }
            for (; i < stackTraceElements.length; i++) {
                if (!stackTraceElements[i].getClassName().equals(classname)) {
                    break;
                }
            }
            if (i < stackTraceElements.length) {
                return stackTraceElements[i].toString();
            } else {
                return "[в неизвестном методе]";
            }
        }
    }

    public static void setLogLevel(Level newLogLevel) {
        logLevel = newLogLevel;
        for (Handler handler : logger.getHandlers()) {
            handler.setLevel(newLogLevel);
        }
        Log.logger.setLevel(newLogLevel);
    }

    public static int getLevelNum() {
        return logLevel.intValue();
    }

    public static int getLevelNum(Level level) {
        return level.intValue();
    }

    public static void fine(String msg) {
        logger.log(Level.FINE, msg);
    }

    public static void info(String msg) {
        logger.log(Level.INFO, msg);
    }

    public static void warning(String msg) {
        logger.log(Level.WARNING, msg + "\t " + callerRef());
    }

    public static void error(String msg) {
        logger.log(Level.SEVERE, msg + "\t " + callerRef());
    }

    public static void exception(String msg, Throwable cause) {
        logger.log(Level.SEVERE, msg + "\t " + callerRef(), cause);
    }

}

Этот класс создает логгер, который выводит сообщения в консоль в формате, который включает временную метку, уровень логирования и само сообщение. Вы можете настраивать уровень логирования через метод setLogLevel(). Убедитесь, что уровень логирования установлен как для логгера, так и для его обработчиков, иначе сообщения могут не отображаться.

0

Другие пользователи уже предоставили хорошие ответы на вопрос, почему это произошло (у ConsoleHandler есть отдельная переменная уровня). Я повторно использую уровень логирования моему приложению и копирую его вверх по иерархии. Это также предоставляет простой способ обновлять уровни в любое время во время выполнения.

// Устанавливаем одинаковый уровень для всех логгеров и обработчиков вверх до родительского уровня
// OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL
Logger logger = Logger.getLogger(this.getClass().getPackage().getName());
// Level level = Level.parse("FINEST");
Level level = logger.getLevel();
Logger tempLogger = logger;
while(tempLogger != null) {
   tempLogger.setLevel(level);
   for(Handler handler : tempLogger.getHandlers())
      handler.setLevel(level);
   tempLogger = tempLogger.getParent();
}

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь