Question

Comme Jeff Atwood a demandé:"Quelle est votre philosophie en matière de journalisation ?Tout le code devrait-il être jonché de .logthis() et .logthat() appels?Ou injectez-vous la journalisation après coup d'une manière ou d'une autre ? »

Était-ce utile?

La solution

Ma philosophie de journalisation se résume assez facilement en quatre parties :

Audit ou journalisation de la logique métier

Enregistrez les éléments qui doivent être enregistrés.Cela provient des exigences de l'application et peut inclure la journalisation de chaque modification apportée à une base de données (comme dans de nombreuses applications financières) ou la journalisation des accès aux données (comme cela peut être requis dans le secteur de la santé pour respecter les réglementations du secteur).

Comme cela fait partie des exigences du programme, nombreux sont ceux qui ne l'incluent pas dans leurs discussions générales sur l'exploitation forestière. Toutefois, il existe des chevauchements dans ces domaines et, pour certaines applications, il est utile de considérer toutes les activités d'exploitation forestière ensemble.

Journalisation du programme

Messages qui aideront les développeurs à tester et à déboguer l'application, et à suivre plus facilement le flux de données et la logique du programme pour comprendre où les erreurs de mise en œuvre, d'intégration et autres peuvent exister.

En général, cette journalisation est activée et désactivée selon les besoins des sessions de débogage.

Journalisation des performances

Ajoutez une journalisation ultérieure si nécessaire pour rechercher et résoudre les goulots d'étranglement des performances et d'autres problèmes de programme qui ne provoquent pas l'échec du programme, mais conduiront à un meilleur fonctionnement.Chevauche la journalisation du programme en cas de fuites de mémoire et de certaines erreurs non critiques.

Journalisation de sécurité

Enregistrement des actions des utilisateurs et des interactions avec des systèmes externes où la sécurité est une préoccupation.Utile pour déterminer comment un attaquant a brisé un système après une attaque, mais peut également se connecter à un système de détection d'intrusion pour détecter des attaques nouvelles ou en cours.

Autres conseils

Je travaille avec des systèmes en temps réel critiques pour la sécurité et la journalisation est souvent le seul moyen de détecter des bugs rares qui n'apparaissent que tous les 53 mardis à la pleine lune, si vous comprenez ce que je veux dire.Cela vous rend obsédé par le sujet, alors je m'excuse maintenant si je commence à écumer.

Je conçois des systèmes capables de consigner à peu près tout, mais je n'active pas tout par défaut.Les informations de débogage sont envoyées à une boîte de dialogue de débogage cachée qui les horodatage et les affiche dans une zone de liste (limitée à environ 500 lignes avant suppression), et la boîte de dialogue me permet de l'arrêter, de l'enregistrer automatiquement dans un fichier journal ou de la détourner vers un débogueur attaché tel que DBWin32.Ce détournement me permet de voir la sortie de débogage de plusieurs applications, toutes soigneusement sérialisées, ce qui peut parfois me sauver la vie.Les fichiers journaux sont automatiquement purgés tous les N jours.je utilisé pour utiliser des niveaux de journalisation numériques (plus vous définissez le niveau élevé, plus vous capturez) :

  • désactivé
  • erreurs uniquement
  • basique
  • détaillé
  • tout

mais c'est trop rigide - à mesure que vous progressez vers un bug, il est beaucoup plus efficace de pouvoir vous concentrer sur la connexion exactement sur ce dont vous avez besoin sans avoir à parcourir des tonnes de détritus, et il peut s'agir d'un type particulier de transaction ou d'opération. cela provoque l'erreur.Si cela vous oblige à tout allumer, vous ne faites que rendre votre travail plus difficile.Vous avez besoin de quelque chose de plus fin.

Alors maintenant, je suis en train de passer à la journalisation basée sur un système de drapeaux.Tout ce qui est enregistré a un indicateur détaillant de quel type d'opération il s'agit, et il y a un ensemble de cases à cocher me permettant de définir ce qui est enregistré.Généralement, cette liste ressemble à ceci :

#define DEBUG_ERROR          1
#define DEBUG_BASIC          2
#define DEBUG_DETAIL         4
#define DEBUG_MSG_BASIC      8
#define DEBUG_MSG_POLL       16
#define DEBUG_MSG_STATUS     32
#define DEBUG_METRICS        64
#define DEBUG_EXCEPTION      128
#define DEBUG_STATE_CHANGE   256
#define DEBUG_DB_READ        512
#define DEBUG_DB_WRITE       1024
#define DEBUG_SQL_TEXT       2048
#define DEBUG_MSG_CONTENTS   4096

Ce système de journalisation est livré avec la version finale, activé et enregistré dans un fichier par défaut.Il est trop tard pour savoir que vous auriez dû vous connecter APRÈS que le bug se soit produit, si ce bug ne se produit qu'une fois tous les six mois en moyenne et que vous n'avez aucun moyen de le reproduire.

Le logiciel est généralement livré avec ERROR, BASIC, STATE_CHANGE et EXCEPTION activés, mais cela peut être modifié sur le terrain via la boîte de dialogue de débogage (ou un paramètre de registre/ini/cfg, où ces éléments sont enregistrés).

Oh et une chose : mon système de débogage génère un fichier par jour.Vos exigences peuvent être différentes.Mais assurez-vous que votre code de débogage démarre chaque fichier avec la date, la version du code que vous exécutez et, si possible, un marqueur pour l'identifiant client, l'emplacement du système ou autre.Vous pouvez obtenir un mélange de fichiers journaux provenant du terrain, et vous avez besoin d'un enregistrement de ce qui vient d'où et quelle version du système ils utilisaient, qui se trouve en fait dans les données elles-mêmes, et vous ne pouvez pas faire confiance au client. /ingénieur de terrain pour vous dire quelle version ils ont - ils peuvent simplement vous dire quelle version ils pensent avoir.Pire encore, ils peuvent signaler la version exe présente sur le disque, mais l'ancienne version est toujours en cours d'exécution car ils ont oublié de redémarrer après le remplacement.Demandez à votre code de vous le dire.

C'est mon cerveau vidé...

Je pense toujours, toujours, toujours ajouter la journalisation en cas d'exception, y compris le message et la trace complète de la pile.Au-delà de cela, je pense que c'est assez subjectif de savoir si vous utilisez souvent ou non les journaux...

J'essaie souvent d'ajouter la journalisation uniquement dans des endroits critiques où ce que j'enregistre devrait très rarement arriver, sinon vous rencontrez le problème comme il l'a mentionné des journaux qui deviennent beaucoup trop gros...c'est pourquoi la journalisation des cas d'erreur est la chose idéale à toujours enregistrer (et c'est formidable de pouvoir voir quand ces cas d'erreur sont réellement rencontrés afin que vous puissiez inspecter le problème plus en détail).

D'autres bonnes choses à enregistrer sont que si vous avez des assertions et que vos assertions échouent, enregistrez-les...par exemple, cette requête doit contenir moins de 10 résultats, si elle est plus grande, il peut y avoir un problème, alors enregistrez-la.Bien sûr, si une instruction de journalisation finit par remplir les journaux, c'est probablement une indication soit de la mettre à une sorte de niveau de "débogage", soit d'ajuster ou de supprimer l'instruction de journalisation.Si les journaux deviennent trop gros, vous finirez souvent par les ignorer.

J'adopte ce que je considère comme une approche traditionnelle ;une certaine journalisation, entourée de définitions conditionnelles.Pour les versions de production, je désactive les définitions.

Je choisis de me connecter délibérément au fur et à mesure, car cela signifie que les données du journal sont significatives :

  • En fonction du cadre de journalisation, vous pouvez ajouter des informations de niveau/gravité/catégorie afin que les données du journal puissent être filtrées.
  • Vous pouvez vous assurer que le bon niveau d’information est présent, ni trop, ni trop peu.
  • Vous savez lors de l'écriture du code quelles sont les choses les plus importantes et pouvez donc vous assurer qu'elles sont enregistrées

L’utilisation d’une forme d’injection de code, d’outil de profilage ou de traçage pour générer des journaux générerait très probablement des journaux verbeux et moins utiles dans lesquels il serait plus difficile de se plonger.Ils peuvent cependant être utiles comme aide au débogage.

Je commence par affirmer beaucoup de conditions dans mon code (en C#, en utilisant System.Diagnostics.Assert), mais j'ajoute la journalisation uniquement là où je trouve, lors du débogage ou de la mise sous tension du système, que j'ai vraiment besoin d'un moyen de suivre ce qui se passe dans mon code sans avoir un débogueur connecté en permanence.

Sinon, je préfère utiliser la capacité de Visual Studio pour mettre des traces dans le code en tant que points d'arrêt spéciaux (c'est-à-direvous insérez un point d'arrêt et faites un clic droit dessus, puis sélectionnez "Quand frappé..." et dites-lui quoi afficher dans ce cas).Il n'est pas nécessaire de recompiler et il est facile d'activer/désactiver les traces à la volée.

Si vous écrivez un programme qui sera utilisé par de nombreuses personnes, il est préférable d'avoir une sorte de mécanisme permettant de choisir ce qui sera enregistré et ce qui ne le sera pas.Un argument en faveur des fonctions .logthis() est qu'elles peuvent constituer un excellent remplacement pour les commentaires en ligne dans certains cas (si elles sont effectuées correctement).

De plus, cela vous aide à déterminer EXACTEMENT où une erreur se produit.

Enregistrez-les tous et laissez Grep les trier.

Je suis d'accord avec Adam, mais j'envisagerais également d'enregistrer des choses intéressantes ou des choses que vous pouvez démontrer comme des réalisations comme une sorte de preuve de leur réalisation.

Je définis une variété de niveaux et passe dans un paramètre avec la configuration/invocation.

Si vous avez vraiment besoin de vous connecter à votre système, vos tests sont nuls ou à tout le moins incomplets et pas très approfondis.Tout dans votre système doit être autant que possible une boîte noire.Remarquez comment les classes de base comme String n'ont pas besoin de journalisation - la principale raison étant qu'elles sont très bien testées et fonctionnent comme détaillé.Pas de surprises.

J'utilise la journalisation pour affiner les problèmes qui ne se reproduisent pas dans nos tests unitaires et encore moins en répétant les mêmes étapes fournies par l'utilisateur :ces rares problèmes qui n'apparaissent que sur du matériel très distant (et parfois, bien que très rarement, même causés par un problème de pilote ou de bibliothèque tierce hors de notre contrôle).

Je suis d'accord avec le commentaire selon lequel tout cela devrait être pris en compte par notre procédure de test, mais il est difficile de trouver plus d'un million de bases de code LOC qui exigent un code de très bas niveau et critique en termes de performances pour répondre à ces exigences.Je ne travaille pas dans des logiciels critiques, mais je travaille dans l'industrie graphique où nous devons souvent tout faire, de la mise en œuvre d'allocateurs de mémoire à l'utilisation du code GPU pour SIMD.

Même avec un code très modulaire, faiblement couplé ou même complètement découplé, les interactions du système peuvent conduire à des entrées et sorties très complexes avec un comportement variant selon les plates-formes où nous avons parfois ce cas de pointe non fiable qui échappe à nos tests.Les boîtes noires modulaires peuvent être très simples, mais les interactions entre elles peuvent devenir très complexes et conduire à des cas extrêmes occasionnels et imprévus.

À titre d'exemple de cas où la journalisation m'a sauvé les fesses, une fois, j'ai eu cet étrange utilisateur avec un prototype de machine Intel qui tombait en panne.Nous avons répertorié la configuration minimale requise pour les machines devant prendre en charge SSE 4, mais cette machine particulière répondait à ces exigences minimales et ne prenait toujours pas en charge les extensions Streaming SIMD au-delà de SSE 3, bien qu'elle soit une machine à 16 cœurs.Le découvrir rapidement a été rendu possible en consultant son journal de bord qui indiquait précisément le numéro de ligne où les instructions SSE 4 étaient utilisées.Aucun membre de notre équipe n'a pu reproduire le problème, encore moins un seul autre utilisateur ayant participé à la vérification du rapport.Idéalement, nous aurions dû écrire du code pour les anciennes versions de SIMD ou au moins effectuer quelques branchements et vérifications pour nous assurer que le matériel prend en charge les exigences minimales, mais nous voulions faire une hypothèse ferme communiquée à travers les exigences matérielles minimales pour des raisons de simplicité et d'économie.Ici, on peut peut-être soutenir que c'est la configuration minimale requise qui a posé problème.

Compte tenu de la façon dont j'utilise la journalisation ici, nous avons tendance à obtenir des journaux assez volumineux.Cependant, l'objectif n'est pas la lisibilité : ce qui est généralement important, c'est la dernière ligne d'un journal envoyé avec un rapport lorsque l'utilisateur subit un crash quelconque qu'aucun de nous dans l'équipe (et encore moins quelques autres utilisateurs dans le monde). peut se reproduire.

Néanmoins, une astuce que j'utilise régulièrement pour éviter le spam excessif des journaux est qu'il est souvent raisonnable de supposer qu'un morceau de code qui s'exécute une fois avec succès le fera également par la suite (ce n'est pas une garantie ferme, mais souvent une hypothèse raisonnable).J'emploie donc souvent un log_once type de fonction pour les fonctions granulaires afin d'éviter les frais généraux liés au coût de la journalisation à chaque fois qu'elle est appelée.

Je ne saupoudre pas les sorties de journaux partout (je pourrais le faire si j'avais le temps).En général, je les réserve le plus aux zones qui semblent les plus dangereuses :code appelant des shaders GLSL, par ex.(Les fournisseurs de GPU varient énormément ici en termes de capacités et même de manière de compiler le code), code utilisant les intrinsèques SIMD, code de très bas niveau, code qui doit inévitablement s'appuyer sur un comportement spécifique au système d'exploitation, code de bas niveau faisant des hypothèses sur le représentation des POD (ex :code qui suppose 8 bits par octet) - le genre de cas où nous saupoudrerions également de nombreuses assertions et contrôles d'intégrité et écrivions le plus grand nombre de tests unitaires.En règle générale, cela suffit, et la journalisation m'a sauvé les fesses à plusieurs reprises, alors que j'aurais autrement résolu un problème non reproductible et que j'aurais dû tenter de résoudre le problème à l'aveugle, ce qui a nécessité de nombreuses itérations pour tenter de trouver une solution au seul utilisateur au monde qui pourrait reproduire le problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top