ShellRaiser, я переделал совсем все что выше понаписал, теперь это выглядит так
| Цитата | | вопрос, а ты на любой эксепшн хочешь повесить отправку? |
да
| Цитата | | или сохраняй всё в лог файл |
а как быть, если на диске нет свободного места? )))))
| Цитата | | вот только ещё есть смешной и глупый вопрос, что ты будешь делать если эксепшн будет валиться при отправке. |
выводить сообщение, что бы в этом случае пользователь руками скопировал вывод стека в письмо и прислал по указанному адресу  запускаем всю эту бодягу
| Код | import javax.swing.*; import java.io.*;
public class Main {
/** * @param args the command line arguments */ public static void main(String[] args) { // TODO code application logic here PrintStream stderr = System.err; LoggingOutputStream los; los = new LoggingOutputStream(stderr); System.setErr(new PrintStream(los, true));
SwingUtilities.invokeLater(new Runnable(){ public void run(){ new Parent(); } }); }
}
|
Вот родитель, генерирующий всякие исключения
| Код | import javax.swing.*; import java.awt.event.*; import java.awt.*;
public class Parent extends JFrame{ Child ch = null; public Parent(){ Stack.setAlive(true); setLayout(new BorderLayout()); Box box = new Box(BoxLayout.PAGE_AXIS); box.add(new JButton(new AbstractAction("EDT Exception") { public void actionPerformed(ActionEvent e) { throw new RuntimeException("Exception generated on the EDT"); } })); box.add(new JButton(new AbstractAction("Thread Exception") { public void actionPerformed(ActionEvent e) { new Thread("Sample Thread") { @Override public void run() { throw new RuntimeException("Exception thrown on a thread"); } }.start(); } })); add(box,BorderLayout.CENTER); JButton btn2 = new JButton("info"); btn2.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ev){ //А тут просто допишем в стек чего попало synchronized (Stack.getInstance()) { Stack.getInstance().getStackTrace().add("пример4\n"); Stack.getInstance().getStackTrace().add("пример5\n"); } } }); add(btn2,BorderLayout.SOUTH); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); pack(); setVisible(true); this.addWindowListener(new WindowAdapter(){ @Override public void windowClosed(WindowEvent ev){ Stack.setAlive(false); if (ch!=null && !ch.isVisible()){ //Форма вывода невидна, закрываем ее ch.stopThread(); ch.dispose(); System.exit(0); }else if (ch!=null){ ch.stopThread(); } } }); SwingUtilities.invokeLater(new Runnable(){ public void run(){ ch = new Child("SendMail V0.0"); } }); } }
|
Обработка ошибок, если они появляются
| Код | import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.net.*;
public class Child extends JFrame{ private Desktop desktop = null; private JTextArea text; private boolean flag = true; public Child(final String ver){ if (Desktop.isDesktopSupported()){ desktop = Desktop.getDesktop(); } setTitle("Ошибка в работе программы "+ver); text = new JTextArea(); text.setEditable(false); JLabel lbl = new JLabel( "<html><center><h3><font color=red>В работе программы произошла ошибка,<br>" + "Вы можете отправить сообщение о ошибке автору по электронной почте<br>" + "или продолжить работу</font></h3></center><br>" + "Ниже находится описание ошибки, которое может помочь рабобраться<br>" + "с проблемой, для разработчика эта информация очень важна</html>"); lbl.setHorizontalAlignment(SwingConstants.CENTER); add(lbl, BorderLayout.NORTH);
JButton btnEmail = new JButton("Отправить отчет"); btnEmail.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ev){ boolean noemail = false; if (Desktop.isDesktopSupported()){ if (desktop.isSupported(Desktop.Action.MAIL)){ URI uri = null; text.selectAll(); text.copy(); try { uri = new URI("mailto", "[email protected]?SUBJECT=Error in "+ver+ "&BODY=Опишите причину появляения ошибки, а так же\n" + "Нажмите Ctrl+V для вставки в письмо лога ошибок\n\n", null); //Пришлось использовать буфер обмена, т.к. длина сообщения передаваемого //таким образом ограничена длиной командной строки //а писать полноценный почтовый клиент не хочется desktop.mail(uri); }catch(Exception ex){ ex.printStackTrace(); noemail = true; } } }else noemail = true; if (noemail){ //это на тот случай, если не удалось вызвать почтовый клиент //Под KDE не запускается из java :( JOptionPane.showMessageDialog(Child.this, "Ваша система не поддерживает вызов email клиента по умолчанию\n" + "Запустите его сами и скопируйте вывод ошибок в это письмо\n"+ "адрес для отправки ошибок: [email protected]", "Неудача отправки письма", JOptionPane.ERROR_MESSAGE); } } }); add(new JScrollPane(text),BorderLayout.CENTER);
JButton btnClose = new JButton("Закрыть и продолжить работу"); btnClose.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ev){ setVisible(false); if (!Stack.isAlive()){ flag = false;//завершаем тред dispose(); System.exit(0); } } }); JPanel bottom = new JPanel(new GridLayout(1,3,10,5)); bottom.add(btnEmail); bottom.add(btnClose);
add(bottom,BorderLayout.SOUTH); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); setSize(600,400); setLocationRelativeTo(null); setAlwaysOnTop(true); runThread(); this.addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent ev){ setVisible(false); //Тут проверяем нужно ли удалить ресурсы //занятые окном if (!Stack.isAlive()){ flag = false;//завершаем тред dispose(); System.exit(0); } } }); }//что бы закрыть запускаем тред, который смотрит за стеком, как только //стек исчезает - убиваем данное окно public void runThread(){ Thread t = new Thread(){ @Override public void run(){ while (flag){ try{ Thread.sleep(100); }catch(Exception ex){};//задержка нужна для того, что бы LoggingOutputStream //имел шанс записать в стек, стек синхронизируемый и если из него постоянно читать //то запись в него происходит крайне медленно или вообще не происходит //на Linux работает без паузы, на Windows без паузы не работает if (Stack.getInstance().getStackTrace().size()>0){ setVisible(true); while (Stack.getInstance().getStackTrace().size()>0){ synchronized (Stack.getInstance()) { text.append(Stack.getInstance().getStackTrace().remove(0)); } } } } } }; t.start(); } public void stopThread(){ flag = false; } }
|
подмена стандартного вывода ошибок
| Код | import java.io.*;
class LoggingOutputStream extends ByteArrayOutputStream {
private String lineSeparator;
private PrintStream olderrstr; /** * Constructor * @param logger Logger to write to * @param level Level at which to write the log message */ public LoggingOutputStream(PrintStream old) { super();
lineSeparator = System.getProperty("line.separator"); olderrstr = old; }
/** * upon flush() write the existing contents of the OutputStream * to the logger as a log record. * @throws java.io.IOException in case of error */ @Override public void flush() throws IOException { //String record; synchronized(this) { super.flush(); final String record = this.toString();
super.reset();
if (record.length() == 0 || record.equals(lineSeparator)) { // avoid empty records return; } //а это вывод в старый поток, т.е. в консоли ничего не меняется olderrstr.println(record); //добавляем строчку в стек synchronized (Stack.getInstance()) { Stack.getInstance().getStackTrace().add(record+lineSeparator); } } } }
|
А вот стек, можно допилить, но вроде пойдет
| Код | import java.util.*; public class Stack { private static boolean alive = true; private static Vector<String> stack = new Vector(); private static Stack instance = null; private Stack(){ } public static synchronized Stack getInstance(){ if (instance==null){ instance = new Stack(); } return instance; } public Vector<String> getStackTrace(){ //вот тут нужно синхронизирорвать доступ к данному полю return stack; } public static synchronized boolean isAlive(){ return alive; } public static synchronized void setAlive(boolean state){ alive = state; } }
|
|