确定FileHandler正在使用的文件

时间:2009-07-12 18:44:38

标签: java logging

我正在创建允许循环浏览文件的java.util.logging.FileHandler。运行我的应用程序的多个实例时,将为该应用程序的每个实例创建一个新的日志文件。我需要知道应用程序正在使用哪个文件,因为我想将日志文件上传到我的服务器以供进一步查看。如何判断某个FileHandler正在使用哪个文件?

4 个答案:

答案 0 :(得分:2)

最简单的方法是在文件名本身中放置某种标识符,即创建FileHandler时的pattern参数。由于这些是同一个应用程序的实例,区分它们的一种方法是通过它们的进程ID,因此您可以创建该模式的那一部分。更好的方法是通过命令行传入标识符并使​​用它来创建文件名。这样你可以控制在某种意义上创建的文件。最后,如果您的应用程序知道为什么它与其他所有应用程序不同,例如它连接到特定的数据库服务器,那么您可以将该数据库服务器名称用作文件名的一部分。

编辑:似乎没有任何API可以获取FileHandler正在使用的文件的名称。我建议查看x4juli中的日志记录扩展(它将很多log4j功能移植到java.util.logging规范中):

你应该能够替换提供getFile()方法的FileHandler实例:

答案 1 :(得分:1)

实际上,只需自己扩展FileHandler就可以做到这一点。例如......

MyFileHandler.java:

import java.io.IOException;
import java.util.logging.FileHandler;
public class MyFileHandler extends FileHandler {
    protected String _MyFileHandler_Patern;
    public MyFileHandler(String pattern) throws IOException {
        _MyFileHandler_Patern = pattern;
    }
    public String getMyFileHandlerPattern() {
        return _MyFileHandler_Patern;
    }
}

DeleteMe.java:

import java.io.IOException;
import java.util.logging.Handler;
import java.util.logging.Logger;
public class DeleteMe {
    public static void main(String[] args) throws IOException {
        Logger log = Logger.getLogger(DeleteMe.class.getName());
        MyFileHandler output = new MyFileHandler("output.log");
        log.addHandler(output);
        for (Handler handler : log.getHandlers()) {
            if (handler instanceof MyFileHandler) {
                MyFileHandler x = (MyFileHandler) handler;
                if ("output.log".equals(x.getMyFileHandlerPattern())) {
                    System.out.println("found hanlder writing to output.log");
                }
            }
        }
    }
}

答案 2 :(得分:0)

好的,我不得不说FileHandler没有提供确定日志文件的方法是非常愚蠢的。

我开始编写一个名为“chooseFile()”的函数,该函数在/ tmp中搜索下一个可用的日志文件名并返回该文件。然后,您可以将该文件的名称传递给新的FileHandler()。

/**
 * Utility: select a log file.  File is created immediately to reserve
 * its name.
 */
static public File chooseFile(final String basename) throws IOException {
    final int nameLen = basename.length();
    File tmpDir = new File(System.getProperty("java.io.tmpdir"));
    String[] logs = tmpDir.list(new FilenameFilter() {
        public boolean accept(File d, String f) { 
            return f.startsWith(basename);
        }
    });
    int count = 0;
    if (logs.length > 0) {
        for (String name : logs) {
            int n = atoi(name.substring(nameLen));
            if (n >= count) count = n + 1;
        }
    }
    String filename = String.format("%s%d.log", basename, count); 
    File logFile = new File(tmpDir, filename);
    logFile.createNewFile();
    return logFile;
}

答案 3 :(得分:0)

这是我相当愚蠢的方式。如果你不使用任何格式字符串,它适用于默认值,如果你在文件名中使用g和u格式字符串,而不是其他格式字符串,则它可以工作。

public class FriendlyFileHandler extends FileHandler {

    /***
     * In order to ensure the most recent log file is the file this one owns,
     * we flush before checking the directory for most recent file.
     * 
     * But we must keep other log handlers from flushing in between and making
     * a NEW recent file.
     */
    private static Object[] flushLock = new Object[0];

    private String pattern;

    public FriendlyFileHandler(String pattern, int maxLogLengthInBytes, int count) throws IOException,
            SecurityException {
        super(pattern, maxLogLengthInBytes, count);

        this.pattern = pattern;
    }

    /***
     * Finds the most recent log file matching the pattern.
     * This is just a guess - if you have a complicated pattern 
     * format it may not work.
     * 
     * IMPORTANT: This log file is still in use. You must 
     * removeHandler() on the logger first, .close() this handler, 
     * then add a NEW handler to your logger. THEN, you can read 
     * the file. 
     * 
     * Currently supported format strings: g, u
     * 
     * @return A File of the current log file, or null on error.
     */
    public synchronized File getCurrentLogFile() {

        synchronized(flushLock) {

            // so the file has the most recent date on it.
            flush();


            final String patternRegex =
                    // handle incremental number formats
                    pattern.replaceAll("%[gu]", "\\d*") +
                    // handle default case where %g is appended to end
                    "(\\.\\d*)?$";

            final Pattern re = Pattern.compile(patternRegex);
            final Matcher matcher = re.matcher("");

            // check all files in the directory where this log would be
            final File basedir = new File(pattern).getParentFile();
            final File[] logs = basedir.listFiles(new FileFilter() {

                @Override
                public boolean accept(final File pathname) {
                    // only get files that are part of the pattern
                    matcher.reset(pathname.getAbsolutePath());

                    return matcher.find();
                }

            });

            return findMostRecentLog(logs);
        }
    }

    private File findMostRecentLog(File[] logs) {

        if (logs.length > 0) {
            long mostRecentDate = 0;
            int mostRecentIdx = 0;

            for (int i = 0; i < logs.length; i++) {
                final long d = logs[i].lastModified();

                if (d >= mostRecentDate) {
                    mostRecentDate = d;
                    mostRecentIdx = i;
                }

            }

            return logs[mostRecentIdx];
        }
        else {
            return null;
        }

    }


    @Override
    public synchronized void flush() {

        // only let one Handler flush at a time.
        synchronized(flushLock) {
            super.flush();
        }
    }

}