2

Yes this question has been asked before however the issue is a little more complex it seems. I have used all solutions from previous questions that relate to this.

Relates to: Freeing Java File Handles , Java keeps file locks no matter what

package me.test;

import java.io.File;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class Test {
    Logger log = Logger.getAnonymousLogger();
    FileHandler handle;

    final static String newline = System.lineSeparator();
    /**
     * @param args
     */
    public static void main(String[] args) {
        Test t = new Test();
        t.run();
    }
    public void run()
    {
        for (int i = 0; i < 6; i++) {
            testLogs();
            change();
        }
        testLogs();
        if (handle != null)
        {
            handle.close();
            log.removeHandler(handle);
        }
    }
    public static FileHandler craftFileHandler(File file, boolean append)
    {
        if (file == null)
            return null;
        FileHandler fh = null;
        try {
            fh = new FileHandler(file.getPath(), append);
            fh.setFormatter(new Formatter() {

                @Override
                public String format(LogRecord record) {
                    return "[test] " + "[" + record.getLevel().toString() + "]" + String.format(record.getMessage(), record.getParameters()) + newline;
                }
            });
            return new FileHandler(file.getPath(), append);
        } catch (Exception e) {
            if (fh != null)
                fh.close();
            return null;
        } 
    }

    public void change()
    {
        if (handle != null)
        {
            handle.flush();
            handle.close();
            log.removeHandler(handle);
        }
        handle = null;
        File f = new File("log.log");
        handle = craftFileHandler(f, true);
        System.out.println(f.getAbsolutePath());
        if (handle != null)
            log.addHandler(handle);
    }
    public void testLogs()
    {
        if (log == null)
        {
            log = Logger.getLogger("test");
            log.setLevel(Level.ALL);
        }
        log.info("This is info #1");
        log.warning("Warning 1");
        log.info("meh info again.");
        log.severe("SEVERE HELL YA NICE TEST");
        log.info("You sure its good here?");
        log.info("Handler count " + log.getHandlers().length);
    }
}

This code is meant to be a test code. I made this test file so I can figure out how to fix this issue on a project I have.

The reason I have a loop of this is because the issue occurs too fast to explain. So a loop was the best way to simulate it. In my project there is a config for a Log file to choose where to put it. But if the file is not changed in config on its reload. It tends to leave the file locked and create extra files EVERY reload

I would like to get this working. If this starts working properly. Then I can properly implement it on my project.

Community
  • 1
  • 1
CoasterChris
  • 91
  • 1
  • 10
  • My code looks messy in this post. I will be updating post with cleaner code. Making sure it results in same issue. Then I will try to see best answer and post more about it after researching what is going wrong. – CoasterChris Aug 23 '13 at 16:59

4 Answers4

2

Always close resources inside finally block-

try {
    fh = new FileHandler(file.getPath(), append);
    fh.setFormatter(new Formatter() {

    @Override
    public String format(LogRecord record) {
        return "[test] " + "[" + record.getLevel().toString() + "]" + String.format(record.getMessage(), record.getParameters()) + newline;
    }
    });
    return new FileHandler(file.getPath(), append);
} catch (Exception e) {

    return null;
    // never close in catch

} finally {
    //  lastly close anything that may be open
    if (fh != null){
        try {
            fh.close();
        } catch (Exception ex){
            // error closing   
        }
    }
}
Sajal Dutta
  • 18,272
  • 11
  • 52
  • 74
  • How would this work when you are returning an object (Exiting the try statement essentially) – CoasterChris Aug 23 '13 at 01:06
  • 2
    @CoasterChris That's the beauty of it. The return statement inside try will store the handler until the finally block is done and then return. finally always gets executed unless of course you switch off the computer. The same thing goes for catch. Before returning null, finally will get executed and then the null will be returned. – Sajal Dutta Aug 23 '13 at 01:09
  • Dutta I thank you for this. I did attempt the try block. The jvm has now confused me. But the close statements should have worked either way. Have you seen the close statements elsewhere in code? Any ideas on how that does not work? – CoasterChris Aug 23 '13 at 01:11
  • @CoasterChris No problem..but how do you know 'close' statement was not executed? Can you debug line by line and see? – Sajal Dutta Aug 23 '13 at 01:14
  • They are executed. But the file locks remain. I can debug line by line. It says they are executed. It may be failing silently as it states in the javadocs of the stream's documentation. EDIT: Forgot i was reading the logger removeHandler. It might not be same on .close() – CoasterChris Aug 23 '13 at 01:16
  • @CoasterChris Did you try my version with finally? It works I just tested. There's no .lck file. One thing though, you will always see handler = 1 in your console output at the end because you don't call testLogs() after removing handler from log in run() method. testLogs() should be called again at the end of run() method so you can see "INFO:Handler count 0" – Sajal Dutta Aug 23 '13 at 01:40
2

You are getting multiple files created because you are creating a FileHandler and never closing it.

fh = new FileHandler(file.getPath(), append);
...
return new FileHandler(file.getPath(), append);

The fix?

return fh;

Finally or not makes absolutely no difference. In this case, you actually do want to be closing in the catch block since nothing will be able to close it if you don't.

ricochet1k
  • 1,232
  • 9
  • 11
1

After use the log method close all handlers.

    this.logger.log(Level.SEVERE, (exception.getClass().getName() + ": " + exception.getMessage()) + "\r\n" + exception.getCause() + "\r\n" + "\r\n");

    for (Handler handler : this.logger.getHandlers())
    {
        handler.close();
    }
Alexandre
  • 363
  • 7
  • 20
0

Well, one issue is here:

 try {
            fh = new FileHandler(file.getPath(), append);
            fh.setFormatter(new Formatter() {

                @Override
                public String format(LogRecord record) {
                    return "[test] " + "[" + record.getLevel().toString() + "]" + String.format(record.getMessage(), record.getParameters()) + newline;
                }
            });
            return new FileHandler(file.getPath(), append);
        } catch (Exception e) {
            if (fh != null)
                fh.close();
            return null;

You never close the file in the try statement, only closing it if there is an error. You should close the file as soon as you done with it:

 try {
            fh = new FileHandler(file.getPath(), append);
            fh.setFormatter(new Formatter() {

                @Override
                public String format(LogRecord record) {
                    return "[test] " + "[" + record.getLevel().toString() + "]" + String.format(record.getMessage(), record.getParameters()) + newline;
                }
            });
            //close fh
            fh.close();
            return new FileHandler(file.getPath(), append);
        } catch (Exception e) {
            if (fh != null)
                fh.close();
            return null;
BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156
  • Reread your code. Your creating a new FileHandler of fh for returning. Then you close it and recreate a new one without ever using the original? Make sense? – CoasterChris Aug 23 '13 at 02:19