为什么 Level.FINE 日志记录消息未显示?

2022-08-31 08:47:47

JavaDocs for java.util.logging.Level state:


按降序排列的级别为:

  • 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 . . .

问题陈述

我的示例将 设置为 ,因此我期望每个循环看到 2 条消息。相反,我看到每个循环都有一条消息(消息丢失)。LevelFINERLevel.FINE

问题

为了看到(或)输出,需要改变什么?FINEFINERFINEST

更新(解决方案)

多亏了Vineet Reynolds的回答,这个版本按照我的期望工作。它显示3条消息和3条消息。INFOFINE

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

记录器仅记录消息,即他们创建日志记录(或日志记录请求)。它们不将消息发布到目标,而目标由处理程序负责。设置记录器的级别,只会导致它创建与该级别或更高级别匹配的日志记录。

您可能正在使用控制台处理程序(我无法推断您的输出是System.err或文件的位置,但我假设它是前者),它默认为发布该级别的日志记录。您必须配置此处理程序,以发布级别和更高级别的日志记录,以获得所需的结果。Level.INFOLevel.FINER

我建议阅读 Java 日志记录概述指南,以便了解底层设计。本指南介绍了记录器和处理程序概念之间的区别。

编辑处理程序级别

1. 使用配置文件

可以修改 java.util.logging 属性文件(默认情况下,这是 中的文件),以更改 ConsoleHandler 的默认级别:logging.propertiesJRE_HOME/lib

java.util.logging.ConsoleHandler.level = FINER

2. 在运行时创建处理程序

不建议这样做,因为这会导致覆盖全局配置。在整个代码库中使用此方法将导致可能无法管理的记录器配置。

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

答案 2

原因

java.util.logging 有一个默认为 的根记录器,以及一个附加到它的 ConsoleHandler,它也默认为 。 低于 ,因此默认情况下不显示精细消息。Level.INFOLevel.INFOFINEINFO


解决方案 1

为您的整个应用程序创建一个记录器,例如,从您的软件包名称或使用Logger.getGlobal(),并将您自己的控制台记录器挂接到它。然后,要求根记录器闭嘴(以避免更高级别的消息重复输出),或者要求记录器不要将日志转发到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 组件的消息。在这种情况下,您可以在根记录器上设置过滤器,以过滤掉不是来自程序的消息。


推荐