71 votes

Comment utiliser trace et dbg en Erlang pour déboguer et tracer mon programme ?

J'essaie de commencer à utiliser erlang:trace/3 y el dbg pour suivre le comportement d'un système de production en direct sans mettre le serveur hors service.

El documentation es opaque (c'est le moins qu'on puisse dire) et il ne semble pas y avoir de didacticiels utiles en ligne.

Ce que j'ai passé toute la journée à essayer de faire, c'est de capturer ce qui se passait dans une fonction particulière en essayant d'appliquer une trace à Module:Function en utilisant dbg:c y dbg:p mais sans aucun succès.

Quelqu'un a-t-il une explication succincte de l'utilisation de trace dans un système Erlang actif ?

0 votes

102voto

Zed Points 27408

Les étapes de base du traçage des appels de fonction se font sur un nœud non vivant :

> dbg:start().   % start dbg
> dbg:tracer().  % start a simple tracer process
> dbg:tp(Module, Function, Arity, []).   % specify MFA you are interested in
> dbg:p(all, c).   % trace calls (c) of that MFA for all processes.

... trace here

> dbg:stop_clear().   % stop tracer and clear effect of tp and p calls.

Vous pouvez tracer pour plusieurs fonctions en même temps. Ajoutez des fonctions en appelant tp pour chaque fonction. Si vous souhaitez effectuer un suivi pour les fonctions non exportées, vous devez appeler tpl . Pour supprimer des fonctions, appelez ctp o ctpl de manière similaire. Certains appels généraux de tp sont :

> dbg:tpl(Module, '_', []).  % all calls in Module
> dbg:tpl(Module, Function, '_', []).   % all calls to Module:Function with any arity.
> dbg:tpl(Module, Function, Arity, []). % all calls to Module:Function/Arity.
> dbg:tpl(M, F, A, [{'_', [], [{return_trace}]}]).   % same as before, but also show return value.

Le dernier argument est une spécification de correspondance. Vous pouvez jouer avec cela en utilisant dbg:fun2ms .

Vous pouvez sélectionner les processus à suivre avec l'appel à p(). Les éléments sont décrits sous erlang:trace. Certains appels sont :

> dbg:p(all, c).   % trace calls to selected functions by all functions
> dbg:p(new, c).   % trace calls by processes spawned from now on
> dbg:p(Pid, c).   % trace calls by given process
> dbg:p(Pid, [c, m]).  % trace calls and messages of a given process

Je suppose que vous n'aurez jamais besoin d'appeler directement erlang:trace comme dbg fait à peu près tout pour vous.

Une règle d'or pour un nœud vivant est de ne générer qu'une quantité limitée de sortie de trace vers le shell, ce qui vous permet de taper dans dbg:stop_clear(). . :)

J'utilise souvent un traceur qui s'arrête automatiquement après un certain nombre d'événements. Par exemple :

dbg:tracer(process, {fun (_,100) -> dbg:stop_clear();
                        (Msg, N) -> io:format("~p~n", [Msg]), N+1 end, 0
                    }).

Si vous cherchez à déboguer sur des nœuds distants (ou plusieurs nœuds), recherchez pan , eper , inviso o onviso .

2 votes

Je n'ai pas réussi à obtenir de trace pour envoyer tout ce qui est à la coquille jusqu'à présent :(

0 votes

Vous dites que ce sont les étapes de base sur un nœud non vivant... sans doute parce que sur un nœud vivant, vous vous retrouveriez dans une bagarre avec le shell (et vous perdriez) ?

1 votes

Le traçage exige certaines ressources du système. Si vous tracez des événements fréquents, vous risquez de compromettre vos performances. Dans le pire des cas, vous perdez le contact et tout explose.

26voto

cdlf Points 378

Sur les systèmes réels, nous traçons rarement vers le shell. Si le système est bien configuré, il collecte déjà les journaux Erlang qui ont été imprimés sur le shell. Je n'ai pas besoin d'insister sur la raison pour laquelle ceci est crucial dans tout nœud vivant...

Permettez-moi d'élaborer sur le traçage des fichiers :

Il est possible d'effectuer un suivi vers un fichier, ce qui produira une sortie binaire qui pourra être convertie et analysée ultérieurement. (pour une analyse ultérieure ou un système de contrôle automatisé, etc.)

Un exemple pourrait être :

  • Trace à plusieurs fichiers enveloppés (12x50 Mbytes). Veuillez toujours vérifier l'espace disque disponible avant d'utiliser une trace aussi importante !

    dbg:tracer(port,dbg:trace_port(file,{"/log/trace",wrap,atom_to_list(node()),50000000,12})).

    dbg:p(all,[call,timestamp,return_to]).

    • Toujours tester sur un nœud de test avant d'entrer quoi que ce soit dans le shell d'un nœud vivant !
    • Il est conseillé d'avoir un nœud de test ou un nœud de réplique pour essayer les scripts.

Cela dit, examinons une séquence de commandes de traçage de base :

<1> dbg:stop_clear().

  • Commencez toujours par vider les ports de suivi et assurez-vous qu'aucun suivi précédent n'interfère avec le suivi actuel.

<2> dbg:tracer().

  • Démarrer le processus de traçage.

<3> dbg:p(all,[call, timestamp]).

  • Dans ce cas, nous effectuons un traçage pour tous les processus et pour les appels de fonction.

<4> dbg:tp( ... ).

  • Comme on le voit dans la réponse de Zed.

<5> dbg:tpl( ... ).

  • Comme on le voit dans la réponse de Zed.

<42> dbg:stop_clear().

  • Là encore, il s'agit de s'assurer que toutes les traces ont été écrites sur la sortie et d'éviter tout désagrément ultérieur.

Vous pouvez :

  • Ajoutez des déclencheurs en définissant des fun()-s dans le shell pour arrêter la trace à un moment ou un événement donné. Les fun()-s récursifs sont le meilleur moyen d'y parvenir, mais soyez très prudent lorsque vous les appliquez.

  • appliquer une grande variété de filtrage pour s'assurer que vous ne tracez que le processus spécifique avec l'appel de fonction spécifique avec le type d'arguments spécifique...

J'ai eu un problème il y a quelque temps, lorsque nous devions vérifier le contenu d'une table ETS et qu'à l'apparition d'une certaine entrée nous devions arrêter la trace dans les 2-3 minutes.

Je suggère également le livre Erlang Programming écrit par Francesco Cesarini. ( Programmation Erlang @ Amazon )

10voto

Le module 'dbg' est un module de bas niveau. Il y a deux astuces que j'utilise très fréquemment pour les tâches dont j'ai couramment besoin.

  1. Utilisez le code d'extension Erlang CLI/shell à l'adresse http://www.snookles.com/erlang/user_default.erl . Il a été écrit à l'origine (pour autant que je sache) par Serge Aleynikov. a été un exemple utile de "c'est ainsi que j'ajoute des fonctions personnalisées au shell". Compilez le module et éditez votre fichier ~/.erlang pour qu'il pointe vers son chemin (voir le commentaire en haut du fichier). du fichier).

  2. Utilisez le bouton " redbug "qui est fourni avec le logiciel EPER collection d'utilitaires. Il est très facile d'utiliser 'dbg' pour créer des millions de traces en quelques secondes. Faire dans un environnement de production peut s'avérer désastreux. Pour une utilisation en développement ou en production, redbug rend presque impossible l'arrêt d'un système en fonctionnement à cause d'une surcharge induite par les traces.

9voto

Andy Till Points 1619

Si vous préférez un traceur graphique, essayez alors erlyberly . Il vous permet de sélectionner les fonctions que vous souhaitez tracer (sur tous les processus pour le moment) et traite de l'API dbg.

Cependant, il ne protège pas contre la surcharge et ne convient donc pas aux systèmes de production.

enter image description here

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X