2

I have a desktop application, when there is a freeze for some minutes, there is a thread which monitors the freeze and it starts dumping stack traces of all threads(this is done in native call so that JVM_DumpAllStacks can be invoked) into temporary file. Then the temporary file is read as String after the native call and it is used to log in application's own logging framework.

The problem is, After all these process, I am not able to restore System.out to CONSOLE stream.

This is better explained in the below code.

public String getAllStackTraces() {

System.out.println("This will be printed in CONSOLE");

// This is NECESSARY for the jvm to dump stack traces in specific file which we are going to set in System.setOut call.
System.out.close(); 

File tempFile = File.createTempFile("threadDump",null,new File(System.getProperty("user.home")));
System.setOut(new PrintStream(new BufferedOutputStream(new FileOuptputStream(tempFile))));

//This native call dumps stack traces all threads to tempFile
callNativeMethodToDumpAllThreadStackTraces(); 

String stackTraces = readFileAsString(tempFile);
//close the tempFile PrintStream so as the next PrintStream object to set as 'out' and to take effect in the native side as well
System.out.close(); 

//Now I want to start printing in the CONSOLE again. How to do it again ?
//The below line does not work as FileDescriptor.out becomes invalid (i.e FileDescriptor.out.fd, handle = -1) after we do System.out.close() where out is PrintStream of console.
//System.setOut(new PrintStream(new BufferedOutputStream(new FileOuptputStream(FileDescriptor.out))));

PrintStream standardConsoleOutputStream = magicallyGetTheOutputStream() // How ???????????
System.setOut(standardConsoleOutputStream);
System.out.println("This will be printed in CONSOLE !ONLY! if we are able to get the new PrintStream of Console again magically");
} 

Now, is there a way to magicallyGetTheOutputStream of Console to start printing in the console again ?

Note: The application is running in java 5 and 6.

Jan
  • 13,738
  • 3
  • 30
  • 55

1 Answers1

2

Consider this code of how to store away original System.out without closing to later restore it to full glory:

    //Store, don't close
    PrintStream storeForLater = System.out;
    //Reassign
    System.out(setToNew);
    ...
    //Close reassigned
    setToNew.close();
    //Reset to old
    System.setOut(storeForLater);

As an alternative to native code, you could call into ThreadMXBean. The returned ThreadInfo objects contain information about Locks held and Locks the thread is waiting for.

public static void dumpThreads(PrintStream out) {
    ThreadInfo[] threads = ManagementFactory.getThreadMXBean()
            .dumpAllThreads(true, true);
    for(final ThreadInfo info : threads) {
        out.println("Thread: " + info.getThreadId() 
         + "/" + info.getThreadName()
         + " in State " + info.getThreadState().name());
        if(info.getLockName() != null) {
            out.println("- Waiting on lock: " + info.getLockInfo().toString()
                     + " held by " + info.getLockOwnerId()+"/"+info.getLockOwnerName());
        }
        for(MonitorInfo mi :  info.getLockedMonitors()) {
            out.println(" Holds a lock on a " + mi.getClassName() + 
                    " from " + mi.getLockedStackFrame().getClassName()+"."+mi.getLockedStackFrame().getMethodName() 
                    + ": " + mi.getLockedStackFrame().getLineNumber());
        }
        for(StackTraceElement elm : info.getStackTrace()) {
            out.println("   at " + elm.getClassName() + "."
                    + elm.getMethodName() + ":"+elm.getLineNumber());
        }
        out.println();
    }
}
Jan
  • 13,738
  • 3
  • 30
  • 55
  • This does not work and the native code still prints in the console instead of `setToNew` – Senthilkumar Annadurai Dec 09 '15 at 08:07
  • **Native Code**?? Why don't you iterate over Thread.getAllStacKTraces() instead? https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#getAllStackTraces() – Jan Dec 09 '15 at 08:10
  • That's a good idea, except that in a deadlock situation some info is getting lost such as information of object for which a particular thread is waiting and object on which it has acquired the lock. Although one can spend time and can identify things, It would make it complex when the stack is big and repeated class and method names in the stack, also if deadlock involves more than two threads. The code is executed on a GUI freeze where the chance of getting deadlock is high. 'JVM_DumpAllStacks' actually does the Thread dump and gives better information. – Senthilkumar Annadurai Dec 09 '15 at 11:07
  • see my change for using ThreadMXBean to include lock information without native code. – Jan Dec 09 '15 at 12:39
  • "This does not work and the native code still prints in the console instead of setToNew" nor would you expect it to, only native code which calls back into Java to use `System.out` which be redirected to what you set `System.out` to. Changing this field, just change this field, nothing else magically happens. If you have native code which prints directly to the console or any other file descriptor this is unaffected. – Peter Lawrey Dec 11 '15 at 22:55
  • Did you try with JMX as I suggested? Have you found another way? – Jan Dec 15 '15 at 18:58