Journalisation
Journaliser les évènements dans des fichiers .log
Notions théoriques
Pourquoi logger ?
Console.WriteLine s'affiche à l'écran mais disparaît dès que le terminal se ferme. En production (serveur, service Windows, conteneur Docker), il n'y a pas de terminal. Le logging (journalisation) permet d'enregistrer des événements dans un fichier ou un service centralisé, avec horodatage et niveau de gravité.
// MAUVAIS en production — disparaît avec le terminal
Console.WriteLine("Utilisateur connecté");
// BON — horodaté, nivelé, enregistré dans un fichier
logger.LogInformation("Utilisateur {Nom} connecté à {Heure}", nom, DateTime.Now);
Les 6 niveaux de log
Du moins grave au plus grave :
| Niveau | Méthode | Usage |
|---|---|---|
Trace | LogTrace | Détails très fins (débogage intensif) |
Debug | LogDebug | Informations de débogage |
Information | LogInformation | Événements normaux importants |
Warning | LogWarning | Situation anormale mais récupérable |
Error | LogError | Erreur — une opération a échoué |
Critical | LogCritical | Défaillance grave — application compromise |
Microsoft.Extensions.Logging — logging intégré .NET
Le package Microsoft.Extensions.Logging.Console est le plus courant pour les applications console. Il est préinstallé dans les projets ASP.NET Core, mais pour une application console simple il faut l'ajouter :
dotnet add package Microsoft.Extensions.Logging
dotnet add package Microsoft.Extensions.Logging.Console
using Microsoft.Extensions.Logging;
// Créer le logger
using ILoggerFactory factory = LoggerFactory.Create(builder =>
{
builder
.AddConsole()
.SetMinimumLevel(LogLevel.Debug); // affiche Debug et au-dessus
});
ILogger logger = factory.CreateLogger("MonApplication");
// Utilisation
logger.LogInformation("Application démarrée");
logger.LogDebug("Connexion à la base de données sur {Host}", "localhost");
logger.LogWarning("Tentative de connexion échouée pour {Utilisateur}", "alice");
logger.LogError("Impossible de lire le fichier {Chemin}", "/data/config.json");
Paramètres structurés {NomParam} vs interpolation $"..."
string utilisateur = "alice";
int tentatives = 3;
// MAUVAIS — interpolation : le message est une chaîne plate, on perd les données
logger.LogWarning($"Échec de connexion pour {utilisateur} après {tentatives} essais");
// BON — paramètres structurés : les valeurs sont indexées séparément
logger.LogWarning("Échec de connexion pour {Utilisateur} après {Tentatives} essais",
utilisateur, tentatives);
Avec les paramètres structurés, les systèmes de logging avancés (Elasticsearch, Seq, Azure Monitor) peuvent filtrer et rechercher par valeur : "montrer toutes les erreurs pour l'utilisateur alice". Avec l'interpolation, on obtient une chaîne plate impossible à filtrer.
Logger une exception avec sa pile d'appels
try
{
File.ReadAllText("donnees.txt");
}
catch (IOException ex)
{
// Passer l'exception EN PREMIER pour inclure la pile d'appels dans le log
logger.LogError(ex, "Impossible de lire le fichier {Chemin}", "donnees.txt");
}
Pour inclure la pile d'appels complète dans le log, passez l'exception comme premier argument de LogError. Si vous l'omettez ou la passez après le message, la pile d'appels n'est pas journalisée.
Serilog — logger populaire et flexible
Serilog est un package NuGet très utilisé qui offre plus de flexibilité que le logger intégré .NET, notamment pour écrire dans plusieurs destinations (console + fichier simultanément) :
Sur Windows (PowerShell) et Linux (Bash) — même commande :
dotnet add package Serilog
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
using Serilog;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.File("logs/journal.txt",
rollingInterval: RollingInterval.Day, // nouveau fichier chaque jour
retainedFileCountLimit: 7) // garder 7 jours
.CreateLogger();
Log.Information("Application démarrée");
Log.Warning("Stock faible pour {Produit} : {Stock} unité(s)", "Clavier", 2);
try
{
throw new InvalidOperationException("Base de données non disponible");
}
catch (Exception ex)
{
Log.Error(ex, "Erreur critique lors de l'initialisation");
}
finally
{
Log.CloseAndFlush(); // important : vider le tampon avant de quitter
}
Exemple pratique
using Microsoft.Extensions.Logging;
using ILoggerFactory factory = LoggerFactory.Create(builder =>
builder.AddConsole().SetMinimumLevel(LogLevel.Debug));
ILogger logger = factory.CreateLogger("GestionStock");
// Simulation d'un système de gestion de stock
var stock = new Dictionary<string, int>
{
["Clavier"] = 5,
["Souris"] = 0,
["Écran"] = 2,
};
logger.LogInformation("=== Démarrage de la vérification du stock ===");
foreach (var (produit, quantite) in stock)
{
if (quantite == 0)
{
logger.LogError("Rupture de stock détectée pour {Produit}", produit);
}
else if (quantite < 3)
{
logger.LogWarning("Stock faible pour {Produit} : {Quantite} unité(s)", produit, quantite);
}
else
{
logger.LogDebug("Stock OK pour {Produit} : {Quantite} unité(s)", produit, quantite);
}
}
// Simulation d'une opération qui peut échouer
try
{
logger.LogInformation("Lecture du fichier de configuration...");
if (!File.Exists("config.json"))
throw new FileNotFoundException("Fichier de configuration manquant.", "config.json");
logger.LogInformation("Configuration chargée avec succès");
}
catch (FileNotFoundException ex)
{
logger.LogError(ex, "Impossible de charger la configuration : {Fichier}", ex.FileName);
logger.LogWarning("Utilisation des valeurs par défaut");
}
logger.LogInformation("=== Vérification terminée ===");
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez créer un journal d'activité pour un système de gestion de notes.
Étape 1 — Configurer le logger
Créez et configurez un logger qui affiche les niveaux Information et au-dessus.
En développement, utilisez LogLevel.Debug pour voir tous les détails. En production, utilisez LogLevel.Information ou LogLevel.Warning pour éviter de noyer les logs importants dans du bruit. Le niveau minimum se configure idéalement dans appsettings.json et non dans le code, pour pouvoir le changer sans recompiler.
Étape 2 — Logger les opérations
Loggez les ajouts de notes avec le niveau approprié selon la note.
Utilisez le niveau adapté à la gravité de l'événement : Information pour les événements normaux, Warning pour les situations préoccupantes mais gérées, Error pour les erreurs qui empêchent une opération de réussir, Critical pour les défaillances qui compromettent toute l'application. Un log Error pour chaque note en dessous de 10 ferait croire à une panne alors qu'il s'agit juste d'un résultat médiocre.
Étape 3 — Logger les exceptions
Capturez une exception et loggez-la avec sa pile d'appels.
Passer l'exception comme premier argument de LogError inclut automatiquement la pile d'appels complète dans le log. C'est indispensable pour diagnostiquer les problèmes en production. Sans la pile d'appels, vous savez qu'une erreur s'est produite, mais pas où dans le code elle a été déclenchée.