我正在使用 java.util.logging
来记录我的应用程序的所有日志。
直到最近,我一直在使用没有任何特定配置的日志记录工具。一切都按预期工作,所有日志都在控制台 (stderr) 中可见
现在,我想为我的日志自定义配置。我希望日志显示在控制台上,但我也希望将它们写入文件中。我想出了以下解决方案:
public static void main(String[] args) {
System.setProperty("java.util.logging.config.file", "log.config");
Logger defLogger = Logger.getLogger("fr.def"); // all loggers I use begin by "fr.def"
defLogger.setLevel(Level.ALL);
defLogger.addHandler(new ConsoleHandler());
defLogger.addHandler(new FileHandler());
// real code here ...
这是 log.config
文件的内容:
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.count=10
java.util.logging.FileHandler.pattern=logs/visiodef2.%g.log
此解决方案大部分有效:我可以在控制台和文件中看到日志。除此之外,在某些情况下,一些日志消息会简单地丢失(对于控制台和文件)。日志丢失的情况示例:
- 在 JVM 的关闭钩子(Hook)上
- 在默认的未捕获异常处理程序上
- 关于 EDT 的异常处理程序
- 在主 JFrame 的 windowClosing 事件上(配置了默认的关闭操作 EXIT_ON_CLOSE)
除上述内容外,没有其他配置。不涉及日志级别:我可以看到一些 INFO 日志,但是一些丢失的日志是 SEVERE。
我还尝试添加一个关闭 Hook 来刷新所有处理程序,但没有成功。
那么,问题是:按照我的方式配置我的日志记录是否安全?您能看出某些日志丢失的原因吗?
最佳答案
我发现了问题。这很奇怪。
实际上,我的问题与日志发生在异常处理程序或框架事件中这一事实完全无关。问题是垃圾收集器在创建几秒钟后销毁了“fr.def”记录器!因此,FileHandler 也被销毁了。 GC 可以做到这一点,因为 LogManager 只保留对其创建的 Logger 的弱引用。
Logger.getLogger
的 javadoc 没有说明任何相关内容,但是前者调用的 LogManager.addLogger
的 javadoc 明确指出:
The application should retain its own reference to the Logger object to avoid it being garbage collected. The LogManager may only retain a weak reference.
因此,解决方法是保留对 Logger.getLogger("fr.def")
返回的对象的引用。
编辑
使用弱引用的选择似乎来自这个bug report .
关于java - 在少数特定情况下丢失的日志消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4050617/