Saya memiliki latar belakang Java, dan saya suka menggunakan sinyal QUIT untuk memeriksa dump thread Java.
Bagaimana cara membiarkan Golang mencetak semua jejak tumpukan goroutine?
Saya memiliki latar belakang Java, dan saya suka menggunakan sinyal QUIT untuk memeriksa dump thread Java.
Bagaimana cara membiarkan Golang mencetak semua jejak tumpukan goroutine?
Jawaban:
Untuk mencetak jejak tumpukan untuk goroutine saat ini , gunakan PrintStack()fromruntime/debug .
PrintStack mencetak ke kesalahan standar jejak tumpukan yang dikembalikan oleh Stack.
Sebagai contoh:
import(
"runtime/debug"
)
...
debug.PrintStack()
Untuk mencetak jejak tumpukan untuk semua penggunaan Lookupdan WriteTodari goroutine 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.
Setiap Profil memiliki nama yang unik. Beberapa profil sudah ditentukan sebelumnya:
goroutine - tumpukan jejak dari semua
tumpukan goroutine saat ini - sebuah contoh dari semua alokasi tumpukan
threadcreate - jejak tumpukan yang mengarah ke pembuatan
blok utas OS baru - jejak tumpukan yang menyebabkan pemblokiran pada sinkronisasi primitif
Sebagai contoh:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack. "Stack mengembalikan pelacakan tumpukan yang diformat dari goroutine yang memanggilnya. Untuk setiap rutinitas, ini menyertakan informasi baris sumber dan nilai PC, kemudian mencoba menemukan, untuk fungsi Go, fungsi atau metode pemanggil dan teks dari baris yang berisi doa."
Ada frontend HTTP untuk runtime/pprofpaket yang disebutkan dalam jawaban Intermernet. Impor paket net / http / pprof untuk mendaftarkan penangan HTTP untuk /debug/pprof:
import _ "net/http/pprof"
import _ "net/http"
Mulai pendengar HTTP jika Anda belum memilikinya:
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
Kemudian arahkan browser ke http://localhost:6060/debug/pprofmenu, atau http://localhost:6060/debug/pprof/goroutine?debug=2untuk tumpukan dump goroutine lengkap.
Ada hal menyenangkan lainnya yang dapat Anda pelajari tentang kode yang sedang berjalan dengan cara ini juga. Lihat entri blog untuk mengetahui contoh dan detail lebih lanjut: http://blog.golang.org/profiling-go-programs
Untuk meniru perilaku Java stack-dump di SIGQUIT tetapi tetap membiarkan program berjalan:
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])
}
}()
Mirip dengan Java, SIGQUIT dapat digunakan untuk mencetak jejak tumpukan program Go dan goroutine-nya.
Perbedaan utama, bagaimanapun, adalah bahwa secara default mengirim SIGQUIT ke program Java tidak menghentikannya, sementara program Go keluar.
Pendekatan ini tidak memerlukan perubahan kode untuk mencetak jejak tumpukan semua goroutine dari program yang ada.
Variabel lingkungan GOTRACEBACK ( lihat dokumentasi paket runtime ) mengontrol jumlah keluaran yang dihasilkan. Misalnya, untuk menyertakan semua goroutine, setel GOTRACEBACK = all.
Pencetakan pelacakan tumpukan dipicu oleh kondisi waktu proses yang tidak terduga (sinyal tidak tertangani), yang awalnya didokumentasikan dalam pengubahan ini , membuatnya tersedia setidaknya sejak Go 1.1.
Atau, jika memodifikasi kode sumber adalah sebuah pilihan, lihat jawaban lain.
Perhatikan bahwa di terminal Linux, SIGQUIT dapat dengan mudah dikirim dengan kombinasi tombol Ctrl+ \.
Anda bisa menggunakan runtime.Stack untuk mendapatkan pelacakan tumpukan semua goroutine:
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
Dari dokumentasi:
func Stack(buf []byte, all bool) int
Stack memformat pelacakan tumpukan dari pemanggilan goroutine ke dalam buf dan mengembalikan jumlah byte yang ditulis ke buf. Jika semuanya benar, format Stack menumpuk jejak dari semua goroutine lain ke dalam buf setelah jejak goroutine saat ini.
string(buf)sini, fmt.Printf("%s", buf)dan fmt.Printf("%s", string(buf))melakukan hal yang persis sama (lihat dokumen untuk fmtpaket); satu-satunya perbedaan di sini adalah bahwa stringversi akan menyalin byte dari yang buftidak perlu
Tekan CTRL + \
(Jika Anda menjalankannya di terminal dan hanya ingin mematikan program Anda dan membuang rutinitas go, dll.)
Saya menemukan pertanyaan ini mencari urutan kuncinya. Hanya ingin cara cepat dan mudah untuk mengetahui apakah program saya membocorkan rutinitas go :)
Pada sistem * NIX (termasuk OSX) mengirim sinyal batal SIGABRT:
pkill -SIGABRT program_name
Anda perlu menggunakan panjang yang dikembalikan oleh runtime.Stack()untuk menghindari mencetak banyak garis kosong setelah jejak tumpukan Anda. Fungsi pemulihan berikut mencetak jejak yang diformat dengan baik:
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]))
}
Secara default, tekan ^\tombol ( CTRL + \ ) untuk membuang jejak tumpukan semua goroutine.
Jika tidak, untuk kontrol yang lebih terperinci, Anda dapat menggunakan panic. Cara sederhana mulai Go 1.6+ :
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
Kemudian, jalankan program Anda seperti ini:
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
Jika Anda juga ingin mencetak go runtime goroutine:
$ GOTRACEBACK=system go run main.go
Berikut semua opsi GOTRACEBACK:
GOTRACEBACK=none menghilangkan jejak tumpukan goroutine seluruhnya.GOTRACEBACK=single (default) berperilaku seperti yang dijelaskan di atas.GOTRACEBACK=all menambahkan pelacakan tumpukan untuk semua goroutine buatan pengguna.GOTRACEBACK=system seperti "semua '' tetapi menambahkan frame stack untuk fungsi run-time dan menampilkan goroutine yang dibuat secara internal oleh run-time.GOTRACEBACK=crashseperti `` sistem '' tetapi macet dengan cara khusus sistem operasi alih-alih keluar. Misalnya, pada sistem Unix, crash muncul SIGABRTuntuk memicu dump inti.Variabel GOTRACEBACK mengontrol jumlah output yang dihasilkan saat program Go gagal karena kepanikan yang belum pulih atau kondisi waktu proses yang tidak terduga.
Secara default, kegagalan mencetak pelacakan tumpukan untuk goroutine saat ini, memilih fungsi internal ke sistem run-time, lalu keluar dengan kode keluar 2. Kegagalan mencetak jejak tumpukan untuk semua goroutine jika tidak ada goroutine saat ini atau kegagalannya internal ke run-time.
Untuk alasan historis, setelan GOTRACEBACK 0, 1, dan 2 adalah sinonim untuk masing-masing tidak ada, semua, dan sistem.
Fungsi SetTraceback paket runtime / debug memungkinkan peningkatan jumlah output pada waktu proses, tetapi tidak dapat mengurangi jumlah di bawah yang ditentukan oleh variabel lingkungan. Lihat https://golang.org/pkg/runtime/debug/#SetTraceback .