4

这有点奇怪,但我不熟悉日志记录包及其属性的使用。我可以通过谷歌搜索找到的所有问题都是“如何使日志记录打开多个文件?” 但我今天的问题是如何让它停止同时处理多个文件。开始了...

首先要做的事情:这个项目仅限于使用 java.util.logging,不,我不能切换到 log4j 或任何其他第三方包,是的,我知道它们应该更棒。:-)

所以当这个小程序启动时,它会运行这段代码:

import java.util.logging.Logger;
import java.util.logging.LogManager;

// in startup routine:
LogManager.getLogManager().readConfiguration(
  this.getClass().getResourceAsStream("/logging.properties"));

从 JAR 中提取属性文件并应用它们,这是可行的。应该从readConfiguration()VM 启动重置所有现有设置。项目的其余部分有像

private final static Logger LOGGER = Logger.getLogger(NameOfClass.class.getName());

我认为这是非常标准的。我们所有的类都在同一个包中(例如称为 TheProject),时髦的日志记录名称/属性层次结构遵循相同的约定,因为这正是 java.util.logging 喜欢滚动的方式。

logging.properties 文件最初是 Java 6 SE JRE 附带的文件的副本,然后进行了修改。现在看起来像这样:

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

# Default global logging level. 
.level=INFO

# Loggers 
# ------------------------------------------ 
# Loggers are usually attached to packages. 
# Here, the level for each package is specified. 
# The global level is used by default, so levels 
# specified here simply act as an override. 
java.level = INFO
javax.swing.level = INFO
sun.awt.level = INFO
theproject.level = ALL

# Handlers 
# -----------------------------------------
theproject.handlers=java.util.logging.FileHandler

# Override of global logging level 
java.util.logging.FileHandler.level=ALL

# Naming style for the output file: 
java.util.logging.FileHandler.pattern=/path/to/logfiles/TheProject%u.%g.log

所有这些都“有效”,因为日志消息显示在 Java 控制台中,也出现在磁盘文件中。这是奇怪的部分:只要小程序运行,就会同时打开两个文件,TheProject0.0.log 和 TheProject1.0.log。当日志消息被触发时,它们会同时出现在两个文件中。这两个文件在任何时候都是彼此的精确副本,包括何时达到最大大小并(两者!)旋转。

我检查了一次只运行一个 JRE VM。

我检查过,在任何给定时间,要么打开两个文件,要么都关闭。这不像一个比另一个开放的时间更长或更短。

如果日志文件已被另一个进程打开,则两个文件名之间不同的 %u 标记被记录为“解决冲突的唯一编号”,但我认为这里不是这种情况,因为两个日志都获得相同的数据而没有否则打开文件。(证据:Windows 不会让我在 VM 运行时删除任何一个文件,但一旦 VM 最终退出它就会删除。)

我是在属性文件中做一些愚蠢的事情,还是误解了如何正确加载属性,或者......?

4

2 回答 2

3

我认为不会readConfiguration()像您认为的那样有效。形成 JavaDocs:

重新初始化日志记录属性并从给定流中重新读取日志记录配置,该流应为 java.util.Properties 格式。读取属性后将触发 PropertyChangeEvent。

如果目标 Logger 存在,则新配置文件中的任何日志级别定义都将使用 Logger.setLevel() 应用。

我不确定这是否真的重置了日志记录配置,或者只是附加/更新当前配置。

我想你可能需要先打电话reset()再打电话 readConfiguration()

重置日志记录配置。

对于所有命名的记录器,重置操作删除并关闭所有处理程序,并且(除了根记录器)将级别设置为空。根记录器的级别设置为 Level.INFO。

编辑:只是为了表明您的属性文件没有问题,您可以在theproject包中创建一个名为 test 的类,如下所示并运行它。只需确保删除现有的日志文件,这样您就知道在运行时创建了多少。

package theproject;

import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class Test {

    private final static Logger LOGGER = Logger.getLogger(Test.class.getName());

    public static void main(String[] args) throws Exception {
        LogManager.getLogManager().readConfiguration(
                  Test.class.getResourceAsStream("/logging.properties"));
//      The only way I could get it to create two log files was to uncomment the line below that
//      adds another FileHandler to the root logger.
//      LogManager.getLogManager().getLogger("").addHandler(new FileHandler("/path/to/logfiles/TheProject%u.%g.log"));
        Test test = new Test();
    }   

    public Test(){
        LOGGER.log(Level.INFO, "Info");
    }

}
于 2012-11-14T17:16:47.447 回答
1

@Joop 确定了它(在评论中,不能标记为答案)。事实证明,设置处理程序是一个附加过程,它不会简单地覆盖以前的设置。这对我来说似乎真的很不直观,但那是 java.util.logging 对你来说......保留所有其他属性,但删除处理程序分配,是要走的路。

我也在使用@jschoen 建议的 reset() 调用,因为这似乎是一件很聪明的事情!

非常感谢你们所有人。我不知道如何将这一切标记为“关闭”……是时候摆弄一下网站了。

于 2012-11-14T19:09:00.713 回答