Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronizing on System.out

I changed System.out to print to a file, by invoking System.setOut and System.setErr.

Every night at midnight, we want to rename (archive) the current log file, and create a new one.

if (out != null) {
    out.close();
    out = null;
    File f = new File(outputfilename);
    f.renameTo(new File(dir.getPath().replace(".log", "-" + System.currentTimeMillis() + ".log")))
    StartLogFile();
}

The StartLogFile():

if (out == null) {
    out = new FileOutputStream(outputfilename, true);
    System.setOut(new PrintStream(out));
    System.setErr(new PrintStream(out));
}

I've left exception-handling out.

My concern is that if something tries to print in between out.close() and setOut/setErr that I'm going to miss a log.

My real question is, how can I make this atomic with other calls to System.out.println? I was thinking about trying

synchronized (System.out) {

}

but I'm not actually sure if the intrinsic lock here does anything. Especially since I'm nullifying the out object during the operation.

Does anyone know how I can ensure proper synchronization here?

like image 305
Cruncher Avatar asked Jun 02 '14 14:06

Cruncher


2 Answers

I would create the new out before closing the old one:

PrintStream old = System.out;
out = new FileOutputStream(outputfilename, true);
System.setOut(new PrintStream(out));
old.close();

This way the old PrintStream is not closed until the new one is created and assigned. At all times there is a valid PrintStream in System.out.

There is no need for synchronized block, because everything is in the same thread.

like image 185
njzk2 Avatar answered Sep 18 '22 20:09

njzk2


Yes you can achieve proper synchronization that way. Here is a sample test.

@Test
public void test() throws InterruptedException {

    new Thread(()->{
        while(true){
            System.out.println("printing something");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }).start();

    Thread.sleep(500);
    synchronized (System.out){
        System.out.println("changin system out");
        Thread.sleep(2000);
        System.out.println("finished with sysout");
    }
    Thread.sleep(2000);
}

and the output will be:

printing something
printing something
printing something
printing something
printing something
changin system out
finished with sysout
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
like image 43
vach Avatar answered Sep 18 '22 20:09

vach