Debugging: Erweiterte Debug-Ausgaben und Log-Verzeichnis-Verschiebung

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 <noreply@anthropic.com>
This commit is contained in:
2025-12-28 15:37:54 +01:00
parent ac654a6f7c
commit 8b29214abd
2 changed files with 48 additions and 7 deletions
+46 -7
View File
@@ -27,19 +27,30 @@ public class SaxonWorker {
String line; String line;
System.err.println("SaxonWorker started and ready"); System.err.println("SaxonWorker started and ready");
System.err.flush();
try { try {
while ((line = reader.readLine()) != null) { 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())) { if ("EXIT".equals(line.trim())) {
System.err.println("SaxonWorker exiting"); System.err.println("SaxonWorker exiting");
break; break;
} }
try { try {
// Parse JSON job // Parse job
System.err.println("DEBUG: Parsing job...");
System.err.flush();
String[] parts = line.split("\\t"); String[] parts = line.split("\\t");
System.err.println("DEBUG: Parts count: " + parts.length);
System.err.flush();
if (parts.length < 3) { if (parts.length < 3) {
System.out.println("ERROR: Invalid job format"); System.out.println("ERROR: Invalid job format");
System.out.flush();
continue; continue;
} }
@@ -47,6 +58,9 @@ public class SaxonWorker {
String xslStylesheet = parts[1]; String xslStylesheet = parts[1];
String outputFo = parts[2]; String outputFo = parts[2];
System.err.println("DEBUG: Building Saxon args...");
System.err.flush();
// Build Saxon arguments // Build Saxon arguments
List<String> saxonArgs = new ArrayList<>(); List<String> saxonArgs = new ArrayList<>();
saxonArgs.add("-s:" + sourceXml); 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 // Redirect Saxon output to stderr to avoid polluting stdout
PrintStream oldOut = System.out; PrintStream oldOut = System.out;
PrintStream oldErr = System.err; PrintStream oldErr = System.err;
@@ -80,21 +97,34 @@ public class SaxonWorker {
System.setOut(oldOut); System.setOut(oldOut);
System.setErr(oldErr); System.setErr(oldErr);
oldErr.println("DEBUG: Saxon transformation completed");
oldErr.flush();
// Send success response // Send success response
System.out.println("OK"); System.out.println("OK");
System.out.flush();
} catch (Exception e) { } catch (Exception e) {
System.setOut(oldOut); System.setOut(oldOut);
System.setErr(oldErr); 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) { } 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) { } 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, java_vm_path: Path,
saxon_jar_path: Path, saxon_jar_path: Path,
classpath_cache: dict[Path, str], classpath_cache: dict[Path, str],
log_dir: Optional[Path] = None,
): ):
""" """
Initialisiert den Saxon-Worker-Pool. Initialisiert den Saxon-Worker-Pool.
@@ -123,11 +154,13 @@ class SaxonWorkerPool:
java_vm_path: Pfad zur Java VM Binary java_vm_path: Pfad zur Java VM Binary
saxon_jar_path: Pfad zur Saxon JAR-Datei saxon_jar_path: Pfad zur Saxon JAR-Datei
classpath_cache: Cache für Saxon-Classpaths 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.num_workers = num_workers
self.java_vm_path = java_vm_path self.java_vm_path = java_vm_path
self.saxon_jar_path = saxon_jar_path self.saxon_jar_path = saxon_jar_path
self.classpath_cache = classpath_cache self.classpath_cache = classpath_cache
self.log_dir = log_dir
# Worker-Prozesse und Queues # Worker-Prozesse und Queues
self.workers: list[subprocess.Popen] = [] self.workers: list[subprocess.Popen] = []
@@ -138,6 +171,7 @@ class SaxonWorkerPool:
# Temporäres Verzeichnis für kompilierte Java-Klasse # Temporäres Verzeichnis für kompilierte Java-Klasse
self.temp_dir: Optional[Path] = None self.temp_dir: Optional[Path] = None
self.worker_class_path: Optional[Path] = None self.worker_class_path: Optional[Path] = None
self.worker_log_dir: Optional[Path] = None
# Initialisierung # Initialisierung
self._compile_worker_class() self._compile_worker_class()
@@ -202,13 +236,18 @@ class SaxonWorkerPool:
classpath_separator = ";" if sys.platform == "win32" else ":" classpath_separator = ";" if sys.platform == "win32" else ":"
full_classpath = str(self.worker_class_path) + classpath_separator + classpath 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): for i in range(self.num_workers):
try: try:
# Starte JVM-Prozess mit SaxonWorker # Starte JVM-Prozess mit SaxonWorker
cmd = [str(self.java_vm_path), "-cp", full_classpath, "SaxonWorker"] cmd = [str(self.java_vm_path), "-cp", full_classpath, "SaxonWorker"]
# Öffne stderr-Log-Datei für diesen Worker # Ö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") stderr_file = open(stderr_log, "w", encoding="utf-8")
process = subprocess.Popen( process = subprocess.Popen(
@@ -281,7 +320,7 @@ class SaxonWorkerPool:
# Prüfe ob Worker noch läuft # Prüfe ob Worker noch läuft
if worker.poll() is not None: if worker.poll() is not None:
# Worker ist tot! # 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: try:
with open(stderr_log, "r") as f: with open(stderr_log, "r") as f:
stderr_content = f.read() stderr_content = f.read()
@@ -318,7 +357,7 @@ class SaxonWorkerPool:
else: else:
# Leere Antwort bedeutet Worker ist crashed # Leere Antwort bedeutet Worker ist crashed
if not response: 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: try:
with open(stderr_log, "r") as f: with open(stderr_log, "r") as f:
stderr_content = f.read()[-500:] # Letzte 500 Zeichen stderr_content = f.read()[-500:] # Letzte 500 Zeichen
+2
View File
@@ -758,11 +758,13 @@ class MainWindow(QMainWindow):
# Erstelle Worker-Pool # Erstelle Worker-Pool
num_workers = app_settings.max_workers num_workers = app_settings.max_workers
log_dir = self.project.project_dir / "temp"
pool = SaxonWorkerPool( pool = SaxonWorkerPool(
num_workers=num_workers, num_workers=num_workers,
java_vm_path=java_vm.path_to_binary_file, java_vm_path=java_vm.path_to_binary_file,
saxon_jar_path=saxon_jar.path_to_jar_file, saxon_jar_path=saxon_jar.path_to_jar_file,
classpath_cache=TransformationJob._classpath_cache, classpath_cache=TransformationJob._classpath_cache,
log_dir=log_dir,
) )
# Setze globalen Pool # Setze globalen Pool