为什么没有显示Level.FINE日志消息?

And*_*son 109 java logging java.util.logging

状态的JavaDocsjava.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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

产量

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 . . .
Run Code Online (Sandbox Code Playgroud)

问题陈述

我的示例设置为Levelto FINER,所以我期望每个循环看到2条消息.相反,我看到每个循环都有一条消息(Level.FINE消息丢失).

需要改变什么才能看到FINE(FINERFINEST)输出?

更新(解决方案)

感谢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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Vin*_*lds 121

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

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

我建议阅读Java Logging Overview指南,以了解底层设计.该指南介绍了Logger和Handler概念之间的区别.

编辑处理程序级别

1.使用配置文件

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

java.util.logging.ConsoleHandler.level = FINER
Run Code Online (Sandbox Code Playgroud)

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

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

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);
Run Code Online (Sandbox Code Playgroud)

  • 更改全局JRE库中的logging.properties是可管理的吗? (7认同)
  • 别客气.是的,如果一个人已经编写了简单地将字符串转储到文件,控制台等中的记录器,那么设计确实会找到你. (3认同)
  • 谢谢.这就是诀窍.我现在意识到为什么我最初很困惑.我之前曾使用过日志记录级别,但我当时的实现只是将每条记录的消息都放入显示的列表中,而不考虑`Handler`. (2认同)
  • 请注意,记录器本身的级别必须比处理程序的级别更少限制.在记录Java之前,检查记录器和处理程序之间的最大级别.所以如果你只设置handler.setLevel(Level.FINER); 您将看不到任何内容,因为默认记录器级别为Level.INFO.您必须将其设置为FINER,FINEST或ALL.说logger.setLevel(Level.ALL); (2认同)

She*_*epy 25

为什么

java.util.logging有一个默认的根记录器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
Run Code Online (Sandbox Code Playgroud)

解决方案2

或者,您可以降低根记录器的栏.

您可以通过代码设置它们:

Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler
Run Code Online (Sandbox Code Playgroud)

或者使用日志配置文件,如果您使用它:

.level = FINE
java.util.logging.ConsoleHandler.level = FINE
Run Code Online (Sandbox Code Playgroud)

通过降低全局级别,您可能会开始看到来自核心库的消息,例如来自某些Swing或JavaFX组件的消息.在这种情况下,您可以在根记录上设置过滤器,以过滤掉不是来自程序的消息.


Joe*_*ong 9

为什么

正如@Sheepy 所提到的,它不起作用的原因是它java.util.logging.Logger的根记录器默认为Level.INFO,并且ConsoleHandler附加到该根记录器的也默认为Level.INFO. 因此,为了看FINE(,FINERFINEST)输出,你需要设置根记录器的默认值,其ConsoleHandlerLevel.FINE如下:

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);
Run Code Online (Sandbox Code Playgroud)


你的更新问题(解决方案)

正如@mins 所提到的,您将在控制台上为INFO及以上打印两次消息:首先由匿名记录器打印,然后由其父记录器,默认情况下也ConsoleHandler设置为的根记录器INFO。要禁用根记录器,您需要添加以下代码行:logger.setUseParentHandlers(false);

还有其他方法可以防止日志被@Sheepy 提到的根记录器的默认控制台处理程序处理,例如:

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );
Run Code Online (Sandbox Code Playgroud)

Logger.getLogger("").setLevel( Level.OFF );不会工作,因为它只阻止直接传递给根记录器的消息,而不是来自子记录器的消息。为了说明它是如何Logger Hierarchy工作的,我画了下图:

在此处输入图片说明

public void setLevel(Level newLevel)设置日志级别,指定此记录器将记录哪些消息级别。低于此值的消息级别将被丢弃。级别值 Level.OFF 可用于关闭日志记录。如果新级别为空,则意味着此节点应从其最近的祖先继承其级别,并具有特定(非空)级别值。