Ich habe Java-Hintergrund und ich liebe es, das Signal QUIT zu verwenden, um den Java-Thread-Dump zu überprüfen.
Wie kann Golang alle Goroutinen-Stapelspuren ausdrucken lassen?
Ich habe Java-Hintergrund und ich liebe es, das Signal QUIT zu verwenden, um den Java-Thread-Dump zu überprüfen.
Wie kann Golang alle Goroutinen-Stapelspuren ausdrucken lassen?
Antworten:
Verwenden Sie from, um den Stack-Trace für die aktuelle Goroutine zu drucken .PrintStack()
runtime/debug
PrintStack druckt den von Stack zurückgegebenen Stack-Trace als Standardfehler.
Beispielsweise:
import(
"runtime/debug"
)
...
debug.PrintStack()
Um den Stack-Trace für alle Goroutinen zu drucken, verwenden Sie Lookup
und WriteTo
von 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.
Jedes Profil hat einen eindeutigen Namen. Einige Profile sind vordefiniert:
goroutine - Stack-Traces aller aktuellen Goroutines-
Heaps - eine Stichprobe aller Heap-Zuordnungen
threadcreate - Stack-Traces, die zur Erstellung neuer
Block- OS-Threads führten - Stack-Traces, die zum Blockieren von Synchronisationsprimitiven führten
Beispielsweise:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
. "Stack gibt eine formatierte Stack-Ablaufverfolgung der Goroutine zurück, die sie aufruft. Für jede Routine enthält sie die Quellzeileninformationen und den PC-Wert und versucht dann, für Go-Funktionen die aufrufende Funktion oder Methode und den Text der Zeile zu ermitteln, die die enthält Aufruf."
Für das runtime/pprof
in der Antwort von Intermernet erwähnte Paket gibt es ein HTTP-Frontend . Importieren Sie das Paket net / http / pprof , um einen HTTP-Handler zu registrieren für /debug/pprof
:
import _ "net/http/pprof"
import _ "net/http"
Starten Sie einen HTTP-Listener, falls Sie noch keinen haben:
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
Zeigen Sie dann mit einem Browser auf http://localhost:6060/debug/pprof
ein Menü oder http://localhost:6060/debug/pprof/goroutine?debug=2
einen vollständigen Goroutine-Stack-Dump.
Es gibt noch andere lustige Dinge, die Sie auf diese Weise über Ihren laufenden Code lernen können. Beispiele und weitere Details finden Sie im Blog-Beitrag: http://blog.golang.org/profiling-go-programs
So ahmen Sie das Java-Verhalten von Stack-Dump auf SIGQUIT nach, lassen das Programm jedoch weiterhin laufen:
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])
}
}()
Ähnlich wie bei Java kann SIGQUIT verwendet werden, um einen Stack-Trace eines Go-Programms und seiner Goroutinen zu drucken.
Ein wesentlicher Unterschied besteht jedoch darin, dass das Senden von SIGQUIT an Java-Programme diese standardmäßig nicht beendet, während Go-Programme beendet werden.
Dieser Ansatz erfordert keine Codeänderung, um eine Stapelverfolgung aller Goroutinen vorhandener Programme zu drucken.
Die Umgebungsvariable GOTRACEBACK ( siehe Dokumentation des Laufzeitpakets ) steuert die Menge der generierten Ausgabe. Um beispielsweise alle Goroutinen einzuschließen, setzen Sie GOTRACEBACK = all.
Das Drucken des Stack-Trace wird durch eine unerwartete Laufzeitbedingung (nicht behandeltes Signal) ausgelöst, die ursprünglich in diesem Commit dokumentiert wurde und seit mindestens Go 1.1 verfügbar ist.
Wenn das Ändern des Quellcodes eine Option ist, lesen Sie alternativ andere Antworten.
Beachten Sie, dass in einem Linux-Terminal SIGQUIT bequem mit der Tastenkombination Ctrl+ gesendet werden kann \.
Sie können runtime.Stack verwenden , um den Stack-Trace aller Goroutinen abzurufen:
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
Aus der Dokumentation:
func Stack(buf []byte, all bool) int
Stack formatiert einen Stack-Trace der aufrufenden Goroutine in buf und gibt die Anzahl der in buf geschriebenen Bytes zurück. Wenn alles wahr ist, stapeln die Stapelformate die Spuren aller anderen Goroutinen nach der Spur für die aktuelle Goroutine in Buf.
string(buf)
hier, fmt.Printf("%s", buf)
und fmt.Printf("%s", string(buf))
tut genau dasselbe (siehe Dokumentation für fmt
Paket); Der einzige Unterschied besteht darin, dass die string
Version die Bytes von buf
unnötig
Drücken Sie STRG + \
(Wenn Sie es in einem Terminal ausführen und nur Ihr Programm beenden und die Go-Routinen usw. sichern möchten)
Ich fand diese Frage auf der Suche nach der Tastenfolge. Ich wollte nur schnell und einfach feststellen, ob mein Programm undicht ist.
Auf * NIX-Systemen (einschließlich OSX) wird ein Signalabbruch gesendet SIGABRT
:
pkill -SIGABRT program_name
Es ist erforderlich, die von zurückgegebene Länge runtime.Stack()
zu verwenden, um zu vermeiden, dass nach der Stapelverfolgung ein paar leere Zeilen gedruckt werden. Die folgende Wiederherstellungsfunktion druckt eine gut formatierte Ablaufverfolgung:
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]))
}
Drücken Sie standardmäßig die ^\
Tasten ( STRG + \ ), um die Stapelspuren aller Goroutinen zu sichern.
Andernfalls können Sie für eine genauere Steuerung verwenden panic
. Der einfache Weg ab Go 1.6+ :
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
Führen Sie dann Ihr Programm folgendermaßen aus:
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
Wenn Sie auch drucken möchten, gehen Sie zur Laufzeit Goroutinen:
$ GOTRACEBACK=system go run main.go
Hier sind alle GOTRACEBACK-Optionen:
GOTRACEBACK=none
lässt die Goroutine-Stapelspuren vollständig weg.GOTRACEBACK=single
(Standardeinstellung) verhält sich wie oben beschrieben.GOTRACEBACK=all
Fügt Stapelspuren für alle vom Benutzer erstellten Goroutinen hinzu.GOTRACEBACK=system
ist wie "alle", fügt jedoch Stapelrahmen für Laufzeitfunktionen hinzu und zeigt Goroutinen an, die intern von der Laufzeit erstellt wurden.GOTRACEBACK=crash
ist wie "System", stürzt jedoch betriebssystemspezifisch ab, anstatt zu beenden. Auf Unix-Systemen wird der Absturz beispielsweise ausgelöst SIGABRT
, um einen Core-Dump auszulösen.Die Variable GOTRACEBACK steuert die Ausgabemenge, die generiert wird, wenn ein Go-Programm aufgrund einer nicht wiederhergestellten Panik oder einer unerwarteten Laufzeitbedingung fehlschlägt.
Standardmäßig druckt ein Fehler eine Stapelverfolgung für die aktuelle Goroutine, wobei Funktionen innerhalb des Laufzeitsystems entfernt werden, und wird dann mit dem Exit-Code 2 beendet. Der Fehler druckt Stapelverfolgungen für alle Goroutinen, wenn keine aktuelle Goroutine vorhanden ist oder der Fehler vorliegt intern zur Laufzeit.
Aus historischen Gründen sind die GOTRACEBACK-Einstellungen 0, 1 und 2 Synonyme für none, all bzw. system.
Die SetTraceback-Funktion des Laufzeit- / Debug-Pakets ermöglicht das Erhöhen der Ausgabemenge zur Laufzeit, kann jedoch die Menge nicht unter die von der Umgebungsvariablen angegebene Menge reduzieren. Siehe https://golang.org/pkg/runtime/debug/#SetTraceback .