Journalisation dans les applications Rust : meilleures pratiques en pratique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Journalisation dans les applications Rust : meilleures pratiques en pratique



La journalisation est l'un des éléments clés de toute application de production. Elle aide à diagnostiquer les erreurs, à suivre le comportement du système et à collecter des métriques. Dans l'écosystème Rust, il existe plusieurs solutions matures pour cela. Dans cet article, nous allons analyser les meilleures pratiques de journalisation avec des exemples de code concrets.



1. Les bases : crate log et architecture façade



En Rust, le standard de facto est le crate log. Il fournit une façade abstraite, non liée à une implémentation spécifique. Cela signifie que vous écrivez les logs via les macros log, et quel backend les traitera (affichage dans la console, dans un fichier, envoi vers ELK) est décidé au moment de l'ajout d'un autre crate.



Configuration de la journalisation de base



// Cargo.toml[dependencies]log = "0.4"env_logger = "0.11"


// main.rsuse log::{info, warn, error, debug};

fn main() { // Initialiser env_logger (lit la variable RUST_LOG) env_logger::init();

info!("Application démarrée"); warn!("Configuration par défaut utilisée"); error!("Erreur critique : {}", "fichier non trouvé");}


Exécutez l'application avec la variable d'environnement :

RUST_LOG=info cargo run


Vous verrez à l'écran :

[2025-01-15T10:30:00Z INFO  my_app] Application démarrée[2025-01-15T10:30:00Z WARN  my_app] Configuration par défaut utilisée[2025-01-15T10:30:00Z ERROR my_app] Erreur critique : fichier non trouvé


2. Configuration flexible des niveaux de journalisation



La variable RUST_LOG permet de filtrer les messages de manière flexible par modules et niveaux. C'est crucial pour les grands projets où le bruit des logs de débogage peut masquer des événements importants.



Exemples de filtrage



# Uniquement les erreurs et avertissements de toute l'applicationRUST_LOG=warn

# Débogage uniquement dans le module database, le reste en infoRUST_LOG=info,my_crate::database=debug

# Tous les niveaux, y compris traceRUST_LOG=trace


En pratique, utilisez cette approche :

use std::env;

fn setup_logging() { if env::var("RUST_LOG").is_err() { // Valeur par défaut pour le développement env::set_var("RUST_LOG", "info,my_crate=debug"); } env_logger::init();}


3. Journalisation structurée avec tracing



Pour les systèmes complexes (microservices, applications asynchrones), il est préférable d'utiliser le crate tracing. Il prend en charge les spans et les champs structurés, ce qui permet de lier les logs en chaînes de requêtes.



Comparaison de log et tracing



  • log — simple, léger, adapté aux petits projets.
  • tracing — puissant, prend en charge les spans, les événements, les champs structurés ; idéal pour le code async et les systèmes avec instrumentation tracing.


Exemple avec tracing et tracing-subscriber



// Cargo.toml[dependencies]tracing = "0.1"tracing-subscriber = "0.3"


use tracing::{info, error, span, Level};use tracing_subscriber::FmtSubscriber;

#[tokio::main]async fn main() { // Configuration du subscriber pour la sortie stdout let subscriber = FmtSubscriber::builder() .with_max_level(Level::TRACE) .finish(); tracing::subscriber::set_global_default(subscriber) .expect("Impossible de définir le subscriber");

// Création d'un span pour une requête HTTP let request_span = span!(Level::INFO, "http_request", method = "GET", path = "/api/users"); let _guard = request_span.enter();

info!("Traitement de la requête commencé");

// Span imbriqué pour le travail avec la base de données let db_span = span!(Level::DEBUG, "db_query", query = "SELECT * FROM users"); let _db_gu

Blogs

Book Recommendations