Java日志记录打开“太多”日志文件

时间:2012-11-14 16:15:49

标签: java java.util.logging

这有点奇怪,但我是日志包及其属性的新手。我通过谷歌搜索找到的所有问题都是“如何让日志记录打开多个文件?”但我今天的问题是如何让它停止同时执行多个文件。我们走了......

首先要做的事情是:这个项目仅限于使用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控制台中,也出现在磁盘文件中。这是奇怪的部分:一旦applet运行,两个文件同时打开,包括TheProject0.0.log和TheProject1.0.log。当日志消息被触发时,它们同时显示在两个文件中。这两个文件在任何时候都是彼此的精确副本,包括达到最大大小并且(都是!)旋转时。

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

在任何给定时间,两个文件都被打开,或两者都关闭,我检查了。这并不像一个人比另一个人开的时间更长或更短。

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

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

2 个答案:

答案 0 :(得分:3)

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

  

重新初始化日志记录属性并重新读取日志记录   来自给定流的配置,应该在   java.util.Properties格式。之后将触发PropertyChangeEvent   阅读这些属性。

     

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

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

我认为您可能需要在致电reset()之前致电readConfiguration()

  

重置日志记录配置。

     

对于所有已命名的记录器,重置操作将删除并关闭所有记录器   处理程序和(根记录器除外)将级别设置为null。该   root logger的级别设置为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");
    }

}

答案 1 :(得分:1)

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

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

非常感谢你们所有人。我不确定如何将这一切标记为“封闭”......是时候把网站搞砸了。