Dev Life
Présentation d’un débogueur multiplateforme pour Go
Nous utilisons Go pour une grande partie de notre développement de serveurs ici chez Mailgun, et c’est génial. Cependant, venant de Python, il y a une chose qui m’a vraiment manqué :
Je pouvais insérer cette petite ligne chaque fois que je ne comprenais pas ce qui se passait dans le code pour voir exactement ce qu’il en était. Mais avec Go ? Pas vraiment. Lorsque j’ai commencé ce projet en janvier, gdb a échoué sur tous les programmes sur lesquels je l’ai essayé. delve ne fonctionnait pas sous OS X, et le débogage avec print était trop lent et limité. Que faire dans ce cas ?
Créer mon propre débogueur, bien sûr.
godebug
La seule chose qui s’oppose [à un bon débogueur Go] est l’écriture de beaucoup de code de bas niveau non portable communiquant avec des interfaces non documentées et boguées.
godebug est un autre type de débogueur. Les débogueurs traditionnels pour les langages compilés utilisent des appels système de bas niveau et lisent des fichiers binaires pour rechercher des symboles de débogage. Ils sont difficiles à configurer correctement et difficiles à porter.
godebug adopte une approche différente : il prend le code source d’un programme cible, insère du code de débogage entre chaque ligne, puis le compile et l’exécute à la place. Le résultat est un débogueur entièrement fonctionnel et extrêmement portable. En fait, grâce à gopherjs, vous pouvez l’exécuter directement ici dans votre navigateur !
Vous pouvez modifier le programme et le relancer avec le bouton « DEBUG IT ! » autant de fois que vous le souhaitez.
Voici un schéma rapide de la démo ci-dessus :
Le code d’origine est transformé deux fois. Tout d’abord, godebug insère l’instrumentation de débogage. Ensuite, gopherjs compile le résultat en JavaScript.
Examinons l’étape d’instrumentation. (Pour en savoir plus sur la partie gopherjs (qui est géniale), consultez son site web.) Voici quelques-uns des appels que godebug insère :
godebug.EnterFuncindique à la bibliothèque d’exécution de godebug que nous entrons dans une fonction. Puisque la commande « next » ne s’arrête pas à l’intérieur des appels de fonction, la bibliothèque d’exécution prend note de ces appels pour savoir quand ignorer des lignes.godebug.ExitFuncindique à la bibliothèque d’exécution que nous quittons une fonction. Omis dansmain.godebug.Linemet le programme en pause et attend une saisie si, et seulement si, une commande utilisateur ou un point d’arrêt le lui a demandé. Lorsqu’il est en pause, il demande une saisie et répond à toutes les commandes.godebug.Declareenregistre la correspondance entre les noms des variables et leurs valeurs. Cette correspondance est utilisée par la commande print.
Il s’agit d’un aperçu abrégé. Il y a d’autres fonctions que godebug insère, et de nombreux détails concernant les fonctions ci-dessus ont été omis. Mais ce sont les éléments de base du fonctionnement de godebug.
Utiliser godebug
Tout ce qui précède (moins la partie serveur et JavaScript) est regroupé dans l’outil de ligne de commande godebug. Voici comment l’utiliser :
Étape 1. Installation
$ go get -u github.com/mailgun/godebug
Étape 2. Définir des points d’arrêt
Ajoutez ce marqueur partout où vous souhaitez un point d’arrêt :
_ = "breakpoint"
Cette instruction devient un point d’arrêt lorsqu’elle est exécutée sous godebug, et n’a aucun effet sinon.
Puisque les points d’arrêt font partie du code source, vous pouvez les entourer de votre propre logique. Disons que vous exécutez un test piloté par un tableau avec des dizaines de cas, et que l’un d’eux échoue : celui qui a testé l’entrée \"weird string\". Vous pouvez ajouter ce point d’arrêt à votre test :
for _, tt := range myTestCases { if tt.in == "weird string" { _ = "breakpoint" } ... }
godebug test mettra le programme en pause à l’instruction du marqueur, idéalement placée juste avant l’exécution du cas de test qui échoue.
Étape 3. Exécuter votre programme
Utilisez la commande godebug run :
godebug run
Ou, pour les tests, utilisez la commande godebug test :
godebug test
Par défaut, godebug n’ajoutera l’instrumentation de débogage qu’au package main (pour godebug run) ou au package en cours de test (pour godebug test). Il n’instrumentera aucun package importé. Cela permet de réduire la charge du débogueur : tous les packages qui ne vous intéressent pas s’exécuteront normalement, à pleine vitesse.
Cela signifie que par défaut, vous ne pouvez pas entrer dans les appels de fonction depuis des packages importés. Mais il vous arrivera parfois d’en avoir besoin ! Pour déboguer d’autres packages, passez l’indicateur -instrument à godebug run ou godebug test :
godebug test -instrument=pkgA,pkgB,pkgC pkg/under/test
La commande ci-dessus instrumentera (et vous permettra ainsi d’entrer dans) pkgA, pkgB, pkgC et pkg/under/test. Elle compilera et exécutera ensuite les tests pour pkg/under/test. Une logique similaire s’applique pour godebug run.
À vous d’essayer !
La prochaine fois que vous voudrez comprendre ce qui se passe dans un programme Go, essayez godebug. Gardez à l’esprit qu’il s’agit encore d’un outil récent qui a besoin d’être perfectionné. Plus particulièrement, certaines de ses limitations connues sont les suivantes :
- impact sur les performances
- peut causer des conflits de lecture si votre programme lit depuis stdin
- impossibilité de s’attacher à un processus en cours d’exécution
- obligation de connaître les packages que vous souhaitez déboguer avant de démarrer la session
Cela dit, je suis ravi de cet outil et j’espère qu’il apportera beaucoup de valeur à la communauté Go. Essayez-le et dites-moi ce que vous en pensez ! Si vous rencontrez des problèmes, n’hésitez pas à m’en faire part. Signalez un problème sur https://github.com/mailgun/godebug/issues ou envoyez un email à : dev@godebug.rocks
En espérant qu’il vous plaise !
https://github.com/mailgun/godebug
Vous souhaitez en savoir plus sur godebug ? Voici une présentation que j’ai donnée à GoSF, abordant plus en détail la génération de code et la gestion de la concurrence :
Comment cela a-t-il fonctionné ?