I want my program exceptions to be sent to each of the following, preferably simultaneously:
- the console which starts it (not necessarily)
- a gui
- a txt file.
How can I achieve this?
My attempts:
System.setErr(PrintStream err)
will forward all exceptions to a new stream. I am not able to state more than one stream though.Calling
System.setErr(PrintStream err)
on a manually writtenOutputStream
:"You can write your own stream class that forwards to multiple streams and call System.setOut on an instance of that class" – Jeffrey Bosboom
I found a way to do this. It is very nasty though. It "collects"
PrintStream
'swrite
-bytes, puts them in a puffer (500 ms timeout) and finally shows it to the user (Proceed
):/* ErrorOutput.java */ public static t_ErrBuffer t_activeErrBuffer = new t_ErrBuffer(""); public static void setStdErrToFile(final File file) { ps = new PrintStream(fos) { @Override public void write(byte[] buf, int off, int len) { byte[] bn = new byte[len]; for (int i = off, j = 0; i < (len + off); i++, j++) { bn[j] = buf[i]; } String msg = null; try { msg = new String(bn, "UTF-8"); } catch (UnsupportedEncodingException e1) {} if (msg.matches("[\\w\\W]*[\\w]+[\\w\\W]*")) { // ^= contains at least one word character if( ! t_activeErrBuffer.isAlive() ) { t_activeErrBuffer = new t_ErrBuffer(msg); t_activeErrBuffer.start(); } else { t_activeErrBuffer.interrupt(); t_activeErrBuffer = new t_ErrBuffer(t_activeErrBuffer.getErrBuffer() + "\n" + msg); // ^= append to buffer and restart. t_activeErrBuffer.start(); } } } }; System.setErr(ps); } /* t_ErrBuffer.java */ public class t_ErrBuffer extends Thread { private String errBuffer; public t_ErrBuffer(String buffer) { this.errBuffer = buffer; } protected class Proceed implements Runnable { public String msg = null; public Proceed(String msg) { this.msg = msg; } @Override public void run() { // todo PRINT ERROR MESSAGE: DO THINGS WITH msg: console, gui, JOptionPane } } @Override public void run() { try { Thread.sleep(500); // collect error lines before output. Needed because PrintStream's "write"-method writes ErrorMessages in multiple pieces (lines) // each time some new exception line comes in, the thread is stopped, buffer is being appended and thread new started } catch (InterruptedException e) { return; // stop } // after 500 ms of wait, no new error message line has come in. Print the message out: Thread t_tmp = new Thread(new Proceed("\n" + this.errBuffer)); t_tmp.start(); return; } public String getErrBuffer() { return this.errBuffer; } }
is this what I am expected to do?
Create new exception class which does it for me. Would probably work, but other exceptions than that (IO, FileNotFound, ...) will still be treated the old way
Instead of stating
[method name] throws Exception
I could enclose all of my code in try/catch-blocks, get the exception and forward it to a method of mine, like this:/* AnyMethod.java */ // ... try { // ... do everything here } catch (IOException | FileNotFoundException e) { // as many as you like ErrorOutput.crash(e); } // ... /* ErrorOutput.java */ public static void crash(Exception e) { FileOutputStream fos_errOutput = new FileOutputStream(new File("ErrorOutput.txt"), true); // 1st if (!System.out.equals(fos_errOutput)) { System.out.println(e.getMessage() + " :"); // to console or the preferred StdOut e.printStackTrace(); } // 2nd JOptionPane.showMessageDialog(Gui.frame, "THE PROGRAM HAS CRASHED!" + "\n\n" + e.getMessage() + "\n\nFor a more detailed report, see ErrorLog.txt"); // gui output // 3rd PrintStream ps = new PrintStream(fos_errOutput); ps.print(new Date().toString() + ":"); // write to file e.printStackTrace(ps); ps.close(); // 4th System.exit(0); // this could also be "throw new Exception" etc., but I don't know why one should do that. }
this would probably also work, but I'd have to put everything into try/catch-blocks. This cannot be good programming style at all.
Using a logger:
"use log4j and set up a method to write to GUI and also to log to stdout, and file" – Scary Wombat
Loggers only help me printing my exceptions into desired streams, but they don't help me catching them, right?
But you really should use a logging package for this -- even java.util.logging can do what you need – Jeffrey Bosboom
I have to tell my logging package where and what to log. But this is exactly what I am searching for.
I now can, as user3159253 suggested, use Thread.UncaughtExceptionHandler
to catch unhandled exceptions specifically.
What is the right way to handle all thrown exceptions the way I want them to? What else do I have to consider apart from Thread.UncaughtExceptionHandler
and System.setErr()
(see above)?