Mam tło w Javie i uwielbiam używać sygnału QUIT do sprawdzania zrzutu wątku Java.
Jak pozwolić Golangowi wydrukować wszystkie ślady stosu gorutyn?
Mam tło w Javie i uwielbiam używać sygnału QUIT do sprawdzania zrzutu wątku Java.
Jak pozwolić Golangowi wydrukować wszystkie ślady stosu gorutyn?
Odpowiedzi:
Aby wydrukować ślad stosu dla bieżącej gorutyny, użyj PrintStack()
fromruntime/debug
.
PrintStack drukuje ze standardowym błędem ślad stosu zwrócony przez Stack.
Na przykład:
import(
"runtime/debug"
)
...
debug.PrintStack()
Aby wydrukować ślad stosu dla wszystkich gorutyn, użyj Lookup
i WriteTo
od 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.
Każdy profil ma unikalną nazwę. Kilka profili jest wstępnie zdefiniowanych:
goroutine - stos śladów wszystkich bieżących goroutines
heap - próbkowanie wszystkich alokacji sterty
threadcreate - ślady stosu, które doprowadziły do utworzenia nowego
bloku wątków systemu operacyjnego - ślady stosu, które doprowadziły do zablokowania na elementach pierwotnych synchronizacji
Na przykład:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
. „Stos zwraca sformatowany ślad stosu goroutine, który go wywołuje. Dla każdej procedury zawiera informacje o wierszu źródłowym i wartość PC, a następnie próbuje znaleźć dla funkcji Go wywołującą funkcję lub metodę oraz tekst wiersza zawierającego wezwanie."
Istnieje nakładka HTTP dla runtime/pprof
pakietu wymienionego w odpowiedzi Intermernet. Zaimportuj pakiet net / http / pprof , aby zarejestrować procedurę obsługi HTTP dla /debug/pprof
:
import _ "net/http/pprof"
import _ "net/http"
Uruchom odbiornik HTTP, jeśli jeszcze go nie masz:
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
Następnie wskaż w przeglądarce http://localhost:6060/debug/pprof
menu lub http://localhost:6060/debug/pprof/goroutine?debug=2
pełny zrzut stosu goroutine.
W ten sposób możesz również dowiedzieć się innych ciekawych rzeczy o działającym kodzie. Sprawdź post na blogu, aby zapoznać się z przykładami i szczegółami: http://blog.golang.org/profiling-go-programs
Aby naśladować zachowanie Java podczas zrzutu stosu na SIGQUIT, ale nadal pozostawiając uruchomiony program:
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])
}
}()
Podobnie jak w Javie, SIGQUIT może być używany do drukowania śladu stosu programu Go i jego goroutinów.
Kluczową różnicą jest jednak to, że domyślnie wysyłanie SIGQUIT do programów Java nie powoduje ich zakończenia, podczas gdy programy Go kończą działanie.
Takie podejście nie wymaga zmiany kodu, aby wydrukować ślad stosu wszystkich gorutyn istniejących programów.
Zmienna środowiskowa GOTRACEBACK ( zobacz dokumentację pakietu wykonawczego ) kontroluje ilość generowanych danych wyjściowych. Na przykład, aby uwzględnić wszystkie gorutyny, ustaw GOTRACEBACK = all.
Drukowanie śladu stosu jest wyzwalane przez nieoczekiwany warunek wykonawczy (nieobsługiwany sygnał), pierwotnie udokumentowany w tym zatwierdzeniu , udostępniając go co najmniej od wersji Go 1.1.
Alternatywnie, jeśli modyfikacja kodu źródłowego jest opcją, zobacz inne odpowiedzi.
Zwróć uwagę, że w terminalu Linux SIGQUIT można wygodnie wysłać za pomocą kombinacji klawiszy Ctrl+ \.
Możesz użyć runtime.Stack, aby uzyskać ślad stosu wszystkich goroutines:
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
Z dokumentacji:
func Stack(buf []byte, all bool) int
Stack formatuje ślad stosu wywołującego gorutynę do bufora i zwraca liczbę bajtów zapisanych w buforze. Jeśli wszystko jest prawdziwe, Stack formatuje ślady wszystkich innych gorutyn w buforze po śladzie dla bieżącej gorutyny.
string(buf)
tu, fmt.Printf("%s", buf)
i fmt.Printf("%s", string(buf))
robić dokładnie to samo (patrz Dokumentacja dla fmt
pakietu); jedyną różnicą jest to, że string
wersja będzie buf
niepotrzebnie kopiować bajty
Naciśnij CTRL + \
(Jeśli uruchamiasz go w terminalu i chcesz po prostu zabić program i zrzucić procedury go itp.)
Znalazłem to pytanie, szukając sekwencji klawiszy. Chciałem szybko i łatwo sprawdzić, czy mój program przecieka procedury go :)
Konieczne jest użycie długości zwróconej przez, runtime.Stack()
aby uniknąć drukowania kilku pustych wierszy po śladzie stosu. Następująca funkcja odzyskiwania drukuje ładnie sformatowany ślad:
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]))
}
Domyślnie naciśnij ^\
klawisze ( CTRL + \ ), aby zrzucić ślady stosu wszystkich goroutines.
W przeciwnym razie, aby uzyskać bardziej szczegółową kontrolę, możesz użyć panic
. Prosty sposób na Go 1.6+ :
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
Następnie uruchom program w ten sposób:
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
Jeśli chcesz również wydrukować goroutines go runtime:
$ GOTRACEBACK=system go run main.go
Oto wszystkie opcje GOTRACEBACK:
GOTRACEBACK=none
całkowicie pomija ślady stosu goroutine.GOTRACEBACK=single
(domyślnie) zachowuje się jak opisano powyżej.GOTRACEBACK=all
dodaje ślady stosu dla wszystkich goroutines utworzonych przez użytkowników.GOTRACEBACK=system
jest jak `ʻall '', ale dodaje ramki stosu dla funkcji wykonawczych i pokazuje gorutynę utworzone wewnętrznie przez środowisko wykonawcze.GOTRACEBACK=crash
jest jak `` system '', ale ulega awarii w sposób specyficzny dla systemu operacyjnego zamiast kończyć działanie. Na przykład w systemach Unix awaria SIGABRT
pojawia się, aby wywołać zrzut pamięci.Zmienna GOTRACEBACK steruje ilością danych wyjściowych generowanych, gdy program Go zawiedzie z powodu nieodwracalnej paniki lub nieoczekiwanego stanu środowiska wykonawczego.
Domyślnie błąd powoduje wydrukowanie śladu stosu dla bieżącego goroutine, eliminując funkcje wewnętrzne systemu wykonawczego, a następnie kończy pracę z kodem zakończenia 2. Niepowodzenie powoduje wydrukowanie śladów stosu dla wszystkich gorutyn, jeśli nie ma aktualnego gorutyny lub wewnętrzne w czasie wykonywania.
Ze względów historycznych ustawienia GOTRACEBACK 0, 1 i 2 są synonimami odpowiednio: none, all i system.
Funkcja SetTraceback pakietu uruchomieniowego / pakietu debugowania umożliwia zwiększenie ilości danych wyjściowych w czasie wykonywania, ale nie może zmniejszyć ilości poniżej wartości określonej przez zmienną środowiskową. Zobacz https://golang.org/pkg/runtime/debug/#SetTraceback .