私はJavaのバックグラウンドを持っており、シグナルQUITを使用してJavaスレッドダンプを検査するのが大好きです。
Golangにすべてのgoroutineスタックトレースを出力させる方法は?
私はJavaのバックグラウンドを持っており、シグナルQUITを使用してJavaスレッドダンプを検査するのが大好きです。
Golangにすべてのgoroutineスタックトレースを出力させる方法は?
回答:
現在のゴルーチンのスタックトレースを出力するには、fromを使用PrintStack()
しruntime/debug
ます。
PrintStackは、Stackによって返されたスタックトレースを標準エラーで出力します。
例えば:
import(
"runtime/debug"
)
...
debug.PrintStack()
すべてのgoroutineのスタックトレースを出力するにはLookup
、およびWriteTo
から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.
各プロファイルには一意の名前があります。いくつかのプロファイルが事前定義されています。
goroutine-現在のすべてのgoroutines
ヒープの
スタックトレース-すべてのヒープ割り当てのサンプリングthreadcreate-新しいOSスレッド
ブロックの作成につながったスタックトレース-同期プリミティブのブロックにつながったスタックトレース
例えば:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
。「スタックは、それを呼び出すゴルーチンのフォーマットされたスタックトレースを返します。ルーチンごとに、ソース行情報とPC値が含まれ、Go関数の場合、呼び出し元の関数またはメソッドと、それを含む行のテキストを検出しようとします。呼び出し。」
runtime/pprof
Intermernetの回答に記載されているパッケージのHTTPフロントエンドがあります。net / http / pprofパッケージをインポートして、次のHTTPハンドラーを登録します/debug/pprof
。
import _ "net/http/pprof"
import _ "net/http"
HTTPリスナーをまだ持っていない場合は、開始します。
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
次に、ブラウザでhttp://localhost:6060/debug/pprof
メニューまたはhttp://localhost:6060/debug/pprof/goroutine?debug=2
完全なゴルーチンスタックダンプを指定します。
この方法で実行中のコードについて学ぶことができる他の楽しいこともあります。例と詳細については、ブログ投稿を確認してください:http: //blog.golang.org/profiling-go-programs
SIGQUITでのスタックダンプのJava動作を模倣し、プログラムを実行したままにするには:
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と同様に、SIGQUITを使用して、Goプログラムとそのゴルーチンのスタックトレースを出力できます。
ただし、主な違いは、デフォルトではSIGQUITをJavaプログラムに送信しても終了しないのに対し、Goプログラムは終了することです。
このアプローチでは、既存のプログラムのすべてのゴルーチンのスタックトレースを出力するためにコードを変更する必要はありません。
環境変数GOTRACEBACK(ランタイムパッケージのドキュメントを参照)は、生成される出力の量を制御します。たとえば、すべてのゴルーチンを含めるには、GOTRACEBACK = allを設定します。
スタックトレースの出力は、このコミットで最初に文書化された予期しないランタイム条件(未処理のシグナル)によってトリガーされ、少なくともGo1.1以降で使用できるようになります。
または、ソースコードの変更がオプションである場合は、他の回答を参照してください。
Linuxターミナルでは、SIGQUITはキーの組み合わせCtrl+で便利に送信できることに注意してください\。
runtime.Stackを使用して、すべてのゴルーチンのスタックトレースを取得できます。
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
ドキュメントから:
func Stack(buf []byte, all bool) int
Stackは、呼び出し元のゴルーチンのスタックトレースをbufにフォーマットし、bufに書き込まれたバイト数を返します。すべてがtrueの場合、Stackは、他のすべてのゴルーチンのスタックトレースを、現在のゴルーチンのトレースの後にbufにフォーマットします。
string(buf)
ここでは、fmt.Printf("%s", buf)
とfmt.Printf("%s", string(buf))
まったく同じことを行うには(のためのドキュメントを参照fmt
パッケージ)。ここでの唯一の違いは、string
バージョンがbuf
不必要にバイトをコピーすることです
CTRL + \を押します
(ターミナルで実行し、プログラムを強制終了してgoルーチンなどをダンプしたい場合)
私はこの質問がキーシーケンスを探しているのを見つけました。私のプログラムがgoルーチンをリークしているかどうかをすばやく簡単に判断する方法が必要でした:)
* NIXシステム(OSXを含む)では、シグナルアボートを送信しますSIGABRT
。
pkill -SIGABRT program_name
runtime.Stack()
スタックトレースの後に大量の空の行が出力されないように、によって返される長さを使用する必要があります。次の回復関数は、適切にフォーマットされたトレースを出力します。
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]))
}
デフォルトでは、^\
キー(CTRL + \)を押して、すべてのゴルーチンのスタックトレースをダンプします。
それ以外の場合は、よりきめ細かい制御のために、を使用できますpanic
。Go 1.6+以降の簡単な方法:
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
次に、次のようにプログラムを実行します。
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
goランタイムゴルーチンも印刷する場合:
$ GOTRACEBACK=system go run main.go
すべてのGOTRACEBACKオプションは次のとおりです。
GOTRACEBACK=none
ゴルーチンスタックトレースを完全に省略します。GOTRACEBACK=single
(デフォルト)上記のように動作します。GOTRACEBACK=all
ユーザーが作成したすべてのゴルーチンのスタックトレースを追加します。GOTRACEBACK=system
`ʻall ''に似ていますが、実行時関数のスタックフレームを追加し、実行時に内部的に作成されたゴルーチンを表示します。GOTRACEBACK=crash
「システム」に似ていますが、終了するのではなく、オペレーティングシステム固有の方法でクラッシュします。たとえば、Unixシステムでは、クラッシュが発生SIGABRT
してコアダンプがトリガーされます。GOTRACEBACK変数は、回復されないパニックまたは予期しない実行時条件が原因でGoプログラムが失敗したときに生成される出力の量を制御します。
デフォルトでは、障害は現在のゴルーチンのスタックトレースを出力し、ランタイムシステムの内部の関数を削除してから、終了コード2で終了します。現在のゴルーチンがない場合、または障害が発生した場合、障害はすべてのゴルーチンのスタックトレースを出力します。ランタイムの内部。
歴史的な理由から、GOTRACEBACK設定0、1、および2は、それぞれnone、all、およびsystemの同義語です。
ランタイム/デバッグパッケージのSetTraceback関数を使用すると、実行時に出力の量を増やすことができますが、環境変数で指定された量より少なくすることはできません。https://golang.org/pkg/runtime/debug/#SetTracebackを参照してください。