Journalisation des meilleures pratiques [fermé]


323

J'aimerais avoir des histoires sur la façon dont les gens gèrent le traçage et la journalisation dans de vraies applications. Voici quelques questions qui pourraient aider à expliquer votre réponse.

Cadres

Quels cadres utilisez-vous?

  • log4net
  • System.Diagnostics.Trace
  • System.Diagnostics.TraceSource
  • Bloc d'application de journalisation
  • Autre?

Si vous utilisez le traçage, utilisez-vous Trace.Correlation.StartLogicalOperation?

Ecrivez-vous ce code manuellement ou utilisez-vous une forme de programmation orientée aspect pour le faire? Vous souhaitez partager un extrait de code?

Fournissez-vous une forme de granularité sur les sources de trace? Par exemple, WPF TraceSources vous permet de les configurer à différents niveaux:

  • System.Windows - paramètres pour l'ensemble de WPF
  • System.Windows.Animation - remplacer spécifiquement pour l'animation.

Les auditeurs

Quelles sorties de journal utilisez-vous?

  • Fichiers texte
  • Fichiers XML
  • Journal des événements
  • Autre?

Si vous utilisez des fichiers, utilisez-vous des journaux de roulement ou un seul fichier? Comment mettez-vous les journaux à la disposition des utilisateurs?

Visualisation

Quels outils utilisez-vous pour afficher les journaux?

  • Bloc-notes
  • Queue
  • Observateur d'événements
  • Systems Operations Manager / Microsoft Operations Manager
  • Afficheur de trace de service WCF
  • Autre?

Si vous créez une solution ASP.NET, utilisez-vous également ASP.NET Health Monitoring? Incluez-vous la sortie de trace dans les événements du moniteur d'intégrité? Qu'en est-il de Trace.axd?

Qu'en est-il des compteurs de performances personnalisés?


3
Il serait utile que les personnes fermant des questions comme celle-ci avec 300 votes positifs suggèrent un format wiki ou une publication sur programmers.stackexchange, ou bien Quora si ce type de question n'est pas le bienvenu. Évidemment, la question est en fait très constructive, elle ne correspond tout simplement pas aux critères souhaités par StackOverflow. programmers.stackexchange.com/questions/57064/… a 24 votes positifs. Peut-être que StackOverflow manque quelque chose?
Niall Connaughton

Si cette question viole le format Q&A, alors il y a quelque chose de mal avec le format Q&A et non avec cette question. Parfois, la décision de clore une question doit être fonction des réponses fournies, certaines questions ouvertes invitent au débat, mais d'autres invitent les utilisateurs à fournir un contenu précieux, comme celui-ci!
Matthias Wolf

1
Cette question - en particulier la première réponse - constituerait probablement une excellente base pour un article de blog si quelqu'un voulait l'utiliser en tant que tel ... En tant que question objective, elle ne correspond pas vraiment - elle est structurée explicitement comme un sondage de paille - mais il y a quelques bonnes informations ci-dessous, d'où le verrou.
Shog9

Réponses:


232

Mise à jour: pour les extensions de System.Diagnostics, fournissant certains des écouteurs manquants que vous pourriez souhaiter, voir Essential.Diagnostics sur CodePlex ( http://essentialdiagnostics.codeplex.com/ )


Cadres

Q: Quels cadres utilisez-vous?

R: System.Diagnostics.TraceSource, intégré à .NET 2.0.

Il fournit une journalisation puissante, flexible et hautes performances pour les applications, mais de nombreux développeurs ne connaissent pas ses capacités et ne les utilisent pas pleinement.

Il existe des domaines dans lesquels des fonctionnalités supplémentaires sont utiles, ou parfois elles existent mais ne sont pas bien documentées, mais cela ne signifie pas que l'ensemble du cadre de journalisation (conçu pour être extensible) doit être jeté et complètement remplacé comme certaines alternatives populaires. (NLog, log4net, Common.Logging et même EntLib Logging).

Plutôt que de changer la façon dont vous ajoutez des instructions de journalisation à votre application et de réinventer la roue, il vous suffit d'étendre le cadre System.Diagnostics aux rares endroits où vous en avez besoin.

Il me semble que les autres frameworks, même EntLib, souffrent simplement du syndrome de Not Invented Here, et je pense qu'ils ont perdu du temps à réinventer les bases qui fonctionnent déjà parfaitement bien dans System.Diagnostics (comme la façon dont vous écrivez des instructions de journal), plutôt que de combler les quelques lacunes qui existent. En bref, ne les utilisez pas - ils ne sont pas nécessaires.

Des fonctionnalités que vous ne connaissiez peut-être pas:

  • L'utilisation des surcharges TraceEvent qui prennent une chaîne de format et des arguments peuvent améliorer les performances car les paramètres sont conservés en tant que références distinctes jusqu'à ce que Filter.ShouldTrace () réussisse. Cela signifie qu'aucun appel coûteux à ToString () sur les valeurs des paramètres tant que le système n'a pas confirmé le message sera réellement enregistré.
  • Le Trace.CorrelationManager vous permet de corréler les instructions de journal concernant la même opération logique (voir ci-dessous).
  • VisualBasic.Logging.FileLogTraceListener est bon pour écrire dans des fichiers journaux et prend en charge la rotation de fichiers. Bien que dans l'espace de noms VisualBasic, il peut être tout aussi facilement utilisé dans un projet C # (ou autre langage) simplement en incluant la DLL.
  • Lorsque vous utilisez EventLogTraceListener si vous appelez TraceEvent avec plusieurs arguments et avec une chaîne de format vide ou nulle, les arguments sont transmis directement à EventLog.WriteEntry () si vous utilisez des ressources de message localisées.
  • L'outil Service Trace Viewer (de WCF) est utile pour afficher des graphiques de fichiers journaux d'activité corrélés (même si vous n'utilisez pas WCF). Cela peut vraiment aider à déboguer des problèmes complexes où plusieurs threads / activités sont impliqués.
  • Évitez les frais généraux en effaçant tous les écouteurs (ou en supprimant Default); sinon Default passera tout au système de trace (et encourra tous ces frais généraux ToString ()).

Domaines que vous pourriez envisager d'étendre (si nécessaire):

  • Écouteur de trace de base de données
  • Écouteur de trace de console colorée
  • Écouteurs de trace MSMQ / Email / WMI (si nécessaire)
  • Implémentez un FileSystemWatcher pour appeler Trace.Refresh pour les changements de configuration dynamiques

Autres recommandations:

Utilisez des identifiants d'événement structurés et conservez une liste de références (par exemple, documentez-les dans une énumération).

Avoir des ID d'événement uniques pour chaque événement (significatif) dans votre système est très utile pour corréler et trouver des problèmes spécifiques. Il est facile de retracer le code spécifique qui enregistre / utilise les identifiants d'événement et peut faciliter la fourniture de conseils pour les erreurs courantes, par exemple l'erreur 5178 signifie que votre chaîne de connexion à la base de données est incorrecte, etc.

Les ID d'événement doivent suivre une sorte de structure (similaire à la théorie des codes de réponse utilisés dans les e-mails et HTTP), qui vous permet de les traiter par catégorie sans connaître de codes spécifiques.

Par exemple, le premier chiffre peut détailler la classe générale: 1xxx peut être utilisé pour les opérations «Démarrer», 2xxx pour le comportement normal, 3xxx pour le suivi des activités, 4xxx pour les avertissements, 5xxx pour les erreurs, 8xxx pour les opérations «Arrêter», 9xxx pour les erreurs fatales, etc.

Le deuxième chiffre peut détailler la zone, par exemple 21xx pour les informations de base de données (41xx pour les avertissements de base de données, 51xx pour les erreurs de base de données), 22xx pour le mode de calcul (42xx pour les avertissements de calcul, etc.), 23xx pour un autre module, etc.

Les ID d'événement structurés et attribués vous permettent également de les utiliser dans des filtres.

Q: Si vous utilisez le traçage, utilisez-vous Trace.Correlation.StartLogicalOperation?

R: Trace.CorrelationManager est très utile pour corréler les instructions de journal dans n'importe quel type d'environnement multi-thread (ce qui est à peu près n'importe quoi de nos jours).

Vous devez au moins définir le ActivityId une fois pour chaque opération logique afin de corréler.

Start / Stop et LogicalOperationStack peuvent ensuite être utilisés pour un contexte basé sur une pile simple. Pour les contextes plus complexes (par exemple les opérations asynchrones), l'utilisation de TraceTransfer vers le nouvel ActivityId (avant de le modifier), permet la corrélation.

L'outil Service Trace Viewer peut être utile pour afficher les graphiques d'activité (même si vous n'utilisez pas WCF).

Q: Ecrivez-vous ce code manuellement ou utilisez-vous une forme de programmation orientée aspect pour le faire? Vous souhaitez partager un extrait de code?

R: Vous souhaiterez peut-être créer une classe d'étendue, par exemple LogicalOperationScope, qui (a) configure le contexte lors de sa création et (b) réinitialise le contexte lorsqu'il est supprimé.

Cela vous permet d'écrire du code tel que le suivant pour encapsuler automatiquement les opérations:

  using( LogicalOperationScope operation = new LogicalOperationScope("Operation") )
  {
    // .. do work here
  }

Lors de la création, la portée peut d'abord définir ActivityId si nécessaire, appeler StartLogicalOperation, puis enregistrer un message TraceEventType.Start. Sur Dispose, il peut enregistrer un message d'arrêt, puis appeler StopLogicalOperation.

Q: Fournissez-vous une forme de granularité sur les sources de trace? Par exemple, WPF TraceSources vous permet de les configurer à différents niveaux.

R: Oui, plusieurs sources de trace sont utiles / importantes à mesure que les systèmes s'agrandissent.

Bien que vous souhaitiez probablement consigner de manière cohérente tous les messages d'avertissement et ci-dessus, ou tous les messages d'information et ci-dessus, pour tout système de taille raisonnable, le volume de suivi d'activité (démarrage, arrêt, etc.) et de journalisation détaillée devient tout simplement trop.

Plutôt que d'avoir un seul commutateur qui active ou désactive tout, il est utile de pouvoir activer ces informations pour une section de votre système à la fois.

De cette façon, vous pouvez localiser les problèmes importants à partir de la journalisation habituelle (tous les avertissements, erreurs, etc.), puis "zoomer" sur les sections souhaitées et les définir sur le suivi d'activité ou même sur les niveaux de débogage.

Le nombre de sources de trace dont vous avez besoin dépend de votre application, par exemple, vous pouvez vouloir une source de trace par assemblage ou par section principale de votre application.

Si vous avez besoin d'un contrôle encore plus précis, ajoutez des commutateurs booléens individuels pour activer / désactiver le traçage spécifique à haut volume, par exemple les vidages de messages bruts. (Ou une source de trace distincte pourrait être utilisée, similaire à WCF / WPF).

Vous pouvez également envisager des sources de trace distinctes pour la trace d'activité par rapport à la journalisation générale (autre), car cela peut faciliter la configuration des filtres exactement comme vous le souhaitez.

Notez que les messages peuvent toujours être corrélés via ActivityId même si différentes sources sont utilisées, utilisez-en autant que vous en avez besoin.


Les auditeurs

Q: Quelles sorties de journal utilisez-vous?

Cela peut dépendre du type d'application que vous écrivez et des éléments enregistrés. Habituellement, des choses différentes vont à différents endroits (c'est-à-dire plusieurs sorties).

Je classe généralement les sorties en trois groupes:

(1) Événements - Journal des événements Windows (et fichiers de trace)

Par exemple, si vous écrivez un serveur / service, la meilleure pratique sous Windows consiste à utiliser le journal des événements Windows (vous n'avez pas d'interface utilisateur pour faire rapport).

Dans ce cas, tous les événements Fatal, Error, Warning et (service-level) Information doivent être enregistrés dans le journal des événements Windows. Le niveau Information doit être réservé à ce type d'événements de haut niveau, ceux que vous souhaitez afficher dans le journal des événements, par exemple "Service Started", "Service Stopped", "Connected to Xyz", et peut-être même "Schedule Initiated" , "Utilisateur connecté", etc.

Dans certains cas, vous souhaiterez peut-être faire de l'écriture dans le journal des événements une partie intégrée de votre application et non via le système de suivi (c'est-à-dire écrire directement les entrées du journal des événements). Cela signifie qu'il ne peut pas être désactivé accidentellement. (Notez que vous souhaitez également noter le même événement dans votre système de trace afin de pouvoir corréler).

En revanche, une application d'interface graphique Windows les signale généralement à l'utilisateur (bien qu'ils puissent également se connecter au journal des événements Windows).

Les événements peuvent également avoir des compteurs de performances associés (par exemple, nombre d'erreurs / s), et il peut être important de coordonner toute écriture directe dans le journal des événements, les compteurs de performances, l'écriture dans le système de suivi et la notification à l'utilisateur afin qu'ils se produisent à le même temps.

Par exemple, si un utilisateur voit un message d'erreur à un moment donné, vous devriez pouvoir trouver le même message d'erreur dans le journal des événements Windows, puis le même événement avec le même horodatage dans le journal de trace (avec d'autres détails de trace).

(2) Activités - Fichiers journaux d'application ou table de base de données (et fichiers de trace)

Il s'agit de l'activité régulière d'un système, par exemple la page Web servie, le marché boursier déposé, la prise de commande, le calcul effectué, etc.

Le suivi d'activité (démarrage, arrêt, etc.) est utile ici (à la bonne granularité).

En outre, il est très courant d'utiliser un journal d'application spécifique (parfois appelé journal d'audit). Il s'agit généralement d'une table de base de données ou d'un fichier journal d'application et contenant des données structurées (c'est-à-dire un ensemble de champs).

Les choses peuvent devenir un peu floues selon votre application. Un bon exemple pourrait être un serveur Web qui écrit chaque demande dans un journal Web; des exemples similaires peuvent être un système de messagerie ou un système de calcul où chaque opération est enregistrée avec des détails spécifiques à l'application.

Un exemple pas si bon est les transactions boursières ou un système d'ordres de vente. Dans ces systèmes, vous enregistrez probablement déjà l'activité car ils ont une valeur commerciale importante, mais le principe de la corrélation avec d'autres actions est toujours important.

En plus des journaux d'applications personnalisés, les activités ont souvent des compteurs de performances associés, par exemple le nombre de transactions par seconde.

En général, vous devez coordonner la journalisation des activités sur différents systèmes, c'est-à-dire écrire dans le journal de votre application en même temps que vous augmentez votre compteur de performances et connectez-vous à votre système de trace. Si vous faites tout en même temps (ou directement les uns après les autres dans le code), les problèmes de débogage sont plus faciles (que s'ils se produisent tous à des moments / emplacements différents dans le code).

(3) Debug Trace - Fichier texte, ou peut-être XML ou base de données.

Il s'agit d'informations au niveau détaillé et inférieur (par exemple, des commutateurs booléens personnalisés pour activer / désactiver les vidages de données brutes). Cela fournit les tripes ou les détails de ce qu'un système fait au niveau d'une sous-activité.

Il s'agit du niveau que vous souhaitez pouvoir activer / désactiver pour des sections individuelles de votre application (d'où les multiples sources). Vous ne voulez pas que ces trucs encombrent le journal des événements Windows. Parfois, une base de données est utilisée, mais il est plus probable que des fichiers journaux roulants soient purgés après un certain temps.

Une grande différence entre ces informations et un fichier journal d'application est qu'il n'est pas structuré. Alors qu'un journal d'application peut avoir des champs pour À, De, Montant, etc., les traces de débogage détaillées peuvent être tout ce qu'un programmeur insère, par exemple "vérifier les valeurs X = {valeur}, Y = faux", ou des commentaires / marqueurs aléatoires comme " Fait, réessayant ".

Une pratique importante consiste à vous assurer que les éléments que vous placez dans les fichiers journaux des applications ou le journal des événements Windows sont également enregistrés dans le système de suivi avec les mêmes détails (par exemple, l'horodatage). Cela vous permet ensuite de corréler les différents journaux lors de l'enquête.

Si vous prévoyez d'utiliser une visionneuse de journaux particulière parce que vous avez une corrélation complexe, par exemple la visionneuse de trace de service, vous devez utiliser un format approprié, c'est-à-dire XML. Sinon, un simple fichier texte est généralement assez bon - aux niveaux inférieurs, les informations sont en grande partie non structurées, vous pouvez donc trouver des vidages de tableaux, des vidages de pile, etc. Pourvu que vous puissiez établir une corrélation avec des journaux plus structurés à des niveaux supérieurs, les choses devraient ça va.

Q: Si vous utilisez des fichiers, utilisez-vous des journaux de roulement ou un seul fichier? Comment mettez-vous les journaux à la disposition des utilisateurs?

R: Pour les fichiers, vous voulez généralement rouler les fichiers journaux du point de vue de la gestion (avec System.Diagnostics, utilisez simplement VisualBasic.Logging.FileLogTraceListener).

La disponibilité dépend à nouveau du système. Si vous ne parlez que de fichiers, alors pour un serveur / service, les fichiers déroulants ne sont accessibles que lorsque cela est nécessaire. (Le journal des événements Windows ou les journaux d'application de base de données auraient leurs propres mécanismes d'accès).

Si vous n'avez pas facilement accès au système de fichiers, le suivi du débogage vers une base de données peut être plus facile. [c'est-à-dire implémenter une base de données TraceListener].

Une solution intéressante que j'ai vue pour une application Windows GUI était qu'elle enregistrait des informations de traçage très détaillées sur un "enregistreur de vol" lors de son exécution, puis lorsque vous la fermiez si elle n'avait aucun problème, elle supprimait simplement le fichier.

Si toutefois il tombait en panne ou rencontrait un problème, le fichier n'était pas supprimé. Soit s'il détecte l'erreur, soit la prochaine fois qu'il s'exécute, il remarquera le fichier, puis il peut prendre des mesures, par exemple le compresser (par exemple 7zip) et l'envoyer par e-mail ou autrement le rendre disponible.

De nos jours, de nombreux systèmes intègrent le signalement automatisé des pannes à un serveur central (après vérification auprès des utilisateurs, par exemple pour des raisons de confidentialité).


Visualisation

Q: Quels outils utilisez-vous pour afficher les journaux?

R: Si vous avez plusieurs journaux pour différentes raisons, vous utiliserez plusieurs visualiseurs.

Notepad / vi / Notepad ++ ou tout autre éditeur de texte est la base des journaux de texte brut.

Si vous avez des opérations complexes, par exemple des activités avec des transferts, vous utiliserez évidemment un outil spécialisé comme le Service Trace Viewer. (Mais si vous n'en avez pas besoin, un éditeur de texte est plus facile).

Comme je connecte généralement des informations de haut niveau au journal des événements de Windows, cela fournit un moyen rapide d'obtenir une vue d'ensemble, de manière structurée (recherchez les jolies icônes d'erreur / d'avertissement). Vous n'avez besoin de commencer à rechercher des fichiers texte que s'il n'y en a pas assez dans le journal, bien qu'au moins le journal vous donne un point de départ. (À ce stade, il est utile de vous assurer que vos journaux ont des entrées coordonnées).

Généralement, le journal des événements Windows met également ces événements importants à la disposition d'outils de surveillance tels que MOM ou OpenView.

Autres --

Si vous vous connectez à une base de données, il peut être facile de filtrer et de trier les informations (par exemple, zoomer sur un ID d'activité particulier. (Avec les fichiers texte, vous pouvez utiliser Grep / PowerShell ou similaire pour filtrer le GUID particulier que vous souhaitez)

MS Excel (ou un autre tableur). Cela peut être utile pour analyser des informations structurées ou semi-structurées si vous pouvez les importer avec les bons délimiteurs afin que différentes valeurs se retrouvent dans différentes colonnes.

Lors de l'exécution d'un service en débogage / test, je l'héberge généralement dans une application console pour plus de simplicité. Je trouve un enregistreur de console coloré utile (par exemple rouge pour les erreurs, jaune pour les avertissements, etc.). Vous devez implémenter un écouteur de trace personnalisé.

Notez que le cadre n'inclut pas un enregistreur de console coloré ou un enregistreur de base de données, donc pour le moment, vous devrez les écrire si vous en avez besoin (ce n'est pas trop difficile).

Cela m'énerve vraiment que plusieurs cadres (log4net, EntLib, etc.) aient perdu du temps à réinventer la roue et à réimplémenter la journalisation, le filtrage et la journalisation de base dans des fichiers texte, le journal des événements Windows et des fichiers XML, chacun dans leur propre manière différente (les instructions de journal sont différentes dans chacun); chacun a ensuite implémenté sa propre version, par exemple, d'un enregistreur de base de données, alors que la plupart de ceux-ci existaient déjà et qu'il ne fallait plus que quelques écouteurs de trace pour System.Diagnostics. Parlez d'un gros gaspillage d'efforts en double.

Q: Si vous créez une solution ASP.NET, utilisez-vous également ASP.NET Health Monitoring? Incluez-vous la sortie de trace dans les événements du moniteur d'intégrité? Qu'en est-il de Trace.axd?

Ces choses peuvent être activées / désactivées au besoin. Je trouve Trace.axd très utile pour déboguer la façon dont un serveur répond à certaines choses, mais il n'est généralement pas utile dans un environnement très utilisé ou pour un suivi à long terme.

Q: Qu'en est-il des compteurs de performances personnalisés?

Pour une application professionnelle, en particulier un serveur / service, je m'attends à le voir entièrement instrumenté avec les deux compteurs de l'Analyseur de performances et la connexion au journal des événements Windows. Ce sont les outils standard de Windows et doivent être utilisés.

Vous devez vous assurer d'inclure les programmes d'installation pour les compteurs de performances et les journaux d'événements que vous utilisez; ceux-ci doivent être créés au moment de l'installation (lors de l'installation en tant qu'administrateur). Lorsque votre application s'exécute normalement, elle ne devrait pas avoir besoin de privilèges d'administration (et ne pourra donc pas créer de journaux manquants).

C'est une bonne raison de pratiquer le développement en tant que non-administrateur (ayez un compte administrateur séparé pour quand vous devez installer des services, etc.). Si vous écrivez dans le journal des événements, .NET créera automatiquement un journal manquant la première fois que vous y écrivez; si vous vous développez en tant que non-administrateur, vous attraperez cela tôt et éviterez une mauvaise surprise lorsqu'un client installe votre système et ne peut pas l'utiliser car il ne fonctionne pas en tant qu'administrateur.


FYI: J'ai rencontré un problème où la trace de Microsoft dans un fichier se bloque. Si plusieurs processus (ou threads) écrivent dans le même fichier et qu'ils entrent en collision, vous obtenez une erreur de verrouillage d'accès exclusif au système de fichiers sur le fichier journal.
Jay

1
L'infrastructure System.Diagnostics est thread-safe; le comportement par défaut consiste à verrouiller la structure, mais vous pouvez remplacer TraceListener.IsThreadSafe si vous fournissez votre propre verrouillage. Voir msdn.microsoft.com/en-us/library/… . Pour plusieurs processus, vous devez normalement écrire dans des fichiers séparés, mais notez que le Service Trace Viewer peut charger plusieurs fichiers de trace (par exemple à partir de plusieurs machines) et les corréler via ActivityId.
Sly Gryphon

1
Peut-être pouvez-vous suggérer comment utiliser TraceEvent () pour consigner les exceptions?
Dmitriy Sosunov

1
N'est-ce pas l'un des principaux inconvénients System.Diagnostics.Tracedont il est décoré, [Conditional("TRACE")]ce qui le rend inutilisable dans les environnements de production, où vous avez rarement du code compilé avec le TRACEdrapeau?
Asbjørn Ulsberg

2
@asbjornu La configuration de build Release par défaut dans Visual Studio a défini TRACE (c'est DEBUG qui est désactivé pour les builds Release); si vous construisez à partir de la ligne de commande, vous devez cependant l'activer.
Sly Gryphon

40

Je dois rejoindre le chorus recommandant log4net, dans mon cas, venant du point de vue de la flexibilité de la plateforme (desktop .Net / Compact Framework, 32/64 bits).

Cependant, l'envelopper dans une API de marque privée est un anti-modèle majeur . log4net.ILoggerest déjà l'équivalent .Net de l' API wrapper Commons Logging , donc le couplage est déjà minimisé pour vous, et puisqu'il s'agit également d'une bibliothèque Apache, ce n'est généralement même pas un problème car vous n'abandonnez aucun contrôle: bifurquez-le si vous doit.

La plupart des bibliothèques de wrapper maison que j'ai vues commettent également une ou plusieurs litanies de défauts:

  1. L'utilisation d'un enregistreur global singleton (ou de manière équivalente un point d'entrée statique) qui perd la résolution fine du modèle d'enregistrement par classe recommandé pour aucun autre gain de sélectivité.
  2. Ne pas exposer l' Exceptionargument facultatif , conduisant à plusieurs problèmes:
    • Cela rend une politique de journalisation des exceptions encore plus difficile à maintenir, donc rien n'est fait de manière cohérente avec les exceptions.
    • Même avec une stratégie cohérente, le formatage de l'exception dans une chaîne perd les données prématurément. J'ai écrit un ILayoutdécorateur personnalisé qui effectue une analyse détaillée d'une exception pour déterminer la chaîne d'événements.
  3. Ne pas exposer les propriétésIsLevelEnabled , ce qui annule la possibilité d'ignorer le code de mise en forme lorsque les zones ou les niveaux de journalisation sont désactivés.

1
J'ai été chargé de refactoriser un (horrible) wrapper interne autour de log4j en quelque chose d'un peu moins horrible (c'est encore assez mauvais, mais c'est le résultat du caillage de chaussures les exigences qui m'ont été données dans log4j). J'ai essayé d'éliminer le point d'entrée statique global, mais j'ai été abattu. Je ne comprends vraiment pas le point. Dans notre configuration, log4j est si fortement étendu et tordu qu'il n'est vraiment utilisé que comme répartiteur d'événements; nous ne l'utilisons que parce que quelqu'un a demandé "comment pouvons-nous utiliser log4j pour cela?" Soit directement log4, soit écrivez votre propre framework. La route du milieu est douloureuse.
Adam Jaskiewicz

25
Je ne suis pas d'accord avec votre recommandation de ne pas envelopper log4net. L'encapsuler avec une API de modèle de fournisseur léger permet aux utilisateurs de vos bibliothèques de classes de brancher leur infrastructure de journalisation préférée. YMMV bien sûr, mais le décrire comme un "anti-pattern majeur" est un peu dogmatique. De plus, le fait qu'il existe des bibliothèques de wrappers avec "une litanie de défauts" n'est pas un bon argument contre un wrapper bien écrit.
Joe

1
Appeler quelque chose un anti-motif ne signifie pas que c'est toujours une mauvaise idée à 100% - juste que cela crée une tendance à vous peindre dans un coin si vous ne faites pas attention. De plus, ILog / LogManager est lui-même une mini-bibliothèque d'encapsuleur bien écrite à l'image de la journalisation des biens communs qui est regroupée dans l'assembly log4net, mais il n'y a aucune raison pour qu'elle ne puisse pas être extraite et transformée en une journalisation des biens communs appropriée pour CLR.
Jeffrey Hantin

18

Je ne développe pas souvent dans asp.net, mais en ce qui concerne les enregistreurs, je pense que beaucoup de meilleures pratiques sont universelles. Voici quelques-unes de mes réflexions aléatoires sur la journalisation que j'ai apprises au fil des ans:

Cadres

  • Utilisez un cadre d'abstraction de l'enregistreur - comme slf4j (ou lancez le vôtre), afin de découpler l'implémentation de l'enregistreur de votre API. J'ai vu un certain nombre de cadres d'enregistreurs aller et venir et vous feriez mieux d'en adopter un nouveau sans trop de tracas.
  • Essayez de trouver un cadre qui prend en charge une variété de formats de sortie.
  • Essayez de trouver un cadre qui prend en charge les plugins / filtres personnalisés.
  • Utilisez un cadre qui peut être configuré par des fichiers externes, de sorte que vos clients / consommateurs puissent modifier facilement la sortie du journal afin qu'elle puisse être lue facilement par les applications commerciales de gestion des journaux.
  • Assurez-vous de ne pas aller trop loin dans les niveaux de journalisation personnalisés, sinon vous ne pourrez peut-être pas passer à différents cadres de journalisation.

Sortie de l'enregistreur

  • Essayez d'éviter les journaux de style XML / RSS pour la journalisation qui pourraient rencontrer des échecs catastrophiques. Ceci est important car si l'interrupteur d'alimentation est éteint sans que votre enregistreur n'écrive la </xxx>balise de fermeture , votre journal est cassé.
  • Consigner les threads. Sinon, il peut être très difficile de suivre le déroulement de votre programme.
  • Si vous devez internationaliser vos journaux, vous souhaiterez peut-être qu'un développeur se connecte uniquement en anglais (ou dans la langue de votre choix).
  • Parfois, avoir la possibilité d'insérer des instructions de journalisation dans les requêtes SQL peut être une bouée de sauvetage dans les situations de débogage. Tel que:
    - Classe appelante: com.foocorp.foopackage.FooClass: 9021
    SELECT * FROM foo;
  • Vous souhaitez une journalisation au niveau de la classe. Normalement, vous ne voulez pas non plus d'instances statiques d'enregistreurs - cela ne vaut pas la micro-optimisation.
  • Le marquage et la catégorisation des exceptions enregistrées sont parfois utiles car toutes les exceptions ne sont pas créées égales. Il est donc utile de connaître un sous-ensemble d'exceptions importantes dans un laps de temps, si vous avez un moniteur de journal qui doit envoyer des notifications sur les états critiques.
  • Les filtres de duplication sauveront votre vue et votre disque dur. Voulez-vous vraiment voir la même instruction de journalisation répétée 10 ^ 10000000 fois? Ne serait-il pas préférable de recevoir un message comme: This is my logging statement - Repeated 100 times

Voir aussi ma question .


5
les filtres de duplication sont une excellente idée
Paul Stovell

J'étais d'accord sur le problème des balises cassées, mais la plupart des bons rédacteurs XML n'utilisent pas le XML complet de toute façon (c'est-à-dire, aucun élément racine) afin qu'ils puissent se connecter sans charger le DOM XML. dans le cas inhabituel, un problème survient à partir d'une entrée partiellement écrite, vous pouvez le corriger manuellement
Paul Stovell

Je fais des allers-retours sur la journalisation XML depuis des années. Maintenant, cela me semble excessif. Si j'avais besoin d'un flux RSS de l'état d'une application, je pense qu'il est mieux implémenté avec un utilitaire de surveillance des journaux.
Elijah

Je suis d'accord sur RSS. Je pense plus aux outils de visualisation qui vous permettent de mieux comprendre l'entrée. avec les fichiers texte, vous souhaitez généralement conserver une entrée sur une seule ligne; mais parfois vous voulez inclure des traces de pile ou des objets sérialisés. c'est là qu'un journal XML (tel qu'utilisé par WCF) est utile
Paul Stovell

+1 pour avoir mentionné l'instrumentation des requêtes SQL. Ceci est en effet très utile pour la corrélation des traces de base de données et des traces d'application. Je le fais manuellement dans mon DAL, mais je me demande quel type de support d'outil existe-t-il pour cette technique?
Constantin

17

Je ne suis pas qualifié pour commenter la connexion pour .Net, car mon pain et mon beurre sont Java, mais nous avons eu une migration dans notre journalisation au cours des 8 dernières années, vous trouverez peut-être une analogie utile à votre question.

Nous avons commencé avec un enregistreur Singleton qui était utilisé par chaque thread de la machine virtuelle Java, et avons défini le niveau de journalisation pour l'ensemble du processus. Cela a entraîné d'énormes journaux si nous devions déboguer même une partie très spécifique du système, donc la leçon numéro un est de segmenter votre journalisation.

Notre incarnation actuelle de l'enregistreur autorise plusieurs instances, l'une étant définie par défaut. Nous pouvons instancier n'importe quel nombre d'enregistreurs enfants ayant différents niveaux de journalisation, mais l'aspect le plus utile de cette architecture est la possibilité de créer des enregistreurs pour des packages et des classes individuels en changeant simplement les propriétés de journalisation. La deuxième leçon est de créer un système flexible qui permet de remplacer son comportement sans changer le code.

Nous utilisons la bibliothèque Apache commons-logging enroulée autour de Log4J.

J'espère que cela t'aides!

* Éditer *

Après avoir lu le post de Jeffrey Hantin ci-dessous, j'ai réalisé que j'aurais dû noter ce qu'est devenu notre wrapper de journalisation interne. C'est maintenant essentiellement une usine et est strictement utilisé pour obtenir un enregistreur de travail en utilisant le fichier de propriétés correct (qui, pour des raisons héritées, n'a pas été déplacé à la position par défaut). Comme vous pouvez maintenant spécifier le fichier de configuration de la journalisation sur la ligne de commande, je soupçonne qu'il deviendra encore plus léger et si vous démarrez une nouvelle application, je suis définitivement d'accord avec sa déclaration selon laquelle vous ne devriez même pas vous embêter à emballer l'enregistreur.


Merci d'avoir répondu. créez-vous les enregistreurs enfants manuellement en code (c.-à-d. sont-ils codés en dur) ou par une sorte de chose automatique / implicite?
Paul Stovell

Non ... si nous ajoutons une configuration de journalisation aux fichiers logging.properties pour un package ou une classe, ils seront enregistrés selon cette configuration, mais tout package ou classe non spécifiquement configuré sera enregistré aux niveaux par défaut.
Steve Moyer

9

Nous utilisons Log4Net au travail en tant que fournisseur de journalisation, avec un wrapper singleton pour l'instance de journal (bien que le singleton soit en cours d'examen, se demandant s'il s'agit d'une bonne idée ou non).

Nous l'avons choisi pour les raisons suivantes:

  • Configuration / reconfiguration simple sur divers environnements
  • Bon nombre d'ajouts préconstruits
  • L'un des CMS que nous utilisons avait déjà intégré
  • Bon nombre de niveaux de journaux et de configurations autour d'eux

Je dois mentionner que cela parle d'un point de vue de développement ASP.NET

Je peux voir quelques avantages à utiliser la trace qui est dans le framework .NET mais je ne suis pas entièrement vendu dessus, principalement parce que les composants avec lesquels je travaille ne font pas vraiment d'appels Trace. La seule chose que j'utilise fréquemment, c'est System.Net.Mailce que je peux dire.

Nous avons donc une bibliothèque qui encapsule log4net et dans notre code, nous avons juste besoin de choses comme ceci:

Logger.Instance.Warn("Something to warn about");
Logger.Instance.Fatal("Something went bad!", new Exception());

try {
  var i = int.Parse("Hello World");
} catch(FormatException, ex) {
  Logger.Instance.Error(ex);
}

Dans les méthodes, nous vérifions si le niveau de journalisation est activé, donc vous n'avez pas d'appels redondants à l'API log4net (donc si le débogage n'est pas activé, les instructions de débogage sont ignorées), mais quand j'obtiens un peu de temps Je vais le mettre à jour pour les exposer afin que vous puissiez faire les vérifications vous-même. Cela empêchera les évaluations d'être entreprises alors qu'elles ne devraient pas l'être, par exemple:

Logger.Instance.Debug(string.Format("Something to debug at {0}", DateTime.Now);

Cela deviendra:

if(Logger.DebugEnabled) Logger.Instance.Debug(string.Format("Something to debug at {0}", DateTime.Now);

(Économisez un peu de temps d'exécution)

Par défaut, nous nous connectons à deux endroits:

  1. Système de fichiers du site Web (dans une extension de fichier non desservie)
  2. Envoi d'email pour erreur et fatal

Les fichiers se font en roulement de chaque jour ou 10mb (IIRC). Nous n'utilisons pas le journal des événements car il peut nécessiter une sécurité plus élevée que nous voulons souvent donner à un site.

Je trouve que le Bloc-notes fonctionne très bien pour lire les journaux.


Les frameworks de journalisation sont l'un des rares cas où le singleton n'est pas une mauvaise utilisation.
mmcdole

Cela peut être le cas si vous souhaitez fournir un contexte autour de votre enregistreur. Mais cela aide à faire face à la concurrence
Aaron Powell

7
J'arracherais certainement le singleton. Vous pouvez certainement avoir une seule instance qui est transmise (de préférence dans le conteneur IOC / DI). J'essaierais également de déplacer la connexion dans un intercepteur ....
yfeldblum

2
Pas un fan de l'instance unique non plus. Je préfère donner à chaque classe un enregistreur au nom unique, donc il est facile de tourner la journalisation vers le haut ou vers le bas par module.
Jeffrey Hantin

8

Quels cadres utilisez-vous?

Nous utilisons un mélange du bloc d'application de journalisation et d'un assistant de journalisation personnalisé qui fonctionne autour des bits du framework .Net. Le LAB est configuré pour générer des fichiers journaux assez volumineux, notamment des fichiers de trace généraux séparés pour l'entrée / sortie de la méthode de service et des fichiers d'erreur spécifiques pour les problèmes inattendus. La configuration inclut la date / heure, le thread, le pId etc. pour l'assistance de débogage ainsi que le détail complet de l'exception et la pile (dans le cas d'une exception inattendue).

L'assistant de journalisation personnalisé utilise la trace.Corrélation et est particulièrement pratique dans le contexte de la journalisation dans WF. Par exemple, nous avons une machine à états qui appelle une série de workflows séquentiels. À chacune de ces activités d'appel, nous enregistrons le début (à l'aide de StartLogicalOperation), puis à la fin, nous arrêtons l'opération logique avec un gestionnaire d'événements de retour gereric.

Cela s'est avéré utile à plusieurs reprises lors de la tentative de débogage des échecs dans des séquences métier complexes, car cela nous permet de déterminer plus rapidement des éléments tels que les décisions de branche If / Else, etc. en fonction de la séquence d'exécution de l'activité.

Quelles sorties de journal utilisez-vous?

Nous utilisons des fichiers texte et des fichiers XML. Les fichiers texte sont configurés via le bloc d'application, mais nous avons également des sorties XML de notre service WF. Cela nous permet de capturer les événements d'exécution (persistance, etc.) ainsi que les exceptions de type métier génériques. Les fichiers texte sont des journaux qui sont roulés par jour et par taille (je pense que la taille totale de 1 Mo est un point de survol).

Quels outils utilisez-vous pour afficher les journaux?

Nous utilisons Notepad et WCF Service Trace Viewer en fonction du groupe de sortie que nous examinons. Le WCF Service Trace Viewer est vraiment très pratique si vous avez correctement configuré votre sortie et peut rendre la lecture de la sortie beaucoup plus simple. Cela dit, si je sais à peu près où est l'erreur - lire un fichier texte bien annoté est également bon.

Les journaux sont envoyés vers un répertoire unique qui est ensuite divisé en sous-répertoires en fonction du service source. Le répertoire racine est exposé via un site Web dont l'accès est contrôlé par un groupe d'utilisateurs de support. Cela nous permet de jeter un œil aux journaux de production sans avoir à soumettre de demandes et à passer par de longs processus de paperasserie pour les données de production.


6

En tant qu'auteurs de l'outil, nous utilisons bien sûr SmartInspect pour la journalisation et le traçage des applications .NET. Nous utilisons généralement le protocole de canal nommé pour la journalisation en direct et les fichiers journaux binaires (chiffrés) pour les journaux de l'utilisateur final. Nous utilisons la console SmartInspect comme outil de visualisation et de surveillance.

Il existe en fait un certain nombre de cadres de journalisation et d'outils pour .NET. Il y a un aperçu et une comparaison des différents outils sur DotNetLogging.com .


5

Il y a beaucoup de bonnes recommandations dans les réponses.

Une meilleure pratique générale consiste à déterminer qui lira le journal. Dans mon cas, ce sera un administrateur sur le site client. J'enregistre donc des messages qui leur donnent quelque chose sur quoi ils peuvent agir. Par exemple, "Impossible d'initialiser l'application. Cela est généralement dû à ......"


1

Nous utilisons log4net sur nos applications Web.

Sa capacité à personnaliser la journalisation au moment de l'exécution en modifiant le fichier de configuration XML est très pratique lorsqu'une application fonctionne mal au moment de l'exécution et que vous devez voir plus d'informations.

Il vous permet également de cibler des classes ou des attributs spécifiques pour vous connecter. C'est très pratique lorsque vous avez une idée de l'endroit où l'erreur se produit. Un exemple classique est NHibernate où vous voulez voir uniquement le SQL aller à la base de données.

Éditer:

Nous écrivons tous les événements dans une base de données et le système Trace. Le journal des événements que nous utilisons pour les erreurs ou les exceptions. Nous enregistrons la plupart des événements dans une base de données afin de pouvoir créer des rapports personnalisés et permettre aux utilisateurs d'afficher le journal s'ils le souhaitent directement depuis l'application.


Pouvez-vous fournir plus de détails sur la façon dont vous l'utilisez? Vous connectez-vous à un fichier ou au journal des événements? S'agit-il d'un fichier journal tournant? Que faites-vous pour le sécuriser ou le sauvegarder? Je suis intéressé par une utilisation réelle.
Paul Stovell

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.