ゴルーチンのスタックトレースをダンプする方法は?


回答:


107

現在のゴルーチンのスタックトレースを出力するには、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)

1
すべてのゴルーチンのスタックトレースを出力しますか?

する必要があります、それは呼び出しますStack。「スタックは、それを呼び出すゴルーチンのフォーマットされたスタックトレースを返します。ルーチンごとに、ソース行情報とPC値が含まれ、Go関数の場合、呼び出し元の関数またはメソッドと、それを含む行のテキストを検出しようとします。呼び出し。」
インターマーネット2013

1
申し訳ありませんが、現在のゴルーチンスタックトレースのみを出力します。

4
@HowardGuo runtime / pprofを使用してすべてのスタックトレースをダンプする例を追加しました。
インターマーネット2013年

1
これは、すべてのゴルーチンではなく、各スレッドの現在実行中のゴルーチンのみを出力すると思います。例:play.golang.org/p/0hVB0_LMdm
rogerdpack 2014

41

runtime/pprofIntermernetの回答に記載されているパッケージの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


私はそれを実行させましたが、私が見る限り実行されたゴルーチンのみを示しています。main.goの起動後に実行されるすべての「メソッド」を確認する方法はありますか?
ルーカス・Lukac

38

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])
    }
}()

4
これが作者が本当に探していたものだと思います-kill-QUITを送信したときにJavaが行うことを模倣しています。私がしなければならなかった小さな変更の1つは、for()ループの最初の行を「<-sigs」に変更することでした。つまり、信号を待った後、信号を破棄するだけです。Goの最近のバージョンでは、後で使用せずに変数を宣言することはできません。
ジョージアームホールド2015年

@ブライアン、StackOverflowで必要なCC-BY-SA 3.0に加えて、BSDまたはその他のより寛容な条件でこれをライセンスしてもよろしいですか?
チャールズ・ダフィー

1
@CharlesDuffyあなたがここにApacheライセンスの下でずっと同じものを見つけることができます:github.com/weaveworks/weave/blob/...
ブライアン・

37

Javaと同様に、SIGQUITを使用して、Goプログラムとそのゴルーチンのスタックトレースを出力できます。
ただし、主な違いは、デフォルトではSIGQUITをJavaプログラムに送信しても終了しないのに対し、Goプログラムは終了することです。

このアプローチでは、既存のプログラムのすべてのゴルーチンのスタックトレースを出力するためにコードを変更する必要はありません。

環境変数GOTRACEBACK(ランタイムパッケージのドキュメントを参照)は、生成される出力の量を制御します。たとえば、すべてのゴルーチンを含めるには、GOTRACEBACK = allを設定します。

スタックトレースの出力は、このコミットで最初に文書化された予期しないランタイム条件(未処理のシグナル)によってトリガーされ、少なくともGo1.1以降で使用できるようになります。


または、ソースコードの変更がオプションである場合は、他の回答を参照してください。


Linuxターミナルでは、SIGQUITはキーの組み合わせCtrl+で便利に送信できることに注意してください\


5
ドキュメントを調べていると、SIGQUITについての言及は見つかりませんでしたが、SIGABRTについての言及は見つかりませんでした。私自身のテスト(go 1.7)から、後者も前者を上回りました。
soltysh 2017

4
これが一番の答えになるはずです。
StevenSoroka19年

ドキュメントでは、「パニックが回復しないか、予期しないランタイム状態が原因でGoプログラムが失敗した場合」について説明しています。捕捉されなかった信号(SIGQUITなど)は後者の1つです。なぜSIGQUITに言及したのですか?OPはJavaでSIGQUITを使用することへの愛情を表明しており、この回答は類似性を強調しているためです。答えを明確にするために言い換えます。
RodolfoCarvalho19年

26

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にフォーマットします。


これには、すべてのゴルーチンからのバックトレースが含まれます。
rogerdpack 2014

これは、回復されていないパニックが要約して使用する形式ですか?
ztyx 2014

2
string(buf)を追加することを忘れないでください。そうしないと、そこに生のバイトが出力されます。
koda 2015年

2
何か間違ったことをしているのか、機能が変更されているのかもしれませんが、空のバイトスライス以外は何も取得されませんか?
17xande 2016年

1
@koda行う必要はありませんstring(buf)ここでは、fmt.Printf("%s", buf)fmt.Printf("%s", string(buf))まったく同じことを行うには(のためのドキュメントを参照fmtパッケージ)。ここでの唯一の違いは、stringバージョンがbuf不必要にバイトをコピーすることです
kbolino 2018

20

CTRL + \を押します

(ターミナルで実行し、プログラムを強制終了してgoルーチンなどをダンプしたい場合)

私はこの質問がキーシーケンスを探しているのを見つけました。私のプログラムがgoルーチンをリークしているかどうかをすばやく簡単に判断する方法が必要でした:)


11

* NIXシステム(OSXを含む)では、シグナルアボートを送信しますSIGABRT

pkill -SIGABRT program_name


どうやら、SIGQUITをJavaプロセスに送信しても、SIGABRTのように終了することはありません
デイブC

私はこれが元の質問に対する最も単純で最も一致する解決策であることがわかりました。多くの場合、コードを変更せずに、すぐにスタックトレースが必要になります。
jotrocken 2017

5

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]))
}

ありませんruntime.Trace; runtime.Stack すでに1年半前に言及されました
デイブC

私はそれを見たことがありません。どのプラットフォームで実行していますか?
ブライアン

あなたが見たことがないのは何ですか?コードはすべてのプラットフォームで実行する必要があります。Windows 7、Ubuntu 14.04、Macでテストしました。
David Tootill 2015年

空の行は見たことがありません。
ブライアン

4

デフォルトでは、^\キー(CTRL + \)を押して、すべてのゴルーチンのスタックトレースをダンプします。


それ以外の場合は、よりきめ細かい制御のために、を使用できますpanicGo 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を参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.