122

状态的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));
        }
    }
}

输出

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

问题陈述

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

问题

为了看到FINE(, FINERor FINEST) 输出需要改变什么?

更新(解决方案)

感谢Vineet Reynolds 的回答,这个版本符合我的预期。它显示 3 xINFO消息和 3 xFINE消息。

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

7 回答 7

132

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

您可能正在使用一个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

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

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

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);
于 2011-06-11T11:53:21.120 回答
31

为什么

java.util.logging 有一个Level.INFO默认为Level.INFO. FINE低于INFO,所以默认不显示细消息。


解决方案 1

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

于 2015-08-06T10:10:09.470 回答
10

为什么

正如@Sheepy 所提到的,它不起作用的原因是它java.util.logging.Logger有一个默认为 的根记录器Level.INFO,并且ConsoleHandler附加到该根记录器也默认为Level.INFO. 因此,为了查看FINE(, FINERor FINEST) 输出,您需要将根记录器及其默认值设置ConsoleHandlerLevel.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工作原理,我画了下图:

在此处输入图像描述

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

于 2018-01-26T03:29:24.860 回答
4

为什么我的 java 日志记录不起作用

提供了一个 jar 文件,可以帮助您找出为什么您的登录没有按预期工作。它为您提供了已安装的记录器和处理程序的完整转储,设置了哪些级别以及日志记录层次结构中的哪个级别。

于 2013-05-02T23:17:56.453 回答
1

尝试了其他变体,这可能是正确的

    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");
于 2017-08-15T07:05:13.783 回答
0

这个解决方案对我来说似乎更好,关于可维护性和变更设计:

  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) {
          // ...
       }
    }
    
于 2018-03-10T17:05:39.263 回答
0

我发现了我的实际问题,并且在任何答案中都没有提到:我的一些单元测试导致日志记录初始化代码在同一个测试套件中运行多次,从而弄乱了以后测试的日志记录。

于 2017-06-11T17:18:51.127 回答