首页 > 解决方案 > 更改日志记录级别后,什么会捕获我的日志记录文件?

问题描述

我创建了简单的应用程序来测试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

当我在此文件(.levelINFO中保留日志记录级别时,它可以工作文件。我的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 更改为ALL后记录它,发生了一些奇怪的事情 - 这是输出文件的内容:

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文件。

我猜还有什么东西会拿走这个日志并写入它?因为这个设置是全局的。但是即使我的应用程序完成了它的生命,锁仍然存在,我希望其他一些日志文件,它实际上也包含我的消息......

标签: javaloggingjava-11java.util.logging

解决方案


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

第 3 方库Java Native Access

但是我想在将其更改为 ALL 后记录 ALL - ant,发生了一些奇怪的事情

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

我猜还有什么东西会拿走这个日志并写入它?

任何使用 JUL 的第三方库也将开始写入您的日志文件。在这种情况下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. 我想我理解你的建议,但仍然 - 我想问一下它为什么会这样,而不是我应该如何更改我的配置。我希望它能把我所有记录器的消息放在那里。

为什么在设计文档API 文档和经常被忽视的java.util.logging 错误中得到解答。设置根级别意味着您也可以获得 JVM 记录器,因为它们是根记录器的子级。

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

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

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

根据日志记录概述部分1.1 控制流概述来自两个子记录器的记录将被发送到父处理程序。记录器树中的库记录器和应用程序记录器之间存在如此大的区别。

除非它们很多,并且日志文件以某种方式被剪切和替换?

FileHandler 默认值在 API 文档中指定。 默认是创建一个没有限制的日志文件。

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

惰性创建的记录器和记录器的垃圾收集在运行时会在运行时创建有趣的行为,因为它们没有强引用来防止它们被 GC 始终持有对记录器的引用作为静态最终以避免意外。

'.lck' 文件只是表示一个打开的文件处理程序。当处理程序关闭时,.lck' 会消失。如果创建或关闭文件处理程序,则更改日志级别不会更改。使用handlersvs..handlers意味着文件处理程序是在发布日志记录时延迟创建的

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

按照此线程中的跟踪和打印说明进行操作。 这将记录正在修改记录器设置的调用者并打印记录器树的状态。

而且我仍然不明白为什么更改日志级别会导致此锁定。我没有明确关闭处理程序 - 在任何这些情况下。

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

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


推荐阅读