Java: Laufzeitausnahmen anzeigen – Variante

Im Artikel „Java: Laufzeitausnahmen anzeigen“ steht, wie ich im AWT-EventDispatchThread nicht gefangene Ausnahmen mit einem Dialog anzeige. Inzwischen verfolge ich eine weniger „aufdringliche“ Variante, die nicht von der Arbeit ablenkt oder das Schließen des Programmfensters verhindert, falls im EventDispatchThread laufend neue Ausnahmen geworfen und nicht gefangen werden:

  • Die Ersatz-EventQueue benutzt das Logging-System und loggt die Ausnahme mit dem Level SEVERE
  • Ein Handler – ein erweiterter java.util.logging.Handler – reagiert auf bestimmte Loglevel, zeigt beispielsweise einen „Fehlerindikator“ an, bei Klick darauf erhält der Benutzer nähere Informationen über den Fehler

Modifizierte EventQueue

public final class AppEventQueue extends java.awt.EventQueue {

    @Override
    protected void dispatchEvent(AWTEvent event) {
        try {
            super.dispatchEvent(event);
        } catch (Throwable t) {
            Logger.getLogger(AppEventQueue.class.getName()).log(Level.SEVERE, null, t);
        }
    }
}

Handler

public final class ErrorLogHandler extends Handler {

    private static final int MIN_LOG_LEVEL_VALUE = Level.WARNING.intValue();

    public ErrorLogHandler() {
        Logger.getLogger("").addHandler(this);
    }

    @Override
    public void publish(LogRecord record) {
        int recordLevelValue = record.getLevel().intValue();
        boolean isError = recordLevelValue >= MIN_LOG_LEVEL_VALUE;

        if (isError) {
            // Hier den Fehler visualisieren
        }
    }

    @Override
    public void flush() {
        // ignorieren
    }

    @Override
    public void close() throws SecurityException {
        // ignorieren
    }
}

Der Handler fügt sich dem root Logger hinzu, der root Logger ruft die Handler-Methode publish() auf. Jeden Loglevel ab WARNING betrachtet der Handler als Fehler (isError). Bei Fehlern kann er beispielsweise über die setIcon()-Methode eines Labels ein Fehler-Icon setzen und bei Klick auf das Label die Fehlerinformationen anzeigen, beispielsweise anhand Fehler-LogRecords, die er temporär speichert.

EventQueue ersetzen

Die EventQueue ersetze ich „rechtzeitig“ durch folgende Codezeile (im Projekt JPhotoTagger unmittelbar nach Erzeugen des Programmfenster-Frames):

Toolkit.getDefaultToolkit().getSystemEventQueue().push(new AppEventQueue());

Die folgenden Abbildungen zeigen die Auswirkungen: In NetBeans setzte ich einen Haltepunkt in die Zeile 127 der Klasse AppInit, Methode setJptEventQueue(), das ist die Zeile mit dem push()-Afuruf. Gelb unterlegt ist der Thread AWT-EventQueue-0. Nach Aufruf ist zu sehen, dass nun Thread AWT-EventQueue-1 läuft, die Namen lassen sich nicht ändern, es wird nur die Nummer hochgezählt.


JPhotoTagger: AWT-EventQueue ersetzen, Debugger-Ansicht vor Ersetzen


JPhotoTagger: AWT-EventQueue ersetzen, Debugger-Ansicht nach Ersetzen.


Fehleranzeige durch einen Log-Handler in JPhotoTagger am unteren Programmfensterrand.

Außerhalb der AWT-EventQueue

In anderen Threads kann ich nicht gefangene Ausnahmen loggen mit java.lang.Thread#setDefaultUncaughtExceptionHandler() – der Handler wird nicht aufgerufen im AWT-Event Dispatch Thread. Beispiel:

public final class UncaughtExceptionLogger implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
         Logger.getLogger(UncaughtExceptionLogger.class.getName()).log(Level.SEVERE, null, e);
    }
}

Benutzung:

Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger());

Zusammenfassung (mit Erweiterung um FileHandler)

  • Nicht gefangene Ausnahmen sollen dem Benutzer unaufdringlich angezeigt werden und in einer Logdatei stehen
  • Ein erweiterter java.util.logging.Handler zeigt dem Benutzer Probleme an ab dem Loglevel WARNING, ein java.util.logging.FileHandler schreibt die LogRecords in eine Logdatei. Diese Handler füge ich dem root Logger hinzu.
  • Je ein Logger loggt ungefangene Ausnahmen mit dem Level SEVERE
    • im AWT-EventDispatchThread in einer eigenen EventQueue, die die „Standard“-EventQueue ersetzt
    • in (allen) anderen Threads in einem java.lang.Thread.UncaughtExceptionHandler, den ich setze mit Thread#setDefaultUncaughtExceptionHandler()

Stichwörter: ,

Zu diesem Artikel können keine Kommentare mehr geschrieben werden.