From 8b29214abdc2c083e9dacf10c18de5587ef3cbf5 Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sun, 28 Dec 2025 15:37:54 +0100 Subject: [PATCH] Debugging: Erweiterte Debug-Ausgaben und Log-Verzeichnis-Verschiebung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Saxon Worker Pool Verbesserungen: - Fügt umfangreiche DEBUG-Ausgaben in Java-Worker hinzu (Job-Parsing, Saxon-Ausführung) - Fügt explizite flush()-Aufrufe hinzu um Buffering-Probleme zu vermeiden - Zeigt Stack Traces bei Exceptions an - Verbessert Exception-Handling (null-sichere getMessage()) - Verschiebt Worker-stderr-Logs von /tmp in Projektverzeichnis unter temp/ - Erweitert SaxonWorkerPool.__init__ um optionalen log_dir Parameter Dies hilft, den genauen Crash-Punkt der Worker zu identifizieren. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/saxon_pool.py | 53 ++++++++++++++++++++++++++++++++++++++------ src/ui/MainWindow.py | 2 ++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/saxon_pool.py b/src/saxon_pool.py index 7d242a5..64f4d3a 100644 --- a/src/saxon_pool.py +++ b/src/saxon_pool.py @@ -27,19 +27,30 @@ public class SaxonWorker { String line; System.err.println("SaxonWorker started and ready"); + System.err.flush(); try { while ((line = reader.readLine()) != null) { + System.err.println("DEBUG: Received line: " + line.substring(0, Math.min(100, line.length()))); + System.err.flush(); + if ("EXIT".equals(line.trim())) { System.err.println("SaxonWorker exiting"); break; } try { - // Parse JSON job + // Parse job + System.err.println("DEBUG: Parsing job..."); + System.err.flush(); + String[] parts = line.split("\\t"); + System.err.println("DEBUG: Parts count: " + parts.length); + System.err.flush(); + if (parts.length < 3) { System.out.println("ERROR: Invalid job format"); + System.out.flush(); continue; } @@ -47,6 +58,9 @@ public class SaxonWorker { String xslStylesheet = parts[1]; String outputFo = parts[2]; + System.err.println("DEBUG: Building Saxon args..."); + System.err.flush(); + // Build Saxon arguments List saxonArgs = new ArrayList<>(); saxonArgs.add("-s:" + sourceXml); @@ -63,6 +77,9 @@ public class SaxonWorker { } } + System.err.println("DEBUG: Running Saxon transformation..."); + System.err.flush(); + // Redirect Saxon output to stderr to avoid polluting stdout PrintStream oldOut = System.out; PrintStream oldErr = System.err; @@ -80,21 +97,34 @@ public class SaxonWorker { System.setOut(oldOut); System.setErr(oldErr); + oldErr.println("DEBUG: Saxon transformation completed"); + oldErr.flush(); + // Send success response System.out.println("OK"); + System.out.flush(); } catch (Exception e) { System.setOut(oldOut); System.setErr(oldErr); - System.out.println("ERROR: " + e.getMessage()); + oldErr.println("DEBUG: Saxon exception: " + e.getClass().getName()); + oldErr.flush(); + e.printStackTrace(oldErr); + System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName())); + System.out.flush(); } } catch (Exception e) { - System.out.println("ERROR: " + e.getMessage()); + System.err.println("DEBUG: Job processing exception: " + e.getClass().getName()); + System.err.flush(); + e.printStackTrace(System.err); + System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName())); + System.out.flush(); } } } catch (IOException e) { - System.err.println("SaxonWorker error: " + e.getMessage()); + System.err.println("SaxonWorker I/O error: " + e.getMessage()); + e.printStackTrace(System.err); } } } @@ -114,6 +144,7 @@ class SaxonWorkerPool: java_vm_path: Path, saxon_jar_path: Path, classpath_cache: dict[Path, str], + log_dir: Optional[Path] = None, ): """ Initialisiert den Saxon-Worker-Pool. @@ -123,11 +154,13 @@ class SaxonWorkerPool: java_vm_path: Pfad zur Java VM Binary saxon_jar_path: Pfad zur Saxon JAR-Datei classpath_cache: Cache für Saxon-Classpaths + log_dir: Optionales Verzeichnis für Worker-Logs (Standard: temp_dir/temp) """ self.num_workers = num_workers self.java_vm_path = java_vm_path self.saxon_jar_path = saxon_jar_path self.classpath_cache = classpath_cache + self.log_dir = log_dir # Worker-Prozesse und Queues self.workers: list[subprocess.Popen] = [] @@ -138,6 +171,7 @@ class SaxonWorkerPool: # Temporäres Verzeichnis für kompilierte Java-Klasse self.temp_dir: Optional[Path] = None self.worker_class_path: Optional[Path] = None + self.worker_log_dir: Optional[Path] = None # Initialisierung self._compile_worker_class() @@ -202,13 +236,18 @@ class SaxonWorkerPool: classpath_separator = ";" if sys.platform == "win32" else ":" full_classpath = str(self.worker_class_path) + classpath_separator + classpath + # Bestimme Log-Verzeichnis + self.worker_log_dir = self.log_dir if self.log_dir else self.temp_dir + if self.log_dir: + self.worker_log_dir.mkdir(parents=True, exist_ok=True) + for i in range(self.num_workers): try: # Starte JVM-Prozess mit SaxonWorker cmd = [str(self.java_vm_path), "-cp", full_classpath, "SaxonWorker"] # Öffne stderr-Log-Datei für diesen Worker - stderr_log = self.temp_dir / f"worker_{i}_stderr.log" + stderr_log = self.worker_log_dir / f"worker_{i}_stderr.log" stderr_file = open(stderr_log, "w", encoding="utf-8") process = subprocess.Popen( @@ -281,7 +320,7 @@ class SaxonWorkerPool: # Prüfe ob Worker noch läuft if worker.poll() is not None: # Worker ist tot! - stderr_log = self.temp_dir / f"worker_{worker_idx}_stderr.log" + stderr_log = self.worker_log_dir / f"worker_{worker_idx}_stderr.log" try: with open(stderr_log, "r") as f: stderr_content = f.read() @@ -318,7 +357,7 @@ class SaxonWorkerPool: else: # Leere Antwort bedeutet Worker ist crashed if not response: - stderr_log = self.temp_dir / f"worker_{worker_idx}_stderr.log" + stderr_log = self.worker_log_dir / f"worker_{worker_idx}_stderr.log" try: with open(stderr_log, "r") as f: stderr_content = f.read()[-500:] # Letzte 500 Zeichen diff --git a/src/ui/MainWindow.py b/src/ui/MainWindow.py index cec7dc4..19d4747 100644 --- a/src/ui/MainWindow.py +++ b/src/ui/MainWindow.py @@ -758,11 +758,13 @@ class MainWindow(QMainWindow): # Erstelle Worker-Pool num_workers = app_settings.max_workers + log_dir = self.project.project_dir / "temp" pool = SaxonWorkerPool( num_workers=num_workers, java_vm_path=java_vm.path_to_binary_file, saxon_jar_path=saxon_jar.path_to_jar_file, classpath_cache=TransformationJob._classpath_cache, + log_dir=log_dir, ) # Setze globalen Pool