Java geçmişim var ve Java iş parçacığı dökümünü incelemek için QUIT sinyalini kullanmayı seviyorum.
Golang'ın tüm gorutinlerin yığın izini yazdırmasına nasıl izin verilir?
Java geçmişim var ve Java iş parçacığı dökümünü incelemek için QUIT sinyalini kullanmayı seviyorum.
Golang'ın tüm gorutinlerin yığın izini yazdırmasına nasıl izin verilir?
Yanıtlar:
Mevcut gorutinin yığın izlemesini yazdırmak için, ' PrintStack()
danruntime/debug
kullanın .
PrintStack, Yığın tarafından döndürülen yığın izini standart hataya yazdırır.
Örneğin:
import(
"runtime/debug"
)
...
debug.PrintStack()
İçin yığın izlemesini yazdırmak için tüm goroutines kullanım Lookup
ve WriteTo
gelen 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.
Her Profilin benzersiz bir adı vardır. Birkaç profil önceden tanımlanmıştır:
goroutine - mevcut
tüm
gorutin yığınlarının yığın izleri - tüm yığın tahsislerinin bir örneklemesi threadcreate - yeni işletim sistemi iş parçacığı
bloğunun oluşturulmasına yol açan yığın izleri - senkronizasyon ilkellerinde engellemeye yol açan yığın izleri
Örneğin:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
. "Yığın, onu çağıran gorutinin biçimlendirilmiş yığın izini döndürür. Her yordam için, kaynak satırı bilgilerini ve PC değerini içerir, ardından Go işlevleri için arama işlevini veya yöntemini ve şunu içeren satırın metnini keşfetmeye çalışır. çağrı. "
runtime/pprof
Intermernet'in cevabında bahsedilen paket için bir HTTP ön ucu var. Aşağıdakiler için bir HTTP işleyicisi kaydetmek için net / http / pprof paketini içe aktarın /debug/pprof
:
import _ "net/http/pprof"
import _ "net/http"
Henüz bir HTTP dinleyiciniz yoksa, bir HTTP dinleyicisi başlatın:
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
Ardından http://localhost:6060/debug/pprof
, bir menü http://localhost:6060/debug/pprof/goroutine?debug=2
için veya tam bir grup yığını dökümü için bir tarayıcıyı işaret edin .
Koşu kodunuz hakkında bu şekilde öğrenebileceğiniz başka eğlenceli şeyler de var. Örnekler ve daha fazla ayrıntı için blog gönderisine bakın: http://blog.golang.org/profiling-go-programs
SIGQUIT'te yığın dökümünün Java davranışını taklit etmek, ancak programı yine de çalışır durumda bırakmak için:
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])
}
}()
Java'ya benzer şekilde, SIGQUIT bir Go programının ve onun gorutinlerinin yığın izini yazdırmak için kullanılabilir.
Bununla birlikte, temel bir fark, varsayılan olarak SIGQUIT'i Java programlarına göndermenin, Go programları çıkarken onları sonlandırmamasıdır.
Bu yaklaşım, mevcut programların tüm programlarının yığın izini yazdırmak için kod değişikliği gerektirmez.
GOTRACEBACK ortam değişkeni ( çalışma zamanı paketinin belgelerine bakın ) üretilen çıktı miktarını kontrol eder. Örneğin, tüm gorutinleri dahil etmek için GOTRACEBACK = all olarak ayarlayın.
Yığın izlemenin yazdırılması, başlangıçta bu işlemde belgelenen beklenmedik bir çalışma zamanı koşulu (işlenmemiş sinyal) tarafından tetiklenir ve en azından Go 1.1'den beri kullanılabilir kılar.
Alternatif olarak, kaynak kodunu değiştirmek bir seçenekse, diğer yanıtlara bakın.
Bir Linux terminalinde SIGQUIT'in Ctrl+ tuş kombinasyonu ile rahatlıkla gönderilebileceğini unutmayın \.
Tüm gorutinlerin yığın izini almak için runtime.Stack'i kullanabilirsiniz :
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
Belgelerden:
func Stack(buf []byte, all bool) int
Yığın, çağıran gorutinin yığın izini buf'ye formatlar ve buf'a yazılan bayt sayısını döndürür. Her şey doğruysa, Stack formatları diğer tüm gorutinlerin izlerini mevcut gorutinin izinden sonra tamponda yığınlar.
string(buf)
burada, fmt.Printf("%s", buf)
ve fmt.Printf("%s", string(buf))
aynı şeyi (Dokümanları görüyorum fmt
pakette); Buradaki tek fark, string
sürümün baytları buf
gereksiz yere kopyalamasıdır
CTRL + \ tuşlarına basın
(Bir terminalde çalıştırırsanız ve sadece programınızı öldürmek ve go rutinlerini atmak istiyorsanız vb.)
Bu soruyu anahtar sırasını ararken buldum. Programımın gidiş rutinlerini sızdırıp sızdırmadığını anlamanın hızlı ve kolay bir yolunu istedim :)
Açık * NIX sistemlerinde (OSX dahil) bir sinyal iptali gönderir SIGABRT
:
pkill -SIGABRT program_name
runtime.Stack()
Yığın izlemenizden sonra bir dizi boş satır yazdırmaktan kaçınmak için döndürülen uzunluğu kullanmak gerekir . Aşağıdaki kurtarma işlevi, güzel biçimlendirilmiş bir iz yazdırır:
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]))
}
Varsayılan olarak, tüm grupların yığın izlerini dökmek için ^\
tuşlarına ( CTRL + \ ) basın .
Aksi takdirde, daha ayrıntılı kontrol için kullanabilirsiniz panic
. Go 1.6+ sürümünden itibaren basit yol :
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
Ardından, programınızı şu şekilde çalıştırın:
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
Ayrıca go çalışma zamanı goroutinlerini yazdırmak istiyorsanız:
$ GOTRACEBACK=system go run main.go
İşte tüm GOTRACEBACK seçenekleri:
GOTRACEBACK=none
gorutin yığın izlerini tamamen atlar.GOTRACEBACK=single
(varsayılan) yukarıda açıklandığı gibi davranır.GOTRACEBACK=all
tüm kullanıcı tarafından oluşturulan gorutinler için yığın izleri ekler.GOTRACEBACK=system
`` tümü '' gibidir ancak çalışma zamanı işlevleri için yığın çerçeveleri ekler ve çalışma zamanı tarafından dahili olarak oluşturulan gorutinleri gösterir.GOTRACEBACK=crash
`` sistem '' gibidir ancak çıkmak yerine işletim sistemine özel bir şekilde çöker. Örneğin, Unix sistemlerinde, kilitlenme SIGABRT
bir çekirdek dökümü tetiklemek için yükselir .GOTRACEBACK değişkeni, bir Go programı kurtarılmamış bir panik veya beklenmedik bir çalışma zamanı durumu nedeniyle başarısız olduğunda üretilen çıktı miktarını kontrol eder.
Varsayılan olarak, bir başarısızlık, mevcut program için bir yığın izini yazdırır, çalışma zamanı sisteminin içindeki işlevleri ortadan kaldırır ve ardından çıkış kodu 2 ile çıkar. çalışma zamanına dahil.
Geçmiş nedenlerden dolayı, GOTRACEBACK ayarları 0, 1 ve 2 sırasıyla none, all ve system için eşanlamlıdır.
Çalışma zamanı / hata ayıklama paketinin SetTraceback işlevi, çalışma zamanında çıktı miktarını artırmaya izin verir, ancak miktarı ortam değişkeni tarafından belirtilenin altına indiremez. Bkz https://golang.org/pkg/runtime/debug/#SetTraceback .