Fermer

janvier 11, 2022

Conseils pour des journaux .NET plus efficaces


Dans cet article, nous aborderons des sujets importants concernant les journaux : comment les mettre en œuvre efficacement, les meilleures pratiques et garantir la pertinence pour les futures analyses de données.

Les journaux sont indispensables dans les applications modernes et qui nécessitent une attention particulière. Cela est particulièrement vrai lorsqu'il s'agit de développement Web avec ASP.NET Core, où les possibilités d'intégration entre les microservices et les API sont pratiquement infinies, et la surveillance de ces connexions peut devenir un grand défi.

En analysant du code, j'ai remarqué que le les journaux étaient toujours présents, mais en regardant en détail, j'ai vu que ces journaux étaient souvent sans importance, car ils contenaient peu ou pas d'informations importantes. Peut-être par manque de temps, distraction ou manque de connaissances, nous laissons échapper des détails qui peuvent faire beaucoup de différence, surtout lorsque nous avons un problème dans l'environnement de production.

Dans cet article, nous aborderons certains sujets importants concernant journaux et comment les mettre en œuvre efficacement, en utilisant les meilleures pratiques et en veillant à ce qu'ils soient pertinents pour l'analyse future des données.

1. Niveaux de journalisation et journalisation .NET

LogLevel dans le contexte .NET est une énumération C# qui définit les niveaux de gravité de la journalisation. Il fournit des méthodes d'extension pour indiquer les niveaux de journalisation et est disponible dans l'assembly Microsoft.Extensions.Logging.Abstractions.

Vous trouverez ci-dessous le tableau des niveaux de journalisation dans .NET Core.

Trace0LogTrace( )Les journaux qui contiennent les messages les plus détaillés. Ces messages peuvent contenir des données d'application sensibles. Ces messages sont désactivés par défaut et ne doivent jamais être activés dans un environnement de production.
Debug1LogDebug()Journaux utilisés pour une enquête interactive pendant le développement. Ces journaux doivent principalement contenir des informations utiles pour le débogage et n'avoir aucune valeur à long terme.
Information2LogInformation()Les journaux qui suivent le flux général de l'application. Ces journaux doivent avoir une valeur à long terme.
Warning3LogWarning()Les journaux qui mettent en évidence un événement anormal ou inattendu dans le flux de l'application, mais n'entraînent pas l'arrêt de l'exécution de l'application.
Error4LogError()Logs qui mettent en évidence le moment où le flux d'exécution actuel est arrêté en raison d'un échec. Ceux-ci doivent indiquer une défaillance de l'activité en cours, et non une défaillance à l'échelle de l'application. attention immédiate.
Aucun6AucunNon utilisé pour écrire des messages de journal. Spécifie qu'une catégorie de journalisation ne doit écrire aucun message.

Ce sont les niveaux de journalisation, qui doivent être utilisés en fonction du contexte auquel ils correspondent le mieux. Vous trouverez ci-dessous quelques exemples pratiques pour chaque niveau.

Exemples d'utilisation pour chaque niveau

public class LogService
{
    private readonly ILogger<LogService> _logger;

    public LogService(ILogger<LogService> logger )
    {
        _logger = logger;
    }

    public void ProccessLog()
    {
        var user = nouveau Utilisateur("John Smith", "smith@mail.com", "Kulas Light" , nulle, nulle);

        
        _logger.LogTrace("Traitement de la demande de l'utilisateur : {Name} - {ProccessLog}", user.Name , nameof(ProccessLog));


        
        var zipcodeDefault = "92998-3874";[19659055]if (user.Zipcode == zipcodeDefault)
            _logger.LogDebug("Le code postal est par défaut pour l'utilisateur : {Name} - {ProccessLog}", user.Name , nom de(ProccessLog)) ;


        
        _logger.LogInformation("Démarrage de l'exécution... - {ProccessLog}", nom de(ProccessLog) );


        
        if (string.IsNullOrEmpty(user.Zipcode))
            _logger.LogWarning("Le code postal est nul ou vide pour l'utilisateur : {Name} - {ProccessLog}", utilisateur.Nom, nom de(ProccessLog));


        
        try
        {
            var zipcodeBase =  "92998-3874";
            var résultat = false;

            if (user.Zipcode == zipcodeBase)
                result = true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message, "Erreur lors du traitement de la demande de l'utilisateur : {Nom} le code postal est nul ou vide . - {ProccessLog}", utilisateur.Nom, nomde(ProccessLog)) ; 
        }


        
        try
        {
            var userPhone = user.Phone;
        }
        catch[19659082](Exception ex)
        {
            _logger.LogCritical(ex.Message, "Le numéro de téléphone est nul ou vide pour l'utilisateur : {Nom}. Veuillez contacter immédiatement l'équipe d'assistance ! - {ProccessLog}", user.Name, nameof(ProccessLog))  ;
            jeté ;
        }


        
        
    }
}

2. Cadres ou bibliothèques de journalisation

Les fonctions disponibles dans Microsoft Logging Assembly répondent aux besoins de base de la journalisation et peuvent être utilisées sur n'importe quel système, grand ou petit. Cependant, certains scénarios nécessitent des journaux plus détaillés et plus d'options de personnalisation. Pour ces cas, il existe des bibliothèques qui peuvent aider et qui sont bien connues et acceptées dans la communauté de développement. est l'une des bibliothèques les plus connues, et quelques exemples d'utilisation.

Serilog

Serilog est actuellement la bibliothèque de journaux la plus téléchargée sur le site Web de NuGet. Vous pouvez le trouver ici : Serilog NuGet.

Comme d'autres bibliothèques, Serilog fournit une journalisation de diagnostic pour les fichiers, les consoles et bien plus encore. Sa configuration est facile et il dispose d'une grande variété de fonctions pour les applications modernes.

Un exemple pratique de son utilisation sera présenté ci-dessous, avec quelques-unes des différentes options de personnalisation disponibles dans Serilog.

Exemple pratique[19659170]Créez une nouvelle application de console avec .NET 6.

Vous pouvez le faire via Visual Studio 2022 ou via la console avec la commande suivante :

dotnet new console --framework net6.0

  1. Installez les bibliothèques suivantes dans la dernière version stable :
  • Serilog
  • Serilog.Expressions
  • Serilog.Formatting.Compact
  • Serilog.Sinks.Console
  • Serilog.Sinks.File
  1. Créer une classe appelé Offre et collez ce code dedans :
public record Offer(int Id, int ProductId,[19659039]chaîne Description, décimal Valeur, décimal Quantité);
  1. Remplacez le code de classe du programme par le code ci-dessous :
using Serilog;
using Serilog.Modèles ;

ExecuteLogs();

void ExecuteLogs()
{
    LogToConsole()
{
    LogToConsole([196590]);
    LogToFile();
}

void LogToConsole()
{
    var  offre = Remplir l'offre();

    Log.Logger = new LoggerConfiguration()
     .Enrich.WithProperty([19659059]"offreId", offre.Id)
     .Enrich.WithProperty("productId ", offre.ProductId)
     .Enrich.WithProperty("quantity" , offre.Quantité)
     .Écrire à.Console(nouveau Modèle d'expression([19659059]"{ {@t, @mt, @l: if @l = 'Information' then undefined() else @l, @x, ..@p} }n"))[19659223].Créer un enregistreur();

    Journal.Information("Informations sur l'offre");
}

void LogToFile() 
{
    var offre = Remplir l'offre();

    Log.Logger = new LoggerConfiguration()
     .Enrich.WithProperty([19659059]"offreId", offre.Id)
     .Enrich.WithProperty("productId ", offre.ProductId)
     .Enrich.WithProperty("quantity" , offre.Quantité)
     .Écrire à.Fichier(nouveau Modèle d'expression([19659293]"{ {@t, @mt, @l: if @l = 'Information' then undefined() else @l, @x, ..@p} }n"),[19659296]"Journaux\log.txt",
                 rollingInterval: RollingInterval.Day)
     .CreateLogger();

    Journal.Informations("Informations sur l'offre");
}

Offre RemplirOffre() =>
        nouveau Offre(5488, 100808,[19659061]"Book", 109, 3);
  1. Exécutez l'application.

Si vous avez suivi les étapes ci-dessus, vous verrez le résultat suivant dans la console de l'application :

{"@t":"2021-11-19T18:53:57.9627579-03:00","@mt":"Informations sur l'offre","offerId" :5488,"productId":100808,"quantity": 3}

Et dans le dossier : "binDebugnet6.0Logs" se trouve le fichier créé. À l'intérieur, il y aura les mêmes données que celles affichées dans la console.

Dans cet exemple, nous avons créé deux méthodes :

  • « LogToConsole() » – Il crée un objet appelé « Offre », puis utilise une nouvelle instance de « » LoggerConfiguration" et ajoute les valeurs des propriétés à la journalisation avec la méthode "Enrich.WithProperty". Ensuite, la méthode "WriteTo.Console" affiche la journalisation des données dans la console, et effectue la configuration du modèle via la classe "ExpressionTemplate".

  • "LogToFile()" – Il fait la même chose que la méthode précédente, mais utilise la méthode "WriteTo.File" pour créer un dossier "Logs" s'il n'existe pas, et à l'intérieur un fichier texte qui stockera les données du journal. La règle "rollingInterval" détermine l'intervalle dans lequel un nouveau fichier sera créé – dans cet exemple, un jour – c'est-à-dire que les journaux seront écrits dans le même fichier jusqu'à la fin de la journée, puis un nouveau fichier sera créé.

Il s'agissait d'une simple démonstration de l'utilisation de Serilog, mais cette bibliothèque possède de nombreuses fonctionnalités intéressantes. N'hésitez pas à les explorer.

3. Meilleures pratiques et recommandations

Journaux structurés

La création de journaux structurés est recommandée lorsque l'application utilise Microsoft Logging Assembly et également si elle utilise un filtrage avancé pour rechercher des journaux. Cela est nécessaire car le mécanisme d'enregistrement du journal doit recevoir la chaîne avec les espaces réservés et leurs valeurs séparément.

Vous trouverez ci-dessous un exemple de journal structuré :

_logger.LogWarning( "Le code postal est nul ou vide pour l'utilisateur : {Name}", user.Name;

Vous pouvez utiliser l'interpolation de chaîne. Cependant, vous devez vous assurer que le service d'enregistrement est prêt à accéder au modèle de message et aux valeurs de propriété même avec le remplacement.

Vous trouverez ci-dessous un exemple de journal structuré avec interpolation de chaîne :

_logger.LogWarning( $"Le code postal est nul ou vide pour l'utilisateur : {user.Name}" ;[19659343]Activer uniquement les journaux appropriés en production

Avant de publier quelque chose dans l'environnement de production, vous devez tenir compte des besoins réels d'utilisation de chacun des niveaux de journal. Par exemple, les journaux qui contiennent trop d'informations peuvent surcharger le serveur ou ralentir l'exécution du système.

Par conséquent, avant p Pour publier quoi que ce soit, une bonne pratique consiste à analyser tous les journaux et à ne laisser que ceux qui sont pertinents et n'entraîneront aucune sorte de surcharge. Les journaux de type Trace et Debug doivent être désactivés dans un environnement de production.

Utilisation d'une bibliothèque de journalisation tierce

Si vous démarrez un nouveau projet, vérifiez toujours si le client avec lequel vous travaillez utilise un troisième -party library et ce que c'est, car vous risquez de perdre votre temps dans quelque chose qui ne pourra peut-être pas entrer en production en raison de l'utilisation de la propriété privée.

Consignation d'informations sensibles

Ne jamais mettre d'informations sensibles ou privées dans les journaux de production, par exemple, les données relatives à l'utilisateur telles que les mots de passe, les numéros de carte de crédit ou toute information sur quelque chose qui ne peut pas être rendue publique. En plus d'être visibles par toute personne ayant accès aux données enregistrées, ces informations ne sont généralement pas cryptées et sont donc exposées si le système subit une sorte d'attaque de pirate. un point important dans le code ne signifie pas que le système est préparé pour une analyse détaillée, car si le message n'a pas beaucoup de sens pour ce contexte, son utilisation sera inutile.

Ainsi, lors de l'écriture des messages de journal, pensez sur ce qui serait une information vraiment importante pour une analyse future de l'exécution. Par exemple, dans les messages à l'intérieur des blocs d'exception, ajoutez toujours le message généré dans la méthode « Catch ».

Une autre recommandation que l'on peut voir dans l'exemple suivant est d'utiliser le nom de la méthode exécutée lors de l'écriture du journal. Dans le cas ci-dessous, nous utilisons dans le journal le nom de la méthode responsable de l'exécution via la commande "nameof(ProccessLog)"

public void ProccessLog( )
{
        try
        {
	
        }
        attrapez (Exception ex)
        {
 

            _logger.LogError(ex.Message, "Erreur lors du traitement de la demande de l'utilisateur : {Nom} le code postal est nul ou vide . - {ProccessLog}", utilisateur.Nom, nomde(ProccessLog)) ; 
        }
}

Conclusion

Dans cet article, nous avons couvert quelques conseils de bonnes pratiques pour écrire des journaux efficaces en C# et .NET. Une chose à considérer est qu'il n'y a pas de règles absolues pour l'écriture des journaux - tout dépendra du contexte dans lequel vous développez, mais si vous suivez ces conseils, votre code s'améliorera sûrement beaucoup.




Source link