119 lines
5.3 KiB
Markdown
119 lines
5.3 KiB
Markdown
---
|
||
model: sonnet
|
||
---
|
||
# AP07 – Ausgabeartefakte: Berichtdatei und Log-Datei mit Suffix-Logik
|
||
|
||
> **Meilenstein:** M1
|
||
> **Vorgänger:** AP04, AP05, AP06 ✅ erforderlich
|
||
> **Nachfolger:** AP08, AP10
|
||
> **Grundlage:** `docs/specs/technik-und-architektur.md` v5, §§ „Ausgabeartefakte", „Zeichensätze", „Logging und Berichtserzeugung"
|
||
> **Entscheidungsprotokoll:** `docs/arbeitspakete/m1/E00-entscheidungsprotokoll.md` (E-04 logs/-Verzeichnis)
|
||
|
||
## Ziel
|
||
|
||
Pro Lauf werden **zwei Ausgabedateien** im **Verzeichnis der Eingabedatei** erzeugt:
|
||
- eine **Berichtdatei** `<basename>.txt`
|
||
- eine **Log-Datei** `<basename>.log`
|
||
|
||
Beide in **UTF-8**. Der Bericht wird zusätzlich in die **Konsole** geschrieben. Bei bereits vorhandenen Dateien gleichen Namens werden neue mit laufendem Suffix `_v1`, `_v2`, … erzeugt.
|
||
|
||
## Voraussetzungen
|
||
|
||
- AP04 (Logging-Adapter), AP05 (Befundmodell), AP06 (Bootstrap/CLI)
|
||
|
||
## Scope IN
|
||
|
||
### `SuffixResolver` im Paket `adapter.out.filesystem`
|
||
|
||
```java
|
||
public class SuffixResolver {
|
||
/**
|
||
* Ermittelt den ersten freien Dateipfad für den gegebenen Basisnamen
|
||
* und die gegebene Extension im Zielverzeichnis.
|
||
* Probiert: <baseName>.<ext>, dann <baseName>_v1.<ext>, <baseName>_v2.<ext>, ...
|
||
*/
|
||
public Path resolveNextFreePath(Path directory, String baseName, String extension) { ... }
|
||
}
|
||
```
|
||
|
||
- Suffix-Zählung ist **pro Extension unabhängig** — `.txt` und `.log` haben getrennte Zähler
|
||
- Unit-Tests mindestens für: keine Datei vorhanden, `.txt` vorhanden, `.txt` + `_v1` vorhanden
|
||
|
||
### `ReportFileWriter` im Paket `adapter.out.reporting`
|
||
|
||
- Eingabe: `ValidationReport` (AP05) + Eingabedatei-Pfad
|
||
- Ausgabe: UTF-8-Textdatei im Verzeichnis der Eingabedatei
|
||
- Dateiname via `SuffixResolver`
|
||
- **Berichtinhalt für M1** (absichtlich minimal, wird in M9 ausgebaut):
|
||
- Kopfzeile: Zeitstempel, Eingabedatei, Verdict
|
||
- Pro `Finding`: eine Zeile mit Severity, Kind, Layer, Feld-ID, deutscher Meldung
|
||
- Fußzeile: Hinweis auf bewusst nicht geprüfte Bereiche
|
||
|
||
Alle Texte auf **Deutsch**, Encoding **UTF-8** explizit — kein Plattform-Default.
|
||
|
||
### `LoggingConfigurator.configureLogFile(Path)` in `adapter.out.logging`
|
||
|
||
- Methode wird im Bootstrap **vor** dem ersten fachlichen Log-Aufruf aufgerufen
|
||
- Konfiguriert Log4j2-File-Appender programmatisch auf den gewünschten Pfad
|
||
- Dateiname via `SuffixResolver` (analog zur Berichtdatei, eigene Zählung)
|
||
- Log4j2-Typen (`LoggerContext`, `Appender` etc.) bleiben **ausschließlich** in `adapter.out.logging` und `bootstrap`
|
||
- Statischer `logs/`-Pfad aus `log4j2.xml` (AP04) wird entfernt oder auf Fallback-Default gesetzt, der nur greift wenn `configureLogFile` nicht aufgerufen wurde (z.B. für Testläufe)
|
||
- **Fallback:** Falls programmatische Log4j2-Umkonfiguration sich als instabil erweist, ist eine System-Property-basierte Konfiguration (`-Dasv.log.file=...`) ein zulässiger Ausweg — Entscheidung im Bericht dokumentieren
|
||
|
||
### Integration in `bootstrap.Main`
|
||
|
||
Reihenfolge vor dem Validierungslauf:
|
||
1. Eingabedatei-Pfad bestimmen
|
||
2. Basisnamen und Zielverzeichnis ableiten
|
||
3. `SuffixResolver` für `.log` aufrufen
|
||
4. `LoggingConfigurator.configureLogFile(logPath)` aufrufen → ab jetzt gehen Logs in die Datei
|
||
5. Validierungslauf starten
|
||
6. `ReportFileWriter` schreiben
|
||
7. Konsolenausgabe (identisch zum Berichtinhalt)
|
||
|
||
### Konsolenausgabe
|
||
|
||
- Schreibt denselben Text wie die Berichtdatei
|
||
- Erfolgt **nach** der Berichtdatei-Erstellung, damit ein IO-Fehler beim Schreiben die Konsolenausgabe nicht verhindert
|
||
|
||
## Scope OUT
|
||
|
||
- Hierarchische Berichtsgliederung (M9)
|
||
- ANSI-Farben / Einfärbung in der Konsole
|
||
- Log-Rotation
|
||
- Minimalbericht bei Exit-Code `2` (AP08)
|
||
|
||
## Schritte
|
||
|
||
1. `SuffixResolver` implementieren inkl. Unit-Tests
|
||
2. `ReportFileWriter` implementieren mit einfachem Zeilenformat für M1
|
||
3. `LoggingConfigurator.configureLogFile(Path)` implementieren
|
||
4. Bootstrap erweitern: Log-Datei-Pfad bestimmen → `LoggingConfigurator` aufrufen
|
||
5. `CliRunner` erweitern: nach Lauf → Berichtdatei schreiben → Konsolenausgabe
|
||
6. End-to-End-Test: beide Ausgabedateien entstehen, Suffix-Logik funktioniert, UTF-8
|
||
7. `mvn clean verify` grün bekommen
|
||
8. Abschlussbericht schreiben
|
||
|
||
## Abnahmekriterien
|
||
|
||
- [ ] Nach Lauf mit `foo/bar.auf` entstehen `foo/bar.auf.txt` und `foo/bar.auf.log`
|
||
- [ ] Zweiter Lauf mit derselben Datei → `foo/bar.auf_v1.txt` und `foo/bar.auf_v1.log`
|
||
- [ ] Dritter Lauf → `_v2` usw.
|
||
- [ ] Beide Ausgabedateien sind UTF-8
|
||
- [ ] Konsolenausgabe ist identisch zum Inhalt der Berichtdatei
|
||
- [ ] `SuffixResolver` hat mindestens drei Unit-Tests
|
||
- [ ] Log4j2-Typen sind außerhalb von `adapter.out.logging` und `bootstrap` nicht sichtbar
|
||
- [ ] Statischer `logs/`-Pfad aus `log4j2.xml` entfernt oder auf Fallback-Default gesetzt
|
||
- [ ] `mvn clean verify` grün
|
||
- [ ] Abschlussbericht unter `docs/arbeitspakete/m1/berichte/AP07-bericht.md`
|
||
|
||
## Rest-Risiken und offene Punkte
|
||
|
||
- Race Conditions bei gleichzeitigen Läufen auf derselben Eingabedatei: laut `technik-und-architektur.md` bewusst nicht behandelt (kein Mehrbenutzerbetrieb in V1).
|
||
- Das Bericht-Dateiformat ist in M1 absichtlich primitiv. In M9 wird es durch die finale hierarchische Struktur ersetzt.
|
||
- Fallback bei instabiler programmatischer Log4j2-Umkonfiguration im Bericht dokumentieren.
|
||
|
||
## Bericht
|
||
|
||
`docs/arbeitspakete/m1/berichte/AP07-bericht.md` nach `docs/arbeitspakete/m1/templates/ap-bericht.md`.
|