v0.1.2-pre.003-fix.001
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 29
|
# version: 30
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/ksp-core-lib", "crates/ksp-logging-lib"]
|
members = ["crates/ksp-core-lib", "crates/ksp-logging-lib"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.2-pre.3"
|
version = "0.1.2-pre.3.fix.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-logging-lib/src/runtime.rs
|
// file: crates/ksp-logging-lib/src/runtime.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
use tracing_subscriber::Layer; // rust-rules: trait-import
|
use tracing_subscriber::Layer; // rust-rules: trait-import
|
||||||
use tracing_subscriber::layer::SubscriberExt; // rust-rules: trait-import
|
use tracing_subscriber::layer::SubscriberExt; // rust-rules: trait-import
|
||||||
@@ -72,6 +72,8 @@ fn prepare_runtime_layers(settings: &crate::LoggingSettings) -> ksp_core_lib::Re
|
|||||||
}
|
}
|
||||||
let mut layers = RuntimeLayers::new();
|
let mut layers = RuntimeLayers::new();
|
||||||
if let std::option::Option::Some(console) = settings.console() {
|
if let std::option::Option::Some(console) = settings.console() {
|
||||||
|
let takeover_filter: BoxedRuntimeLayer = std::boxed::Box::new(build_target_filter(settings));
|
||||||
|
layers.push(takeover_filter);
|
||||||
layers.push(build_console_layer(console, settings));
|
layers.push(build_console_layer(console, settings));
|
||||||
}
|
}
|
||||||
return std::result::Result::Ok(layers);
|
return std::result::Result::Ok(layers);
|
||||||
@@ -87,7 +89,6 @@ fn build_console_layer(console: &crate::ConsoleSettings, settings: &crate::Loggi
|
|||||||
.with_ansi(false)
|
.with_ansi(false)
|
||||||
.with_target(true)
|
.with_target(true)
|
||||||
.with_span_events(map_span_events(settings.span_events()))
|
.with_span_events(map_span_events(settings.span_events()))
|
||||||
.with_filter(build_target_filter(settings))
|
|
||||||
.boxed();
|
.boxed();
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-logging-lib/unit_tests/runtime.rs
|
// file: crates/ksp-logging-lib/unit_tests/runtime.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn level_mapping_covers_all_ksp_levels() {
|
fn level_mapping_covers_all_ksp_levels() {
|
||||||
@@ -54,3 +54,20 @@ fn file_output_is_rejected_until_file_runtime_is_introduced() {
|
|||||||
};
|
};
|
||||||
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_SETTINGS);
|
assert_eq!(error.code(), crate::ERROR_CODE_INVALID_SETTINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn console_runtime_keeps_takeover_filter_separate_from_formatter() {
|
||||||
|
let settings = crate::LoggingSettings::new(
|
||||||
|
crate::LogFilterLevel::Info,
|
||||||
|
crate::SpanEvents::Off,
|
||||||
|
std::option::Option::Some(crate::ConsoleSettings::stdout()),
|
||||||
|
std::option::Option::None,
|
||||||
|
);
|
||||||
|
let result = super::prepare_runtime_layers(&settings);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
let layers = match result {
|
||||||
|
std::result::Result::Ok(layers) => layers,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
assert_eq!(layers.len(), 2);
|
||||||
|
}
|
||||||
|
|||||||
144
deltas/0.1.2/pre.003-fix.001.md
Normal file
144
deltas/0.1.2/pre.003-fix.001.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
<!-- file: deltas/0.1.2/pre.003-fix.001.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta 0.1.2-pre.003-fix.001
|
||||||
|
|
||||||
|
## Base requise
|
||||||
|
|
||||||
|
Livraison précédente :
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.1.2-pre.003
|
||||||
|
```
|
||||||
|
|
||||||
|
La base porte :
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version = "0.1.2-pre.3"
|
||||||
|
Cargo.toml header version = 29
|
||||||
|
```
|
||||||
|
|
||||||
|
## Motif du correctif
|
||||||
|
|
||||||
|
Les validations remontées pour `pre.003` sont :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cargo fmt --all OK
|
||||||
|
cargo check --workspace OK
|
||||||
|
cargo clippy --workspace --all-targets OK
|
||||||
|
cargo test --workspace ECHEC
|
||||||
|
```
|
||||||
|
|
||||||
|
Le test d'intégration :
|
||||||
|
|
||||||
|
```text
|
||||||
|
global_runtime_supports_takeover_hot_reload_and_single_initialization
|
||||||
|
```
|
||||||
|
|
||||||
|
panique pendant le premier `reinitialize()` activant la console :
|
||||||
|
|
||||||
|
```text
|
||||||
|
a `Filtered` layer was used, but it had no `FilterId`; was it registered with the subscriber?
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cause
|
||||||
|
|
||||||
|
`pre.003` construisait le sink console sous cette forme conceptuelle :
|
||||||
|
|
||||||
|
```text
|
||||||
|
fmt layer
|
||||||
|
.with_filter(Targets)
|
||||||
|
-> Filtered<fmt, Targets, Registry>
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce `Filtered` était ensuite boxed dans le `Vec<Box<dyn Layer<Registry>>>` placé derrière `tracing_subscriber::reload::Layer`.
|
||||||
|
|
||||||
|
Au démarrage sans sink, le `Vec` initial était vide. Le premier hot reload construisait donc un nouveau `Filtered` après l'installation du subscriber global puis remplaçait le `Vec` via `Handle::reload`. Or un per-layer `Filtered` a besoin que son `FilterId` soit enregistré lors de son attachement au subscriber. La documentation de `tracing-subscriber 0.3.23` indique explicitement que `Handle::reload` ne doit pas être utilisé pour remplacer directement un `Filtered`.
|
||||||
|
|
||||||
|
Le panic n'indique donc pas un défaut du contrat public KSP de hot reload, mais une composition interne incorrecte des layers de `pre.003`.
|
||||||
|
|
||||||
|
## Correction
|
||||||
|
|
||||||
|
Le runtime conserve :
|
||||||
|
|
||||||
|
```text
|
||||||
|
reload::Layer<Vec<Box<dyn Layer<Registry>>>>
|
||||||
|
```
|
||||||
|
|
||||||
|
mais la composition devient :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Vec reloadable
|
||||||
|
├── Targets global takeover filter
|
||||||
|
└── fmt console layer
|
||||||
|
```
|
||||||
|
|
||||||
|
au lieu de :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Vec reloadable
|
||||||
|
└── Filtered<fmt console layer, Targets>
|
||||||
|
```
|
||||||
|
|
||||||
|
`Targets` est utilisé comme layer de filtrage global. Le layer `fmt` n'appelle plus `with_filter`.
|
||||||
|
|
||||||
|
Conséquences :
|
||||||
|
|
||||||
|
- aucun nouveau `Filtered` n'est injecté par `Handle::reload` ;
|
||||||
|
- aucun `FilterId` tardif n'est nécessaire ;
|
||||||
|
- le takeover reste global : les targets externes restent `OFF` ;
|
||||||
|
- les niveaux KSP et overrides par préfixe restent inchangés ;
|
||||||
|
- le `Vec` complet peut toujours être remplacé pour activer/désactiver des sinks à chaud ;
|
||||||
|
- l'API publique `initialize` / `reinitialize` / `LoggingGuard` ne change pas ;
|
||||||
|
- `pre.004` peut toujours ajouter le backend fichier au même runtime reloadable.
|
||||||
|
|
||||||
|
Une configuration sans sink conserve un `Vec` vide, donc le logging reste effectivement désactivé jusqu'à un `reinitialize()` qui ajoute une sortie.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
Le test d'intégration déjà présent qui a révélé la régression reste le test de non-régression principal :
|
||||||
|
|
||||||
|
```text
|
||||||
|
global_runtime_supports_takeover_hot_reload_and_single_initialization
|
||||||
|
```
|
||||||
|
|
||||||
|
Un test unitaire supplémentaire vérifie que la console prépare deux layers distincts : le takeover filter global et le formatter.
|
||||||
|
|
||||||
|
## Version technique
|
||||||
|
|
||||||
|
Ce correctif modifie du Rust. Conformément à la règle KSP de signal technique, la version workspace devient :
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version = "0.1.2-pre.3.fix.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
et l'en-tête du `Cargo.toml` racine devient :
|
||||||
|
|
||||||
|
```text
|
||||||
|
# version: 30
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers du delta
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-logging-lib/src/runtime.rs
|
||||||
|
crates/ksp-logging-lib/unit_tests/runtime.rs
|
||||||
|
docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md
|
||||||
|
deltas/0.1.2/pre.003-fix.001.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validations à exécuter
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
cargo check --workspace
|
||||||
|
cargo test --workspace
|
||||||
|
cargo clippy --workspace --all-targets
|
||||||
|
```
|
||||||
|
|
||||||
|
Si ces validations sont propres, la tranche suivante reste :
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.1.2-pre.004 — non-blocking console/file + guards + ANSI + reload sinks
|
||||||
|
```
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<!-- file: docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md -->
|
<!-- file: docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Plan KSP 0.1.2 — Logging foundation
|
# Plan KSP 0.1.2 — Logging foundation
|
||||||
|
|
||||||
## Statut
|
## Statut
|
||||||
|
|
||||||
Plan actif de `0.1.2`, établi par `0.1.2-pre.001`, corrigé par `0.1.2-pre.001-fix.001`, concrétisé par la façade de `0.1.2-pre.002` puis étendu au runtime subscriber par `0.1.2-pre.003`.
|
Plan actif de `0.1.2`, établi par `0.1.2-pre.001`, corrigé par `0.1.2-pre.001-fix.001`, concrétisé par la façade de `0.1.2-pre.002` puis étendu au runtime subscriber par `0.1.2-pre.003` et son correctif `0.1.2-pre.003-fix.001`.
|
||||||
|
|
||||||
`pre.002-fix.001` a été validé dans l'environnement de développement avec `cargo fmt`, `cargo check`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` propres sur la version Cargo `0.1.2-pre.2.fix.1`. `pre.003` ajoute le subscriber global, le takeover/filtering KSP, la console initiale et le hot reload des layers. Les writers non bloquants, le fichier, les guards et le stripping ANSI restent réservés à `pre.004`.
|
`pre.002-fix.001` a été validé dans l'environnement de développement avec `cargo fmt`, `cargo check`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` propres sur la version Cargo `0.1.2-pre.2.fix.1`. Pour `pre.003`, `cargo fmt`, `cargo check` et `cargo clippy --workspace --all-targets` sont propres, mais `cargo test --workspace` a révélé un panic de `tracing-subscriber` lors du premier hot reload avec console : un `Filtered` nouvellement injecté dans le `Vec` reloadable ne possédait pas de `FilterId` enregistré. `pre.003-fix.001` sépare donc le `Targets` global du formatter afin qu'aucun `Filtered` ne soit remplacé par `Handle::reload`. Les writers non bloquants, le fichier, les guards et le stripping ANSI restent réservés à `pre.004`.
|
||||||
|
|
||||||
## Base auditée
|
## Base auditée
|
||||||
|
|
||||||
@@ -926,7 +926,7 @@ Objectifs :
|
|||||||
|
|
||||||
### `0.1.2-pre.003` — subscriber + takeover + console + reload foundation
|
### `0.1.2-pre.003` — subscriber + takeover + console + reload foundation
|
||||||
|
|
||||||
Statut : implémenté dans la tranche `pre.003`, sous réserve des validations Cargo à exécuter dans l'environnement de développement.
|
Statut : implémenté dans `pre.003`, puis corrigé par `pre.003-fix.001` après détection d'un panic de reload dans le test d'intégration global.
|
||||||
|
|
||||||
Réalisé :
|
Réalisé :
|
||||||
|
|
||||||
@@ -943,7 +943,7 @@ Réalisé :
|
|||||||
|
|
||||||
La console de `pre.003` utilise encore directement `stdout`/`stderr` comme writer synchrone. C'est un état transitoire volontaire : `pre.004` remplace ces writers par `tracing-appender::non_blocking`, introduit les `WorkerGuard`/`ErrorCounter`, puis ajoute le fichier et le stripping ANSI. La release stable `0.1.2` ne sera pas déclarée conforme tant que ce remplacement n'est pas terminé.
|
La console de `pre.003` utilise encore directement `stdout`/`stderr` comme writer synchrone. C'est un état transitoire volontaire : `pre.004` remplace ces writers par `tracing-appender::non_blocking`, introduit les `WorkerGuard`/`ErrorCounter`, puis ajoute le fichier et le stripping ANSI. La release stable `0.1.2` ne sera pas déclarée conforme tant que ce remplacement n'est pas terminé.
|
||||||
|
|
||||||
Le runtime reloadable est un `Vec<Box<dyn Layer<Registry>>>` placé derrière une unique `reload::Layer`. Cette composition permet de changer à chaud le nombre et le type des sinks tout en conservant un seul subscriber global et prépare directement l'ajout du layer fichier de `pre.004`.
|
Le runtime reloadable reste un `Vec<Box<dyn Layer<Registry>>>` placé derrière une unique `reload::Layer`. En revanche, les sinks reloadables ne doivent pas encapsuler leur `Targets` via `Layer::with_filter`, car cela crée un `Filtered` dont le `FilterId` est enregistré lors de son attachement initial au subscriber et ne peut pas être remplacé directement avec `Handle::reload`. `pre.003-fix.001` place donc `Targets` comme layer de filtrage global distinct dans le même `Vec`, à côté du layer `fmt` non filtré. Le `Vec` entier reste remplaçable à chaud, mais aucun `Filtered` nouvellement construit n'a besoin d'être enregistré après l'installation globale du subscriber. Cette composition conserve le takeover externe, permet de changer à chaud le nombre et le type des sinks et prépare l'ajout du layer fichier de `pre.004`.
|
||||||
|
|
||||||
### `0.1.2-pre.004` — non-blocking console/fichier + guards + ANSI + reload sinks
|
### `0.1.2-pre.004` — non-blocking console/fichier + guards + ANSI + reload sinks
|
||||||
|
|
||||||
@@ -1038,7 +1038,7 @@ Les deux questions d'API propres à `pre.002` sont résolues :
|
|||||||
1. les macros KSP délèguent aux macros `tracing` au point d'appel via un bridge interne caché et exigent un `target:` explicite ;
|
1. les macros KSP délèguent aux macros `tracing` au point d'appel via un bridge interne caché et exigent un `target:` explicite ;
|
||||||
2. la surface span publique est `Span::in_scope(...)` pour le synchrone et `instrument(span, future)` pour l'async, avec type de future retourné opaque.
|
2. la surface span publique est `Span::in_scope(...)` pour le synchrone et `instrument(span, future)` pour l'async, avec type de future retourné opaque.
|
||||||
|
|
||||||
La composition de reload est désormais fixée pour cette release à un `Vec` de layers boxed derrière une `reload::Layer`, ce qui autorise l'activation/désactivation des sinks et le remplacement de leurs paramètres sans second subscriber global.
|
La composition de reload est désormais fixée pour cette release à un `Vec` de layers boxed derrière une `reload::Layer`, ce qui autorise l'activation/désactivation des sinks et le remplacement de leurs paramètres sans second subscriber global. Le takeover `Targets` est un layer global distinct dans ce `Vec`; les layers de sortie reloadables ne doivent pas être des `Filtered` remplacés directement par `Handle::reload`.
|
||||||
|
|
||||||
Restent à confirmer par les prereleases suivantes sans remettre en cause ce contrat :
|
Restent à confirmer par les prereleases suivantes sans remettre en cause ce contrat :
|
||||||
|
|
||||||
@@ -1046,4 +1046,4 @@ Restent à confirmer par les prereleases suivantes sans remettre en cause ce con
|
|||||||
2. le détail visuel exact du formatter humain, sans transformer sa ponctuation en contrat public ;
|
2. le détail visuel exact du formatter humain, sans transformer sa ponctuation en contrat public ;
|
||||||
3. le comportement de flush/rotation et le swap transactionnel des `WorkerGuard` lorsque les sinks non bloquants seront introduits.
|
3. le comportement de flush/rotation et le swap transactionnel des `WorkerGuard` lorsque les sinks non bloquants seront introduits.
|
||||||
|
|
||||||
La prochaine action après validation de `pre.003` est `0.1.2-pre.004` : `tracing-appender`, console/fichier non bloquants, guards, rotation, stripping ANSI et reload des sinks.
|
La prochaine action après validation de `pre.003-fix.001` est `0.1.2-pre.004` : `tracing-appender`, console/fichier non bloquants, guards, rotation, stripping ANSI et reload des sinks.
|
||||||
|
|||||||
Reference in New Issue
Block a user