Comment vider les stacktraces de goroutine?


Réponses:


107

Pour imprimer la trace de pile de la goroutine actuelle , utilisez PrintStack()fromruntime/debug .

PrintStack imprime en erreur standard la trace de pile renvoyée par Stack.

Par exemple:

import(
   "runtime/debug"
)
...    
debug.PrintStack()

Pour imprimer la trace de pile pour toutes les goroutines, utilisez Lookupet à WriteTopartir de runtime/pprof.

func Lookup(name string) *Profile
// Lookup returns the profile with the given name,
// or nil if no such profile exists.

func (p *Profile) WriteTo(w io.Writer, debug int) error
// WriteTo writes a pprof-formatted snapshot of the profile to w.
// If a write to w returns an error, WriteTo returns that error.
// Otherwise, WriteTo returns nil.

Chaque profil a un nom unique. Quelques profils sont prédéfinis:

goroutine - traces de pile de tous les
tas de goroutines actuels - un échantillon de toutes les allocations de tas
threadcreate - traces de pile qui ont conduit à la création d'un nouveau
bloc de threads du système d'exploitation - traces de pile qui ont conduit au blocage des primitives de synchronisation

Par exemple:

pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)

1
Imprime-t-il la trace de toutes les goroutines?

Il devrait, il appelle Stack. "Stack renvoie une trace de pile formatée de la goroutine qui l'appelle. Pour chaque routine, elle inclut les informations de la ligne source et la valeur PC, puis tente de découvrir, pour les fonctions Go, la fonction ou méthode appelante et le texte de la ligne contenant le invocation."
Intermernet

1
Désolé, il imprime uniquement la trace actuelle de la pile de goroutine.

4
@HowardGuo J'ai ajouté un exemple utilisant runtime / pprof pour vider toutes les traces de pile.
Intermernet

1
Je pense que cela ne produit que la goroutine en cours d'exécution de chaque thread, pas toutes les goroutines, ex: play.golang.org/p/0hVB0_LMdm
rogerdpack

41

Il existe une interface HTTP pour le runtime/pprofpaquet mentionné dans la réponse d'Intermernet. Importez le package net / http / pprof pour enregistrer un gestionnaire HTTP pour /debug/pprof:

import _ "net/http/pprof"
import _ "net/http"

Démarrez un écouteur HTTP si vous n'en avez pas déjà:

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

Puis pointez un navigateur vers http://localhost:6060/debug/pprofpour un menu, ou http://localhost:6060/debug/pprof/goroutine?debug=2pour un vidage complet de la pile de goroutine.

Vous pouvez également apprendre d'autres choses amusantes sur votre code en cours d'exécution. Consultez l'article de blog pour des exemples et plus de détails: http://blog.golang.org/profiling-go-programs


je l'ai fait courir par elle ne montre que les goroutines exécutées pour autant que je vois. Est-il possible que je puisse voir toutes les "méthodes" qui sont exécutées après le lancement de main.go?
Lukas Lukac

38

Pour imiter le comportement Java du stack-dump sur SIGQUIT tout en laissant le programme en cours d'exécution:

go func() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGQUIT)
    buf := make([]byte, 1<<20)
    for {
        <-sigs
        stacklen := runtime.Stack(buf, true)
        log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
    }
}()

4
Je pense que c'est ce que l'auteur recherchait vraiment - imite ce que fait Java lorsque vous envoyez un kill -QUIT. Un petit changement que j'ai dû faire était de changer la première ligne de la boucle for () en: "<- sigs". En d'autres termes, supprimez simplement le signal après l'avoir attendu. Les versions récentes de Go ne vous permettront pas de déclarer une variable sans l'utiliser ultérieurement.
George Armhold

@Bryan, êtes-vous prêt à en attribuer une licence sous BSD ou d'autres conditions plus permissives en plus de CC-BY-SA 3.0 requis par StackOverflow?
Charles Duffy

1
@CharlesDuffy vous pouvez trouver à peu près la même chose ici sous licence Apache: github.com/weaveworks/weave/blob/…
Bryan

37

Semblable à Java, SIGQUIT peut être utilisé pour imprimer une trace de pile d'un programme Go et de ses goroutines.
Une différence clé, cependant, est que par défaut l'envoi de SIGQUIT aux programmes Java ne les termine pas, tandis que les programmes Go se terminent.

Cette approche ne nécessite aucun changement de code pour imprimer une trace de pile de toutes les goroutines des programmes existants.

La variable d'environnement GOTRACEBACK ( voir la documentation du package d'exécution ) contrôle la quantité de sortie générée. Par exemple, pour inclure toutes les goroutines, définissez GOTRACEBACK = all.

L'impression de la trace de la pile est déclenchée par une condition d'exécution inattendue (signal non géré), documentée à l'origine dans ce commit , la rendant disponible depuis au moins Go 1.1.


Sinon, si la modification du code source est une option, voir les autres réponses.


Notez que dans un terminal Linux, SIGQUIT peut être envoyé avec la combinaison de touches Ctrl+ \.


5
En parcourant la documentation, je n'ai trouvé aucune mention de SIGQUIT, plutôt de SIGABRT. D'après mes propres tests (avec go 1.7), ce dernier a également fonctionné sur le premier.
soltysh

4
cela devrait être la meilleure réponse.
Steven Soroka

La documentation fait référence à «lorsqu'un programme Go échoue en raison d'une panique non récupérée ou d'une condition d'exécution inattendue». Un signal non capturé (SIGQUIT, etc.) est l'un de ces derniers. Pourquoi ai-je mentionné SIGQUIT? Parce que l'OP exprime son amour pour l'utilisation de SIGQUIT avec Java, et cette réponse met l'accent sur la similitude. Reformuler la réponse pour la rendre plus claire.
Rodolfo Carvalho le

26

Vous pouvez utiliser runtime.Stack pour obtenir la trace de la pile de toutes les goroutines:

buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)

De la documentation:

func Stack(buf []byte, all bool) int

Stack formate une trace de pile de la goroutine appelante en buf et renvoie le nombre d'octets écrits dans buf. Si tout est vrai, Stack formate les traces de toutes les autres goroutines dans buf après la trace de la goroutine actuelle.


Cela inclut les traces de toutes les goroutines, c'est bien!
rogerdpack

Est-ce le format qu'une panique non récupérée se résume à utiliser?
Ztyx

2
N'oubliez pas d'ajouter une chaîne (buf) ou vous y imprimerez les octets bruts.
koda

2
Peut-être que je fais quelque chose de mal, ou peut-être que la fonctionnalité a changé, mais cela ne récupère rien pour moi sauf une tranche d'octets vide?
17xande

1
@koda il n'y a pas besoin de faire string(buf)ici, fmt.Printf("%s", buf)et de fmt.Printf("%s", string(buf))faire exactement la même chose (voir la documentation pour le fmtpaquet); la seule différence ici est que la stringversion copiera les octets bufinutilement
kbolino

20

Appuyez sur CTRL + \

(Si vous l'exécutez dans un terminal et que vous voulez simplement tuer votre programme et vider les routines go, etc.)

J'ai trouvé cette question à la recherche de la séquence clé. Je voulais juste un moyen rapide et facile de savoir si mon programme fuit des routines go :)


11

Sur les systèmes * NIX (y compris OSX), envoyez un signal d'abandon SIGABRT:

pkill -SIGABRT program_name


Apparemment, envoyer SIGQUIT à un processus Java ne le termine pas comme SIGABRT le fera.
Dave C

J'ai trouvé que c'était la solution la plus simple et la plus adaptée à la question initiale. Souvent, vous avez besoin d'un stacktrace tout de suite, sans changer votre code.
jotrocken

5

Il est nécessaire d'utiliser la longueur renvoyée par runtime.Stack()pour éviter d'imprimer un tas de lignes vides après votre trace de pile. La fonction de récupération suivante imprime une trace joliment formatée:

if r := recover(); r != nil {
    log.Printf("Internal error: %v", r))
    buf := make([]byte, 1<<16)
    stackSize := runtime.Stack(buf, true)
    log.Printf("%s\n", string(buf[0:stackSize]))
}

Il n'y a pas runtime.Trace; runtime.Stack a déjà été mentionné il y a un an et demi .
Dave C

Je n'ai jamais vu ça; sur quelle plateforme utilisez-vous?
Bryan

Qu'est-ce que tu n'as pas vu? Le code doit fonctionner sur toutes les plates-formes; Je l'ai testé sur Windows 7, Ubuntu 14.04 et Mac.
David Tootill

Jamais vu de lignes vides.
Bryan

4

Par défaut, appuyez sur les ^\touches ( CTRL + \ ) pour vider les traces de pile de toutes les goroutines.


Sinon, pour un contrôle plus granulaire, vous pouvez utiliser panic. Le moyen simple à partir de Go 1.6+ :

go func() {
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGQUIT)
    <-s
    panic("give me the stack")
}()

Ensuite, exécutez votre programme comme ceci:

# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go

Si vous souhaitez également imprimer des goroutines d'exécution go:

$ GOTRACEBACK=system go run main.go

Voici toutes les options de GOTRACEBACK:

  • GOTRACEBACK=none omet complètement les traces de la pile de goroutine.
  • GOTRACEBACK=single (le défaut) se comporte comme décrit ci-dessus.
  • GOTRACEBACK=all ajoute des traces de pile pour toutes les goroutines créées par l'utilisateur.
  • GOTRACEBACK=system est comme `` tout '' mais ajoute des cadres de pile pour les fonctions d'exécution et affiche les goroutines créées en interne par l'exécution.
  • GOTRACEBACK=crashest comme `` système '' mais se bloque d'une manière spécifique au système d'exploitation au lieu de quitter. Par exemple, sur les systèmes Unix, le crash SIGABRTse déclenche pour déclencher un vidage de mémoire.

Voici la documentation

La variable GOTRACEBACK contrôle la quantité de sortie générée lorsqu'un programme Go échoue en raison d'une panique non récupérée ou d'une condition d'exécution inattendue.

Par défaut, un échec imprime une trace de pile pour la goroutine actuelle, supprimant les fonctions internes au système d'exécution, puis se termine avec le code de sortie 2. L'échec imprime les traces de pile pour toutes les goroutines s'il n'y a pas de goroutine en cours ou si l'échec est interne au runtime.

Pour des raisons historiques, les paramètres GOTRACEBACK 0, 1 et 2 sont respectivement des synonymes de none, all et system.

La fonction SetTraceback du package d'exécution / débogage permet d'augmenter la quantité de sortie au moment de l'exécution, mais elle ne peut pas réduire la quantité en dessous de celle spécifiée par la variable d'environnement. Voir https://golang.org/pkg/runtime/debug/#SetTraceback .

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.