Meilleures pratiques pour la journalisation et le traçage dans .NET

53

J'ai beaucoup lu sur le traçage et la journalisation, essayant de trouver une règle d'or pour les meilleures pratiques en la matière, mais il n'y en a pas. Les gens disent que les bons programmeurs produisent un bon traçage, mais disent-le comme ça et ça doit venir de l'expérience.

J'ai aussi lu des questions similaires ici et sur Internet et ce ne sont pas vraiment les mêmes choses que je pose ou je n'ai pas de réponse satisfaisante, peut-être parce que les questions manquent de détails.

Ainsi, les gens disent que le traçage devrait en quelque sorte reproduire l'expérience de débogage de l'application dans les cas où il est impossible d'attacher un débogueur. Il doit fournir suffisamment de contexte pour que vous puissiez voir quel chemin est pris à chaque point de contrôle de l'application.

En approfondissant, vous pouvez même distinguer entre le suivi et la journalisation des événements, en ce sens que "la journalisation des événements est différente du traçage car elle capture les états principaux plutôt que le flux de contrôle détaillé".

Maintenant, disons que je veux effectuer le traçage et la journalisation en utilisant uniquement les classes .NET standard, celles de l’ System.Diagnosticsespace de noms. J'ai pensé que la classe TraceSource était meilleure pour le travail que la classe Trace statique, car je souhaitais différencier les niveaux de trace et en utilisant la classe TraceSource, je pouvais transmettre un paramètre informant le type d'événement, tout en utilisant la classe Trace que je devais utiliser. Trace.WriteLineIfet ensuite vérifier les choses comme SourceSwitch.TraceInformationet SourceSwitch.TraceErrors, et il n'a même pas de propriétés comme TraceVerboseou TraceStart.

Avec tout cela à l'esprit, considéreriez-vous une bonne pratique à suivre:

  • Tracez un événement "Start" au début d'une méthode, qui devrait représenter une seule opération logique ou un pipeline, ainsi qu'une représentation sous forme de chaîne des valeurs de paramètre transmises à la méthode.
  • Trace un événement "Information" lors de l'insertion d'un élément dans la base de données.
  • Tracez un événement "Information" lorsque vous prenez un chemin ou un autre dans une déclaration if / else importante.
  • Tracez une "critique" ou une "erreur" dans un bloc catch, selon qu'il s'agisse ou non d'une erreur récupérable.
  • Trace un événement "Stop" à la fin de l'exécution de la méthode.

Et aussi, s'il vous plaît préciser quand mieux tracer les types d'événements Verbose et Warning. Si vous avez des exemples de code avec une trace / journalisation agréable et êtes disposé à partager, ce serait excellent.

Remarque: j'ai trouvé quelques bonnes informations ici, mais toujours pas ce que je cherche: http://msdn.microsoft.com/en-us/magazine/ff714589.aspx

Levidad
la source
Peut - être que la manière préférée de se connecter à net-déployé sur azure au niveau de stackoverflow est également utile.
K3B
un exemple d'application de code source complet utilisant de bons modèles pour la journalisation?
Kiquenet
Honnêtement ... Si je travaillais avec .NET, j'installerais probablement quelque chose comme New Relic et l'appellerai terminé. (Peut-être pas une bonne option au moment où cela a été posté)
svidgen

Réponses:

17

L'importance des types de trace doit être choisie non pas en fonction de l'emplacement de la trace dans le code, mais en raison du fait que le message suivi est plus ou moins important. Exemple:

Tracez un événement "Start" lors du démarrage d'une méthode, qui devrait représenter une opération logique unique ou un pipeline, ainsi qu'une représentation sous forme de chaîne des valeurs de paramètre transmises à la méthode.

Utilisez le type de démarrage lorsque vous démarrez une opération logique. Cela ne signifie pas que la trace de début doit être au début d'une méthode, cela ne signifie pas non plus qu'une méthode doit avoir une trace de début.

Ceci étant dit, dans la plupart des cas, une opération logique commencera au début de la méthode. Sinon, vous devriez vous demander si le code est refactoré correctement.

Le suivi des paramètres peut également être une mauvaise idée . Vous devez penser quoi tracer, au cas par cas. Par exemple, il est vraiment mauvais de tracer les paramètres d’une méthode void Authenticate(string userName, string plainPassword).

Trace un événement "Information" lors de l'insertion d'un élément dans la base de données.

Ça dépend. Certains articles doivent être suivis, mais pas tous.

  • Par exemple, imaginez que vous insérez réellement un élément de journal dans votre base de données. Voulez-vous suivre les journaux? Et puis trace des traces? Et puis trace la journalisation de la trace?
  • Autre exemple: vous insérez des données sensibles. Cela nécessite un audit. Depuis que vous avez vérifié l'insertion, pourquoi la rechercher?

Tracez un événement "Information" lorsque vous prenez un chemin ou un autre dans une déclaration if / else importante.

Encore une fois, cela dépend.

Tracer une "critique" ou une "erreur" dans un bloc catch en fonction de la météo, il s'agit d'une erreur récupérable.

L'action entreprise après une erreur non récupérable peut être plus que le traçage. Par exemple, côté serveur, vous souhaitez stocker l'exception dans la base de données pour une analyse ultérieure. En outre, certaines exceptions sont moins importantes que d’autres et ne nécessitent pas de traçage.

Trace un événement "Stop" à la fin de l'exécution de la méthode.

Voir le premier point.

veuillez préciser le meilleur moment pour tracer les types d'événements Verbose et Warning.

Verbeux:

Verbose est utilisé pour identifier ce que vous devez identifier lorsque quelque chose ne va vraiment pas. Cela signifie que dans la plupart des cas, vous désactiverez le traçage des messages commentés, mais vous devrez parfois déboguer certaines parties de votre code pour comprendre pourquoi quelque chose échoue sur un cas d'extrémité.

Vous avez généralement beaucoup de messages commentés qui vous permettent de bien comprendre le flux des applications. Cela signifie également que ces messages doivent être désactivés la plupart du temps pour les raisons suivantes:

  • sinon, le journal se développera très vite,
  • vous n'en avez pas besoin la plupart du temps,
  • ils peuvent contenir des données sensibles sur le flux de l'application.

Pensez à verbose comme un outil que vous devez utiliser lorsque vous n’avez pas accès au débogueur.

Attention:

La trace de type avertissement est utilisée lorsque quelque chose d'anormal se produit, mais elle n'est pas trop cruciale pour être traitée comme une erreur. Par exemple, une mémoire vive faible peut émettre un avertissement, mais il n’ya aucune raison de rechercher une erreur, car votre application peut continuer, même si elle sera plus lente que d’habitude.

Exemples:

  • Exemple 1: l'application n'a pas réussi à ouvrir le fichier que l'utilisateur a demandé d'ouvrir. Le fichier existe et n'est pas utilisé, les autorisations sont définies correctement, mais quelque chose bloque l'ouverture d'un fichier. Dans ce cas, vous allez tracer une erreur , car votre application ne peut pas gérer ce cas et continue à fonctionner comme prévu par l'utilisateur (c.-à-d. Qu'il lit le fichier).

  • Exemple 2: après l'inspection de l'erreur dans le premier exemple, vous constatez que l'erreur est provoquée par le fait que le chemin d'accès au fichier comporte plus de 259 caractères. Donc, vous refactorisez votre code pour attraper PathTooLongException. Lorsque, la prochaine fois, l'utilisateur essaie d'ouvrir le même fichier, la nouvelle version de l'application affiche un message expliquant que le fichier est trop long et qu'il doit être déplacé dans un autre dossier pour raccourcir le chemin complet afin de l'ouvrir. cette application. Vous tracez également un message .

  • Exemple 3: votre application a passé vingt secondes à ouvrir et à analyser un petit fichier, tandis que la plupart des fichiers prennent entre dix et cent millisecondes à ouvrir et à analyser. Vous tracez un avertissement avec des informations pertinentes: le type de disque sur lequel se trouve réellement le fichier, le système de fichiers, la taille du fichier, le temps exact passé, le temps allumé, etc. Lorsque l'utilisateur se plaint qu'il faut vingt secondes pour ouvrir le fichier, vous prenez la trace pour trouver ce qui se passe. Vous constatez par exemple que le chargement des fichiers depuis un partage réseau prend tellement de temps que l'ordinateur vient de démarrer. Vous expliquez à l'utilisateur que le retard est dû au réseau et n'est pas lié à votre application.

  • Exemple 4: le fichier ouvert est affiché de manière incorrecte. Vous activez la trace détaillée où vous voyez réellement comment les données sont chargées à partir d'un fichier, puis analysées, étape par étape.

Arseni Mourzenko
la source
Un modèle que nous utilisons où je travaille est la consignation de "KnownErrors" en tant qu'avertissements et de "UnknownErrors" en tant qu'erreurs. Cela peut ne pas être approprié en fonction de votre infrastructure et de la manière dont elle traite les avertissements, mais cela fonctionne bien pour nous.
Andrew dit Réintégrer Monica
5
 > say I want to do my tracing and logging using only the standard .NET classes

System.Diagnostics est génial car vous pouvez configurer où les informations de trace doivent aller où (fichier, journal des événements, base de données, ....)

Malheureusement, si vous voulez utiliser, System.Diagnosticsvous devez savoir à l'avance ( au moment de la conception ) quels flux de trace devraient pouvoir être suivis. (Dans l'exemple d'article, il s'agit de Transfert, Reprise, Suspension, ...). Ceux-ci peuvent être configurés pour être désactivé, Debuglevel ou Errorlevel.

Je préfère avoir un système de journalisation où je peux décider, au moment de l'exécution, de classlevel / namespacelevel , du niveau de détail de la journalisation. Par exemple, tous les Debug et supérieurs de MyNamespace.Business.*mais pas MyNamespace.Business.Calculations.

Si vous utilisez log4net (ou Common.logging), chaque classe reçoit son propre enregistreur afin que vous puissiez facilement décider quelles classes seront journalisées à quel niveau.

Comme les opérations de base de données sont dans une classe séparée, il n’est plus nécessaire de disposer d’une règle distincte.

Trace an "Information" event when inserting an item into the database.

Au lieu de cela, je préfère avoir ces directives:

  • Tracelevel devrait montrer le flux de travail de base
  • Debuglevel doit afficher les données détaillées et le traitement dans le flux de travail, y compris les décisions dans le flux de programmes avec des raisons (Création d'un nouvel élément car cet élément n'existait pas dans la base de données)
  • Infolevel pour le démarrage / l’arrêt des services et une entrée pour chaque action de flux de travail / interface graphique démarrée
k3b
la source
Je vois, c'est une bonne information, merci! Néanmoins, comme je le demande dans ma question initiale, pourriez-vous clarifier les utilisations des types d’événements Verbose et Warning? Et aussi, je demande à d’autres personnes d’apporter leur point de vue, car ce sujet mérite une exploration plus profonde que celle que j’ai vue sur Internet.
Levidad
4

Vous pouvez essayer le framework Story , il a une approche unique de la journalisation car il vous permet d'écrire tous les journaux (et d'ajouter d'autres informations pertinentes) dans leur contexte. Ainsi, lorsque vous aurez besoin de le lire plus tard, vous obtiendrez tout ce dont vous avez besoin.

Il ajoutera automatiquement les concepts "commencer" et "arrêter" au début et à la fin d'une histoire.

Et avec un système basé sur des règles, vous pouvez contrôler l'utilisation de chaque récit (contexte) en fonction des informations dont il dispose, par exemple, imprimer tous les récits comportant une erreur ou provenant de l'utilisateur "admin".

Aussi plus d'informations sur ce blog

Amit Apple
la source
1
réponse mise à jour avec plus d'informations
Amit Apple