Files
khadhroony-solana-project/deltas/0.1.2/pre.004.md
2026-08-14 18:43:54 +02:00

302 lines
8.1 KiB
Markdown

<!-- file: deltas/0.1.2/pre.004.md -->
<!-- version: 1 -->
# Delta 0.1.2-pre.004
## Base requise
Livraison précédente validée :
```text
0.1.2-pre.003-fix.001
```
La base de développement validée porte :
```text
workspace.package.version = "0.1.2-pre.3.fix.1"
Cargo.toml header version = 30
```
Les validations remontées avant l'ouverture de cette tranche sont propres :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test --workspace
```
## Objectif
Compléter le runtime Logging avec les sorties réellement retenues pour `0.1.2` :
- ajouter `tracing-appender` ;
- rendre console et fichier non bloquants pour le caller ;
- posséder les `WorkerGuard` jusqu'au reload/shutdown approprié ;
- exposer les dropped-line counters ;
- activer le fichier `Never/Hourly/Daily` avec construction fallible ;
- supprimer les séquences ANSI avant persistence ;
- conserver le takeover et le hot reload transactionnel établis par `pre.003-fix.001`.
## Version Cargo
`workspace.package.version` passe de :
```text
0.1.2-pre.3.fix.1
```
à :
```text
0.1.2-pre.4
```
L'identifiant de livraison est :
```text
0.1.2-pre.004
```
Le header du `Cargo.toml` racine passe de version 30 à 31.
## Dépendance `tracing-appender`
L'audit du 2026-08-14 confirme `tracing-appender 0.2.5`, publié le 2026-04-17, dans la génération `^0.2`.
La dépendance est centralisée sous `[workspace.dependencies]` :
```toml
tracing-appender = { version = "^0.2", default-features = false }
```
`ksp-logging-lib` la consomme avec :
```toml
tracing-appender.workspace = true
```
Aucune feature optionnelle n'est activée. Le backend expose `NonBlockingBuilder`, `WorkerGuard`, `ErrorCounter` et `RollingFileAppender` sans feature supplémentaire.
## Console non bloquante
La console n'utilise plus directement `stdout`/`stderr` dans le formatter.
Chaque sink console construit :
```text
Stdout | Stderr
-> NonBlockingBuilder(lossy = true)
-> fmt layer
+ WorkerGuard
+ ErrorCounter
```
Le mode lossy est explicite : lorsque la queue est saturée, un log peut être abandonné au lieu de bloquer le thread appelant.
Le thread worker console est nommé :
```text
ksp-logging-console
```
## Fichier et rotation
`FileSettings` est maintenant réellement consommé par le runtime.
Le mapping est :
```text
FileRotation::Never -> Rotation::NEVER
FileRotation::Hourly -> Rotation::HOURLY
FileRotation::Daily -> Rotation::DAILY
```
Le runtime utilise uniquement :
```text
RollingFileAppender::builder()
.rotation(...)
.filename_prefix(...)
.build(directory)
```
La forme builder retourne un `Result`; aucune API de construction qui panique n'est utilisée par KSP.
Un échec retourne :
```text
logging.file_output_initialization_failed
```
avec le directory, le file-name prefix et l'erreur `InitError` externe conservés dans le contrat Core.
## Stripping ANSI
Le fichier est composé comme suit :
```text
fmt layer
-> NonBlocking queue
-> StripAnsiWriter
-> RollingFileAppender
```
Le stripping est donc effectué par le thread logging et non par le caller.
`StripAnsiWriter` conserve un état entre les appels `Write` afin de retirer correctement une séquence terminal coupée entre plusieurs buffers. La première surface couvre :
- CSI (`ESC [` ... final byte) ;
- OSC terminé par BEL ou ST ;
- autres chaînes terminal ESC de type DCS/SOS/PM/APC terminées par ST.
Ce mécanisme est générique et n'introduit aucune dépendance Tauri.
## Formatter humain
Console et fichier partagent le formatter humain KSP avec :
- timestamp standard `tracing-subscriber` ;
- niveau ;
- target ;
- champs/message ;
- source file ;
- line number ;
- ANSI du formatter désactivé ;
- lifecycle de spans selon `SpanEvents`.
La ponctuation exacte du formatter reste hors contrat public.
## Ownership et reload
`LoggingGuard` possède désormais les outputs actifs :
```text
LoggingGuard
├── reload handle
├── current LoggingSettings
├── active console WorkerGuard/ErrorCounter
├── active file WorkerGuard/ErrorCounter
└── cumulative retired dropped-line counters
```
`reinitialize()` :
1. valide les nouveaux settings ;
2. construit entièrement le nouveau file appender et tous les nouveaux non-blocking writers/guards ;
3. construit les nouveaux layers ;
4. remplace le `Vec` reloadable ;
5. mémorise les dropped lines des anciens sinks ;
6. remplace les outputs actifs ;
7. détruit les anciens `WorkerGuard`, provoquant leur flush borné par le backend.
Une erreur avant le swap détruit uniquement les nouveaux outputs préparés et laisse l'ancienne configuration active.
## Dropped lines
Nouvelle surface publique :
```text
DroppedLines
LoggingGuard::dropped_lines() -> DroppedLines
```
`DroppedLines` expose :
```text
console()
file()
total()
```
Les valeurs sont cumulées pour toute la durée de vie du `LoggingGuard`, y compris après plusieurs hot reloads. Les `ErrorCounter` de `tracing-appender` ne sont pas exposés directement aux consumers.
## Tests
### Unitaires
- mapping `Never/Hourly/Daily` ;
- runtime sans sink ;
- console préparée avec filter séparé, non-blocking output et guard ;
- addition saturante des dropped-line counters ;
- stripping CSI ;
- stripping d'une CSI coupée entre deux writes ;
- stripping OSC terminé par BEL/ST.
### Intégration runtime global
Le test global vérifie désormais :
1. initialisation silencieuse sans sink ;
2. hot reload console non bloquante ;
3. takeover KSP et silence `sqlx` ;
4. erreur de création d'un file appender sur un chemin invalide ;
5. conservation des settings précédents après cet échec ;
6. hot reload vers un fichier `Never` ;
7. émission d'un message contenant des codes ANSI ;
8. retrait du sink fichier par reload, donc drop/flush de son guard ;
9. présence du message KSP dans le fichier ;
10. absence des codes ANSI persistés ;
11. absence du message externe `sqlx` ;
12. présence du target et de la source ;
13. lecture de la statistique cumulée ;
14. refus d'un second `initialize()`.
La saturation déterministe avec une queue artificiellement petite est reportée à `pre.005`, où un writer de test injecté pourra être utilisé sans rendre la capacité de queue publique dans `LoggingSettings`.
## Fichiers ajoutés
- `crates/ksp-logging-lib/src/writer.rs`
- `crates/ksp-logging-lib/unit_tests/writer.rs`
- `deltas/0.1.2/pre.004.md`
## Fichiers modifiés
- `Cargo.toml`
- `crates/ksp-logging-lib/Cargo.toml`
- `crates/ksp-logging-lib/src/error.rs`
- `crates/ksp-logging-lib/src/lib.rs`
- `crates/ksp-logging-lib/src/runtime.rs`
- `crates/ksp-logging-lib/unit_tests/runtime.rs`
- `crates/ksp-logging-lib/tests/runtime.rs`
- `crates/ksp-logging-lib/tests/public_api.rs`
- `docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`
## Validations exécutées pendant la préparation
- revérification documentaire officielle de `tracing-appender 0.2.5` ;
- vérification de la sémantique lossy de `NonBlockingBuilder` ;
- vérification de `WorkerGuard` et `ErrorCounter::dropped_lines()` ;
- vérification du builder fallible de `RollingFileAppender` ;
- contrôle TOML des manifests ;
- contrôle des headers `file:` / `version:` ;
- contrôle de la centralisation de `tracing-appender` sous `[workspace.dependencies]` ;
- contrôle que le code production ajouté n'utilise ni `unwrap`, ni `expect`, ni `panic`, ni opérateur `?`, ni `unsafe` ;
- contrôle que les usages directs de `tracing-appender` restent dans `ksp-logging-lib`.
## Validations à exécuter dans le workspace
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test --workspace
cargo tree -p ksp-logging-lib
cargo tree -p ksp-logging-lib -d
cargo tree -p ksp-logging-lib -e features
```
Aucune validation Cargo non exécutable dans l'environnement de préparation n'est déclarée réussie.
## Suite
Après validation de `pre.004`, passer à `0.1.2-pre.005` :
- concurrence/reloads répétés ;
- saturation déterministe et dropped lines ;
- audits de façade et usages directs de la stack tracing ;
- audits Cargo/features/doublons ;
- mesure grossière de l'overhead du reload/runtime ;
- compléments de tests et documentation de crate avant la tranche finale.