Identify the file used by FileHandler

I am creating one java.util.logging.FileHandlerthat is allowed to cycle through files. When I run multiple instances of my application, a new log file is created for each instance of the application. I need to know which file is used by the application because I want to upload the log file to my servers for further consideration. How can I determine which file is used by a specific FileHandler?

+5
source share
4 answers

The easiest way is to specify some kind of identifier in the file name itself, i.e. argument patternwhen creating FileHandler. Since these are instances of the same application, one way to distinguish them is through the process identifier, so you can do this part of the template. The best approach is to pass the identifier through the command line and use this to create the file name. This way you control the files you create in a way. Finally, if your application has some knowledge of why it is different from everyone else, for example, it connects to a specific database server, you can simply use this database server name as part of the file name.

EDIT: , API, , FileHandler. x4juli ( log4j java.util.logging):

FileHandler, getFile():

+2

, , 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");
                }
            }
        }
    }
}
+1

, , FileHandler .

"selectFile()", /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;
}
0

Here is my pretty hacky way around it. It works by default if you do not use format strings and should work if you use g and u format strings in the file name, but not others.

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();
        }
    }

}
0
source

All Articles