Files
khadhroony-solana-project/crates/ksp-logging-lib/USAGE.md
2026-08-15 19:58:18 +02:00

203 lines
6.8 KiB
Markdown

<!-- file: crates/ksp-logging-lib/USAGE.md -->
<!-- version: 3 -->
# Utilisation de ksp-logging-lib
## Target d'une crate consommatrice
Chaque crate KSP comportementale fournit explicitement son target, égal au nom Cargo de la crate :
```rust
const LOGGING_TARGET: &str = "ksp-store-lib";
ksp_logging_lib::trace!(
target: LOGGING_TARGET,
domain = "store",
component = "postgres",
operation = "load_transactions",
"executing store operation"
);
```
Les champs `domain`, `component`, `operation` et autres champs structurés sont ajoutés par le caller lorsqu'ils sont utiles ; ils ne remplacent pas le target propriétaire.
## Contrat des outputs
`LoggingSettings` possède :
- le `default_filter` global de takeover KSP ;
- les `TargetFilter` globaux ;
- la politique `SpanEvents` ;
- une console déclarée optionnellement ;
- zéro, un ou plusieurs `FileSettings`.
Chaque output possède un `OutputFilter` indépendant. Son niveau, ses targets et ses domains s'appliquent **en plus** de la politique globale. `*` signifie « tous » dans la dimension concernée.
Les formats publics sont :
```text
Human
Compact
Pretty
Json
```
Une sortie fichier possède un `output_id` stable et unique dans `LoggingSettings`. Cet identifiant appartient au runtime Logging et ne doit pas être confondu avec les `file_id` utilisés par `ksp-config-lib` pour identifier ses documents.
Les fichiers persistants interdisent `ansi = true`.
## Compatibilité runtime de `pre.004`
`0.1.3-pre.004` étend d'abord le **contrat public**. Le runtime multi-sink/routing est livré séparément en `pre.005`.
Jusqu'à cette tranche suivante, `initialize`/`reinitialize` refusent explicitement toute capacité nouvellement représentée qu'ils ne savent pas encore appliquer : plusieurs fichiers actifs, format non `Human`, ANSI console ou filtre propre à un output. Ces valeurs ne sont donc jamais acceptées puis ignorées silencieusement.
Les helpers `ConsoleSettings::stdout()` et `ConsoleSettings::stderr()` construisent une console compatible avec le runtime actuel : activée, `Human`, sans ANSI et sans filtre supplémentaire par rapport au takeover global.
## Initialisation compatible avec le runtime actuel
```rust
let file = ksp_logging_lib::FileSettings::new(
"file.worker",
true,
"logs",
"worker.log",
ksp_logging_lib::FileRotation::Daily,
ksp_logging_lib::LogFormat::Human,
ksp_logging_lib::OutputFilter::unrestricted(),
);
let settings = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Info,
ksp_logging_lib::SpanEvents::NewAndClose,
std::option::Option::Some(ksp_logging_lib::ConsoleSettings::stderr()),
std::vec![file],
);
let initialize_result = ksp_logging_lib::initialize(&settings);
let mut logging_guard = match initialize_result {
std::result::Result::Ok(guard) => guard,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
```
Une configuration sans output actif est valide et installe une infrastructure initialement silencieuse qui pourra être activée plus tard par hot reload.
## Construction d'un contrat multi-output
Le contrat public peut déjà représenter la future configuration Config complète :
```rust
let console = ksp_logging_lib::ConsoleSettings::new(
true,
ksp_logging_lib::ConsoleOutput::Stderr,
true,
ksp_logging_lib::LogFormat::Compact,
ksp_logging_lib::OutputFilter::new(
ksp_logging_lib::LogFilterLevel::Debug,
std::vec!["*".to_string()],
std::vec!["*".to_string()],
),
);
let error_file = ksp_logging_lib::FileSettings::new(
"file.config.error",
true,
"logs/config",
"error.jsonl",
ksp_logging_lib::FileRotation::Daily,
ksp_logging_lib::LogFormat::Json,
ksp_logging_lib::OutputFilter::new(
ksp_logging_lib::LogFilterLevel::Error,
std::vec!["ksp-config-lib".to_string()],
std::vec!["config".to_string()],
),
);
let settings = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Warn,
ksp_logging_lib::SpanEvents::NewAndClose,
std::option::Option::Some(console),
std::vec![error_file],
);
let validation = settings.validate();
```
`validate()` vérifie le contrat structurel. L'activation runtime de ce routage enrichi appartient à `pre.005`.
## Hot reload
Une configuration compatible avec les capacités runtime actives peut être appliquée sans redémarrer le processus ou le worker :
```rust
let debug_settings = ksp_logging_lib::LoggingSettings::new(
ksp_logging_lib::LogFilterLevel::Info,
ksp_logging_lib::SpanEvents::NewAndClose,
std::option::Option::Some(ksp_logging_lib::ConsoleSettings::stderr()),
std::vec::Vec::new(),
)
.with_target_filter(ksp_logging_lib::TargetFilter::new(
"ksp-store-lib",
ksp_logging_lib::LogFilterLevel::Debug,
));
let reload_result = ksp_logging_lib::reinitialize(&mut logging_guard, &debug_settings);
if let std::result::Result::Err(error) = reload_result {
return std::result::Result::Err(error);
}
```
La nouvelle configuration est préparée avant la bascule. Si sa validation ou la création d'un nouveau sink échoue, l'ancienne configuration reste active.
## Spans synchrones
```rust
let span = ksp_logging_lib::trace_span!(
target: LOGGING_TARGET,
"materialize_transaction",
domain = "store"
);
let output = span.in_scope(|| {
return materialize_transaction();
});
```
Avec `SpanEvents::NewAndClose`, le formatter produit les événements de création/fermeture et les temps `busy` / `idle` à la fermeture.
## Spans async
Une `Future` doit être instrumentée avec `ksp_logging_lib::instrument` ; un guard d'entrée de span ne doit pas être conservé à travers `.await` :
```rust
let span = ksp_logging_lib::trace_span!(
target: LOGGING_TARGET,
"fetch_account",
domain = "transport"
);
let output = ksp_logging_lib::instrument(span, fetch_account()).await;
```
La future instrumentée entre/sort du span pendant ses polls et lors de son `Drop`, conformément au contrat de la primitive `tracing` sous-jacente.
## Lignes abandonnées
Les sorties utilisent des queues lossy afin de ne pas appliquer de backpressure au hot path. Les compteurs restent encore agrégés console/fichier pendant `pre.004` ; leur généralisation par output appartient au runtime multi-sink :
```rust
let dropped = logging_guard.dropped_lines();
ksp_logging_lib::warn!(
target: LOGGING_TARGET,
console = dropped.console(),
file = dropped.file(),
total = dropped.total(),
"logging queues dropped lines"
);
```
## Instrumentation async et executor
`instrument(span, future)` accepte une `Future` standard et ne dépend d'aucun executor particulier. Tokio n'est présent qu'en `dev-dependency` pour valider la surface sur un executor réel, y compris après plusieurs suspensions et sur un runtime multi-thread.