更改日志记录级别后,什么捕获了日志文件?

时间:2019-08-29 15:03:39

标签: java logging java-11 java.util.logging

我创建了一个简单的应用程序来测试java.util.logging的行为:

 public static void main(String[] args) {
     Logger logger = Logger.getLogger("sample-name");

     logger.log(Level.SEVERE, "SEVERE");
     logger.log(Level.WARNING, "WARNING");
     logger.log(Level.INFO, "INFO");
     logger.log(Level.CONFIG, "CONFIG");
     logger.log(Level.FINE, "FINE");
     logger.log(Level.FINER, "FINE");
     logger.log(Level.FINEST, "FINEST");
 }

并启用了日志记录到 /usr/lib/jvm/java-11-openjdk/conf/logging.properties 中的文件:

handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

当我在此文件( .level INFO 中保留日志记录级别时,它可以工作。我的 user.home 中有一个java0.log输出文件,内容如下:

Aug 29, 2019 4:57:48 PM main.LoggingTester main
SEVERE: SEVERE
Aug 29, 2019 4:57:48 PM main.LoggingTester main
WARNING: WARNING
Aug 29, 2019 4:57:48 PM main.LoggingTester main
INFO: INFO

但是我要记录所有-将其更改为 ALL 后的ant,发生一些奇怪的事情-这是输出文件的内容:

Aug 29, 2019 5:00:32 PM com.sun.jna.Native extractFromResourcePath
FINE: Looking in classpath from java.net.URLClassLoader@5305068a for /com/sun/jna/linux-x86-64/libjnidispatch.so
Aug 29, 2019 5:00:32 PM com.sun.jna.Native extractFromResourcePath
FINE: Found library resource at jar:file:/opt/intellij/idea-IC-191.6707.61/lib/jna.jar!/com/sun/jna/linux-x86-64/libjnidispatch.so
Aug 29, 2019 5:00:32 PM com.sun.jna.Native extractFromResourcePath
FINE: Extracting library to /home/iid/.cache/JNA/temp/jna7163336009872108237.tmp
Aug 29, 2019 5:00:32 PM com.sun.jna.Native loadNativeDispatchLibraryFromClasspath
FINE: Trying /home/iid/.cache/JNA/temp/jna7163336009872108237.tmp
Aug 29, 2019 5:00:32 PM com.sun.jna.Native loadNativeDispatchLibraryFromClasspath
FINE: Found jnidispatch at /home/iid/.cache/JNA/temp/jna7163336009872108237.tmp

此外,还会创建 java0.log.lock 文件。

我猜还有别的东西需要这个日志并写入日志?因为此设置是全局的。 但是,即使我的应用程序已经寿终正寝,锁仍然存在,并且我希望其他一些日志文件实际上也包含我的消息……

2 个答案:

答案 0 :(得分:1)

  

更改日志记录级别后,什么捕获了日志文件?

第三方库Java Native Access

  

但是我想记录所有-将其更改为全部后,ant会发生一些奇怪的事情

如果您在logging.properties中将.level更改为ALL,则您已将ROOT记录器的级别更改为ALL,这意味着所有记录器将继承该级别并将其设置为'ALL'。除非明确覆盖该级别。

  

我猜还有别的东西需要这个日志并写入日志?

使用JUL的任何第3方库也将开始写入您的日志文件。在这种情况下,com.sun.jna.Native

您最可能想做的是将日志记录配置更改为:

handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=ALL
.level=INFO
sample-name.level=ALL
sample-name.handlers=java.util.logging.FileHandler
java.util.logging.FileHandler.level=ALL

这会将ROOT记录器保留为默认设置,并将您的名称空间设置为记录所有级别。

  

此外,创建了java0.log.lock文件。

当FileHandler打开并没有关闭时,就会发生这种情况。最有可能在LogManager清除程序运行之前,记录器已被垃圾回收。将程序更改为:

private static final Logger logger = Logger.getLogger("sample-name");
public static void main(String[] args) {
    logger.log(Level.SEVERE, "SEVERE");
    logger.log(Level.WARNING, "WARNING");
    logger.log(Level.INFO, "INFO");
    logger.log(Level.CONFIG, "CONFIG");
    logger.log(Level.FINE, "FINE");
    logger.log(Level.FINER, "FINE");
    logger.log(Level.FINEST, "FINEST");
}

强制终止正在运行的JVM也将导致悬挂的“ lck”文件。

  
      
  1. 我想我理解您的建议,但是-我想问一下为什么会这样,而不是如何更改我的配置。我希望它会将来自所有记录器的消息放在那里。
  2.   

为什么在design docsAPI docs和经常被忽视的java.util.logging bugs中得到回答。设置根级别意味着您也可以获得JVM记录器,因为它们是根记录器的子代。

handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler行将2个处理程序附加到根记录器。根记录器是所有记录器的父记录器,并由空字符串""

表示

在运行时,记录器树如下所示:

           "" ->java.util.logging.FileHandler, java.util.logging.ConsoleHandler
           |
         -----------------------
         ^                  ^
         |                  |
    sample-name      com.sun.jna.Native

根据记录概述部分1.1 Overview of Control Flow,两个子记录器的记录都将发送到parent handlers。记录器树中的库记录器和应用程序记录器如此不同。

  

除非其中有很多,并且日志文件被以某种方式剪切和替换了?

FileHandler defaults are specified in the API docs.默认是创建一个无限制的日志文件。

  
      
  1. 锁定文件仅在日志级别为ALL(而不是INFO)时显示。似乎与垃圾收集器有关吗?
  2.   

Lazily created loggersgarbage collection of loggers在运行时会创建有趣的行为,因为它们没有强有力的参考来阻止它们成为G.C。始终以静态最终形式引用记录器,以免引起意外。

'。lck'文件仅指示打开的文件处理程序。 .lck'在处理程序关闭时消失。如果为file handler is created or closed,则更改日志级别不会更改。 handlers.handlers的使用表示filehandler is created lazily when a log record is published

  

...但是问题是我原来的记录消息消失了。我希望其他任何记录器都可以汇总到日志文件中,并且不要替换。

Follow the tracing and printing instructions in this thread.这将记录正在修改记录器设置的调用方并打印记录器树的状态。

  

我仍然不明白为什么更改日志级别会导致此锁定。在任何一种情况下,我都不会明确关闭处理程序。

将日志记录属性更改为使用.handlers而不是handlers。无论使用点处理程序的级别如何,您都应该在运行时看到锁定文件。如果那是正确的,那么我上面的理论是正确的。

您不需要显式关闭处理程序,只要它是attached到记录器树即可。如果从记录器中显式删除了处理程序,则该代码负责关闭处理程序。否则,在正常关闭JVM时,LogManager $ Cleaner会为您关闭处理程序。

答案 1 :(得分:-1)

别忘了将处理程序的级别也更改为ALL。 ConsoleHandler的默认级别为INFO-因此,如果仅更改记录器的级别,则日志消息可能仍会被处理程序过滤。

我知道我误解了您的问题,因此这里提供了一条额外的(希望是更相关的)信息:

实际上,LogManager强烈引用了具有全局配置文件附加处理程序的记录器。他们不会被垃圾收集。这是因为,否则,如果附加了该处理程序的记录器已经消失并且不再被引用,则在JVM关闭时可能无法正确关闭该处理程序。因此,除非处理程序被应用程序以编程方式关闭,否则锁定文件将保持不变,并且日志文件将保持打开状态以供写入,直到JVM关闭为止。