CodeGym /Cours /C# SELF /Journalisation structurée et

Journalisation structurée et Serilog

C# SELF
Niveau 64 , Leçon 1
Disponible

1. Introduction

Si la journalisation texte basique — c'est votre journal intime avec des notes "J'ai mangé aujourd'hui", alors la journalisation structurée transforme chaque entrée en une fiche avec des champs : {Date: ..., Événement: "Mangé", Calories: 500, Plat: "Viande rôtie"}. Ça veut dire que vous pouvez ensuite non seulement lire le journal, mais aussi construire un graphique des calories sur un mois, filtrer les événements par plat et savoir quand vous avez mangé trop tard.

Pourquoi le texte simple ne suffit-il pas ?

Avec du texte simple tout est simple... jusqu'à un certain point. Essayez de rassembler des statistiques sur les erreurs dans les logs, les volumes de ventes d'une boutique en ligne, la chaîne d'actions d'un utilisateur par son ID (par exemple 42), si toutes les données sont des pavés de texte. La journalisation structurée permet d'ajouter de l'analyse et même de l'IA aux logs. Avec elle on peut chercher des anomalies, construire des dashboards et réagir automatiquement aux problèmes.

Avantages

  • Permet de logger non seulement des messages, mais aussi les données associées (champs/propriétés).
  • Les logs peuvent être analysés automatiquement : compter, filtrer, générer des rapports.
  • On utilise des formats standardisés, comme JSON, faciles à parser par des machines.

Serilog : qu'est-ce que c'est et pourquoi l'utiliser ?

Serilog (site officiel : serilog.net, documentation : github.com/serilog/serilog/wiki) est une bibliothèque populaire pour la journalisation structurée en .NET. Elle s'intègre très bien avec Microsoft.Extensions.Logging, supporte la sortie vers des dizaines de systèmes (fichier, console, Seq, ElasticSearch, Grafana, Azure, etc.), a un impact minimal sur la performance et est simple à configurer.

En quoi Serilog diffère du "simple logging" ?

  • Structure : les logs sont des objets avec des champs, sur lesquels on peut filtrer (par ex. toutes les erreurs de l'utilisateur avec l'ID 42).
  • Formats : sait écrire pas seulement du texte, mais aussi du JSON, du XML, pratique pour le traitement ultérieur.
  • Flexibilité : beaucoup de packages-sinks prêts à envoyer les logs partout.

Structure d'une entrée de log avec Serilog

Regardons un log structuré avant d'écrire du code.

{
  "Timestamp": "2024-06-22T10:23:45.123Z",
  "Level": "Information",
  "MessageTemplate": "L'utilisateur {UserId} s'est connecté",
  "Properties": {
    "UserId": 42,
    "IpAddress": "127.0.0.1"
  }
}

Même sans analyse avancée on comprend : il s'agit de l'utilisateur n°42 et de son adresse IP.

2. Installation et configuration de base de Serilog dans un projet C#

Étape 1. Installer les packages NuGet

Dans Rider/Visual Studio via le NuGet Package Manager installez :

  • Serilog
  • Serilog.Sinks.Console (sortie vers la console)
  • Serilog.Extensions.Logging (pour l'intégration avec Microsoft.Extensions.Logging)

Via la ligne de commande :

dotnet add package Serilog
dotnet add package Serilog.Sinks.Console

Étape 2. Configuration minimale

Ajoutons la config dans Program.cs et écrivons le premier log.

using System;
using Serilog;

namespace MySuperApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // 1. Configuration basique de Serilog : sortie console
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.Console()
                .CreateLogger();

            // 2. Exemple de journalisation structurée
            int userId = 42;
            string ip = "127.0.0.1";
            Log.Information("L'utilisateur {UserId} s'est connecté avec l'IP {IpAddress}", userId, ip);

            Log.CloseAndFlush();
        }
    }
}

Dans la console on verra à peu près ceci :

[10:30:16 INF] L'utilisateur 42 s'est connecté avec l'IP 127.0.0.1

Ensuite il est facile d'envoyer la sortie dans un fichier JSON, Seq ou un autre système.

3. Formatage des logs : Message Template

Dans Serilog on utilise la syntaxe des templates au lieu de concaténer des chaînes :

Log.Information("Opération {Operation} sur le fichier {FileName}", "suppression", "test.txt");

Ce n'est pas qu'une jolie écriture — c'est de la journalisation structurée : les champs Operation et FileName seront présents dans l'entrée, accessibles pour filtrage et agrégation.

En quoi cela diffère-t-il de string.Format ?

string.Format("Opération {0} sur le fichier {1}", operation, fileName) concatène simplement la chaîne avec des placeholders {0}, {1}. Serilog crée des champs séparés avec lesquels on peut ensuite travailler analytiquement.

Configuration flexible : niveaux, filtres, différents "sinks"

Serilog peut écrire les logs simultanément à plusieurs endroits.

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Console()
    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

Maintenant les logs sont écrits à la fois dans la console et dans un fichier avec rotation quotidienne.

4. Exemple

Supposons que nous faisons une application console "bloc-notes" qui permet de créer des entrées utilisateur. Ajoutons la journalisation structurée des actions.

using System;
using Serilog;

namespace NotesApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.Console()
                .WriteTo.File("notes-log.json", rollingInterval: RollingInterval.Day, 
                              formatter: new Serilog.Formatting.Json.JsonFormatter())
                .CreateLogger();

            Console.WriteLine("Entrez le nom d'utilisateur :");
            string userName = Console.ReadLine();

            Log.Information("L'utilisateur {UserName} a lancé l'application NotesApp", userName);

            while (true)
            {
                Console.WriteLine("Entrez le texte de la note (ou tapez 'sortie') :");
                string note = Console.ReadLine();

                if (note == "sortie")
                {
                    Log.Information("L'utilisateur {UserName} a quitté", userName);
                    break;
                }

                Log.Information("L'utilisateur {UserName} a créé une note : {NoteText}", userName, note);
            }

            Log.CloseAndFlush();
        }
    }
}

Commentaire :
Le log enregistre qui lance le programme, ce qui est saisi et quand il quitte. Dans le fichier notes-log.json chaque entrée est un objet JSON facile à analyser.

5. Détails utiles

Bonnes pratiques de la journalisation structurée

  • N'abusez pas des niveaux Debug/Trace en production — utilisez Information et Warning judicieusement.
  • Utilisez des paramètres nommés dans les templates au lieu de concaténer des chaînes.
  • Ne logguez jamais de données sensibles (mots de passe, tokens, clés).
  • Logguez les événements métier importants, pas seulement les erreurs et exceptions.
  • Configurez la rotation et le nettoyage des logs pour éviter de remplir le disque.

Visualisation et analyse : Seq, Kibana, Application Insights

Serilog supporte de nombreux sinks — destinations où envoyer les logs.

Sink Courte description Où c'est utilisé
Console Directement dans la console Développement, tests
File Dans un fichier local ou réseau Petits projets, dev
Seq Interface web avec filtrage et dashboards Entreprise, analytics
ElasticSearch Puissant système de stockage et d'analyse Grandes entreprises
Azure Application Insights Monitoring cloud et télémétrie Services fortement chargés sur Azure

Seq (datalust.co/seq) — solution très populaire pour le développement et l'usage interne : filtrage pratique, recherche par champs et déploiement rapide.

Tables et visualisation

Ci-dessous — un petit tableau de ce qu'on peut logger de façon structurée :

Ce qu'on loggue À quoi ça ressemble dans Serilog Exemple de valeur
ID utilisateur
{UserId}
123
Action
{Action}
"Suppression"
Erreur
Log.Error(ex, "Erreur dans {Module}")
"Module d'enregistrement"
Temps d'opération {Elapsed:0.000} s 1.234
Nom de fichier
{FileName}
"report.pdf"

Astuces et fonctionnalités additionnelles de Serilog

  • Enrichers : ajoutent des propriétés à chaque log (par ex. .Enrich.WithMachineName()).
  • Logs corrélés : ajoutez RequestId pour corréler une chaîne d'événements.
  • Configuration via appsettings.json : pratique pour la production.
{
  "Serilog": {
    "MinimumLevel": "Debug",
    "WriteTo": [
      { "Name": "Console" },
      { "Name": "File", "Args": { "path": "log.txt" } }
    ]
  }
}

Advanced sinks : on peut envoyer des logs vers Slack, Telegram, par mail (mais attention à ne pas recevoir mille mails pour chaque erreur).

6. Partie pratique : intégration avec Microsoft.Extensions.Logging

En .NET on utilise souvent l'interface standard ILogger pour ne pas être lié à une librairie précise. Serilog peut être connecté en tant que provider.

Étape 1. Installer le package

dotnet add package Serilog.Extensions.Logging

Étape 2. Configuration

using Microsoft.Extensions.Logging;
using Serilog;

// ...

// Configurer Serilog comme d'habitude :
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateLogger();

// Maintenant on utilise Microsoft.Extensions.Logging
var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddSerilog();
});

ILogger<Program> logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Message de test : {TestValue}", 123);

// N'oubliez pas de fermer :
Log.CloseAndFlush();

Commentaire :
Désormais tout votre code utilisant ILogger<T> est indépendant du provider — si vous voulez vous pouvez basculer vers NLog ou Log4Net.

7. Erreurs typiques en travaillant avec Serilog

Surcharge des logs : si vous logguez tout, l'information utile sera difficile à trouver.

Logger les exceptions comme du texte : utilisez la surcharge avec l'exception — ainsi la structure de l'erreur sera incluse dans le log.

try
{
    // some code
}
catch (Exception ex)
{
    Log.Error(ex, "Une erreur s'est produite lors de l'exécution de la requête");
}

Abus de configuration : ne transformez pas la configuration en dépotoir — n'ajoutez que les sinks et niveaux nécessaires.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION