Exception in File schreiben

Hallo :slight_smile: Mir ist grad nur aufgefallen, das wenn mein Programm mehrere Exceptions bekommt, und jedes mal mein Catch-Block durchgeführt wird:

                        FileHandler fh = null;
                        String userHome = System.getProperty("user.home");
                        Path home = Paths.get(userHome);
                        Path syserr = home.resolve(Paths.get("Documents", "NetBeansProjects", "MusikPlayerGUIBuilder_New", "syserr"));
                        String syserrString = syserr.toString();
                        try {
                            if (!Files.exists(syserr)) {
                                Files.createDirectory(syserr);
                            }
                            fh = new FileHandler(syserrString + "\\syserr.log", 1_073_741_824, 1, true);
                        } catch (IOException ex1) {
                            System.err.println("Filehandler bei " + MusikThread.class.getName() + " kaputt");
                        }
                        Logger log = Logger.getLogger(MusikThread.class.getName());
                        log.addHandler(fh);
                        log.log(Level.SEVERE, "Exception " + ex.getClass().getName() + " bei " + MusikThread.class.getName(), ex);```
(Den Pfad hab ich nur zu Testzwecken so geändert, damit ich einen eigenen syserr-Ordner habe, der die log enthält)

So und jedesmal wenn das aufgerufen wird, benennt er die alte in "syserr.xml.log.1" bzw. "XXX.2" usw. um und erstellt eine neue, die dann alle Exceptions beinhält. So, da ich aber gerne will, das er alle Exceptions in die oben genannte Datei schreibt, was er ja auch macht, aber er soll eben nicht die alten einfach umbenennen, sonder die vorhandene wiederverwenden. Gibts dafür ne Möglichkeit das umzusetzen? Meine momentan einzige Idee wäre das hier:
```FileHandler fh = null;
            String userHome = System.getProperty("user.home");
            Path home = Paths.get(userHome);
            Path syserr = home.resolve(Paths.get("Documents", "NetBeansProjects", "Tests", "syserr.xml.log"));
            Path syserr2 = home.resolve(Paths.get("Documents", "NetBeansProjects", "Tests", "syserr.xml.log.1"));
            String syserrString = syserr.toString();
            System.out.println(syserrString);
            try {
                fh = new FileHandler(syserrString, 1_073_741_824, 1, true);
                Logger log = Logger.getLogger(LoggingTest.class.getName());
                log.addHandler(fh);
                log.log(Level.SEVERE, "Exception " + ex.getClass().getName() + " bei " + LoggingTest.class.getName(), ex);
                Files.deleteIfExists(syserr2);
            } catch (IOException ex1) {
                System.err.println("Filehandler bei LoggingTest kaputt");
            }```

Funzt aber auch nicht. Jemand ne Idee? Würde das nur ungerne so lassen, da ich die syserr schon gerne im Hauptordner habe, sie allerdings auch den Ordner nicht füllen sollte, in dem sie x Dateien erstelle :) Google half btw nicht

Du kannst Log4j verwenden. Bei Stackoverflow steht auch wie du eine Exception loggen kannst. http://stackoverflow.com/questions/4347797/how-to-send-a-stacktrace-to-log4j

getLogger() liefert nur beim ersten Mal ein neues Logger-Objekt, bei wiederholten Aufrufen mit dem gleichen Namen wird die Instanz wiederverwendet. Dadurch hängst Du bei jeder Exception wieder einen neuen (= einen weiteren) FileHandler an den Logger. Das könnte evtl. solche Probleme verursachen.

Der Fehler ist, ständig Logger- und vor allem FileHandler-Objekte in lokalen Variablen neu zu speichern. Speicher die Referenz auf das Logger-Objekt in einem static final Feld. Initialisiere es genau einmal (öfter geht ja bei final auch nicht :wink: ) und verwende dann nur noch diese Referenz für log-Aufrufe.

OT:

Das stimmt nur mit Einschränkungen. Der Cache für bereits instanzierte Logger-Objekte ist nämlich eine Weak-Reference Implementierung. D.h. sobald keine Referenz mehr auf das Logger-Objekt im Code ist (so wie hier) ist die Instanz ein Kandidat für Garbage Collection. Sollte diese zwischendurch zuschlagen, muss eine neue Instanz erzeugt werden. Nur, wenn zwischendurch nicht garbage collected wurde, wird die Neuerzeugung vermieden.

Sry, das ich erst jetz antworte, aber war ne Zeit lang nich zuhause :smiley: Ich werd mal eure Vorschläge ausprobieren

Edit:


    private static FileHandler fh = null;
    private static final Logger log = Logger.getLogger(LoggingTest.class.getName());

    public LoggingTest() {
        createFileHandler();
    }

    private FileHandler createFileHandler() {
        if (fh == null) {
            String userHome = System.getProperty("user.home");
            Path home = Paths.get(userHome);
            Path syserr = home.resolve(Paths.get("Documents", "NetBeansProjects", "Tests", "syserr.xml.log"));
            Path syserr2 = home.resolve(Paths.get("Documents", "NetBeansProjects", "Tests", "syserr.xml.log.1"));
            String syserrString = syserr.toString();
            try {
                fh = new FileHandler(syserrString, 1_073_741_824, 1, true);
            } catch (IOException ex) {
                System.out.println("FileHandler bei LoggingTest kaputt");
            }
        }
        return fh;

    }

    public static void main(String[] args) {

        LoggingTest a = new LoggingTest();
        try {
            a.exception();
        } catch (Exception ex) {
            if (log.getHandlers() == null) {
                log.addHandler(fh);
            }
            log.log(Level.SEVERE, "Exception " + ex.getClass().getName() + " bei " + LoggingTest.class.getName(), ex);
        }
        try {
            a.exception();
        } catch (Exception ex) {
            if (log.getHandlers() == null) {
                log.addHandler(fh);
            }
            log.log(Level.SEVERE, "Exception " + ex.getClass().getName() + " bei " + LoggingTest.class.getName(), ex);
        }
        try {
            a.exception();
        } catch (Exception ex) {
            if (log.getHandlers() == null) {
                log.addHandler(fh);
            }
            log.log(Level.SEVERE, "Exception " + ex.getClass().getName() + " bei " + LoggingTest.class.getName(), ex);
        }
    }

    public void exception() throws Exception {
        throw new Exception("Test");
    }
}```
Das funzt zwar so und die Syserr wird auch erstellt, aber sie ist leer?! Es wird auch nur eine erstellt und eine .lck datei, die denke ich nur zur Laufzeit da ist...

Das hier ist immer noch schlecht:

   private static FileHandler fh = null;
   private static final Logger log = Logger.getLogger(LoggingTest.class.getName());
   
   public LoggingTest() {
       createFileHandler();
   }

Du hast den FileHandler fh static (also eine Referenz für alles), überschreibst ihn aber bei jeder Neuerzeugung. Das macht so keinen Sinn. Trenne klar zwischen dem, was Du nur einmal brauchst und dem, was Du je Instanz haben willst. Auch Dein Konstrukt, mitten im Code noch den Logger zu konfigurieren ist unübersichtlich und fehleranfällig. Z.B. der Teil hier:

if (log.getHandlers() == null) {
  log.addHandler(fh);
}

Was macht Dich so sicher, dass getHandlers() null zurück liefert und nicht vielleicht eher ein leeres Array? In dem Fall würde nämlich Dein Handler überhaupt nicht zum Logger hinzugefügt und folglich auch nichts ins Logfile geschrieben. Dieses Konstrukt hast Du nur drinnen, weil Du nicht -wie schon geraten- im Vorherein Deinen Logger vernünftig konfigurierst und ihn dann einfach nur noch nutzt.

Also neu erstellen tu ich den nur einmal, da die ganze Methode in nem if (fh == null) abläuft, oder denk ich da grad falsch?

zum unteren, mein erster Gedanke war : leeres Array == null. Dabei stimmt es ja nicht und {} heißt ja leer, bzw .length = 0, ich probiers mal.

Edit: mit diesem if im catch klappts, so wie es soll, nur eine Datei die alle Exceptions einschließt, danke :slight_smile:

                log.addHandler(fh);
            }```

Also neu erstellen tu ich den nur einmal, da die ganze Methode in nem if (fh == null) abläuft, oder denk ich da grad falsch?

Ja stimmt, die null-Prüfung hatte ich übersehen. Aber da merkst Du, wie krude Dein Konstrukt ist, dass Du das überhaupt prüfen musst.

Prüfen müssen tu ich es nicht, mach es nur aus Sicherheit, das wirklich nur einmal einer erstellt wird, mit final funzt das ganze ja nicht wirklich. Wenn ichs weglasse, funktioniert es genauso.