问题
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.
回答1:
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();
}
}
来源:https://stackoverflow.com/questions/34172384/recreate-system-out-to-print-again-in-console-after-system-out-close