Come scaricare gli stacktrace goroutine?


Risposte:


107

Per stampare la traccia dello stack per la goroutine corrente , utilizzare PrintStack()daruntime/debug .

PrintStack stampa sull'errore standard la traccia dello stack restituita da Stack.

Per esempio:

import(
   "runtime/debug"
)
...    
debug.PrintStack()

Per stampare la traccia dello stack per tutti i goroutine utilizzare Lookupe WriteToda 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.

Ogni profilo ha un nome univoco. Alcuni profili sono predefiniti:

goroutine - tracce dello stack di tutti gli
heap goroutine correnti - un campionamento di tutte le allocazioni di heap
threadcreate - tracce dello stack che hanno portato alla creazione di nuovi thread del sistema operativo
block - tracce dello stack che hanno portato al blocco delle primitive di sincronizzazione

Per esempio:

pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)

1
Stampa la traccia dello stack di tutte le goroutine?

Dovrebbe, chiama Stack. "Stack restituisce un'analisi dello stack formattata della goroutine che la chiama. Per ogni routine, include le informazioni sulla riga di origine e il valore del PC, quindi tenta di scoprire, per le funzioni Go, la funzione o il metodo chiamante e il testo della riga contenente invocazione."
Intermernet

1
Spiacenti, stampa solo la traccia dello stack goroutine corrente.

4
@HowardGuo Ho aggiunto un esempio utilizzando runtime / pprof per scaricare tutte le tracce dello stack.
Intermernet

1
Penso che questo restituisca solo la goroutine attualmente in esecuzione di ogni thread, non tutte le goroutine, es: play.golang.org/p/0hVB0_LMdm
rogerdpack

41

C'è un frontend HTTP per il runtime/pprofpacchetto menzionato nella risposta di Intermernet. Importa il pacchetto net / http / pprof per registrare un gestore HTTP per /debug/pprof:

import _ "net/http/pprof"
import _ "net/http"

Avvia un listener HTTP se non ne hai già uno:

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

Quindi punta un browser su http://localhost:6060/debug/pprofper un menu o http://localhost:6060/debug/pprof/goroutine?debug=2per uno stack dump goroutine completo.

Ci sono anche altre cose divertenti che puoi imparare sul tuo codice in esecuzione in questo modo. Guarda il post del blog per esempi e maggiori dettagli: http://blog.golang.org/profiling-go-programs


L'ho fatto funzionare da esso mostra solo le goroutine eseguite per quanto vedo. C'è un modo per vedere tutti i "metodi" che vengono eseguiti dopo il lancio di main.go?
Lukas Lukac

38

Per imitare il comportamento Java di stack-dump su SIGQUIT ma lasciando il programma in esecuzione:

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
Penso che questo sia ciò che l'autore stava davvero cercando: imita ciò che fa Java quando si invia un kill -QUIT. Un piccolo cambiamento che ho dovuto fare è stato quello di cambiare la prima riga del ciclo for () in: "<- sigs". In altre parole, scarta il segnale dopo averlo atteso. Le versioni recenti di Go non ti consentono di dichiarare una variabile senza utilizzarla in seguito.
George Armhold

@Bryan, sei disposto a concederlo in licenza in base a BSD o ad altri termini più permissivi aggiuntivi rispetto a CC-BY-SA 3.0 richiesto da StackOverflow?
Charles Duffy

1
@CharlesDuffy puoi trovare più o meno la stessa cosa qui sotto la licenza Apache: github.com/weaveworks/weave/blob/…
Bryan

37

Simile a Java, SIGQUIT può essere utilizzato per stampare una traccia dello stack di un programma Go e le sue goroutine.
Una differenza fondamentale, tuttavia, è che per impostazione predefinita l'invio di SIGQUIT a programmi Java non li termina, mentre i programmi Go terminano.

Questo approccio non richiede modifiche al codice per stampare una traccia dello stack di tutte le goroutine dei programmi esistenti.

La variabile d'ambiente GOTRACEBACK ( vedere la documentazione del pacchetto runtime ) controlla la quantità di output generato. Ad esempio, per includere tutte le goroutine, imposta GOTRACEBACK = all.

La stampa dello stack trace è innescata da una condizione di runtime imprevista (segnale non gestito), originariamente documentata in questo commit , rendendola disponibile almeno a partire da Go 1.1.


In alternativa, se la modifica del codice sorgente è un'opzione, vedere altre risposte.


Notare che in un terminale Linux, SIGQUIT può essere comodamente inviato con la combinazione di tasti Ctrl+ \.


5
Guardando i documenti non ho trovato alcuna menzione di SIGQUIT, piuttosto SIGABRT. Dai miei test (con go 1.7) quest'ultimo ha funzionato anche sul primo.
Soltysh

4
questa dovrebbe essere la risposta migliore.
Steven Soroka

I documenti fanno riferimento a "quando un programma Go fallisce a causa di un panico non recuperato o di una condizione di runtime imprevista". Un segnale non rilevato (SIGQUIT, ecc.) È uno di questi ultimi. Perché ho menzionato SIGQUIT? Perché l'OP esprime il proprio amore per l'utilizzo di SIGQUIT con Java, e questa risposta sottolinea la somiglianza. Riformulare la risposta per renderla più chiara.
Rodolfo Carvalho

26

Puoi usare runtime.Stack per ottenere la traccia dello stack di tutte le goroutine:

buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)

Dalla documentazione:

func Stack(buf []byte, all bool) int

Stack formatta una traccia dello stack della goroutine chiamante in buf e restituisce il numero di byte scritti in buf. Se tutto è vero, Stack formati impilano le tracce di tutte le altre goroutine in buf dopo la traccia per la goroutine corrente.


Questo include i backtrace di tutte le goroutine, bello!
rogerdpack

È questo il formato che si riduce a utilizzare un panico irrecuperabile?
Ztyx

2
Non dimenticare di aggiungere la stringa (buf) o stamperai i byte grezzi lì.
koda

2
Forse sto facendo qualcosa di sbagliato, o forse la funzionalità è cambiata, ma questo non recupera nulla per me tranne una fetta vuota di byte?
17xande

1
@koda non è necessario fare string(buf)qui fmt.Printf("%s", buf)e fmt.Printf("%s", string(buf))fare la stessa identica cosa (vedere la documentazione per il fmtpacchetto); l'unica differenza qui è che la stringversione copierà bufinutilmente i byte da
kbolino

20

Premi CTRL + \

(Se lo esegui in un terminale e vuoi solo terminare il tuo programma e scaricare le routine go ecc.)

Ho trovato questa domanda cercando la sequenza di tasti. Volevo solo un modo semplice e veloce per sapere se il mio programma perdeva le routine di go :)


11

Sui sistemi * NIX (incluso OSX) invia un segnale di interruzione SIGABRT:

pkill -SIGABRT program_name


Apparentemente, l'invio di SIGQUIT a un processo Java non lo termina come farà SIGABRT.
Dave C

Ho trovato che questa è la soluzione più semplice e più corrispondente alla domanda originale. Spesso hai bisogno di uno stacktrace subito, senza cambiare il tuo codice.
jotrocken

5

È necessario utilizzare la lunghezza restituita da runtime.Stack()per evitare di stampare un mucchio di righe vuote dopo la traccia dello stack. La seguente funzione di ripristino stampa una traccia ben formattata:

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

Non c'è runtime.Trace; runtime.Stack era già stato menzionato un anno e mezzo fa .
Dave C

Non l'ho mai visto; su quale piattaforma stai correndo?
Bryan

Cos'è che non hai visto? Il codice dovrebbe essere eseguito su tutte le piattaforme; L'ho testato su Windows 7, Ubuntu 14.04 e Mac.
David Tootill

Mai visto righe vuote.
Bryan

4

Per impostazione predefinita, premere i ^\tasti ( CTRL + \ ) per scaricare le tracce dello stack di tutte le goroutine.


Altrimenti, per un controllo più granulare, puoi usare panic. Il modo più semplice a partire da Go 1.6+ :

go func() {
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGQUIT)
    <-s
    panic("give me the stack")
}()

Quindi, esegui il programma in questo modo:

# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go

Se vuoi anche stampare go runtime goroutine:

$ GOTRACEBACK=system go run main.go

Ecco tutte le opzioni di GOTRACEBACK:

  • GOTRACEBACK=none omette completamente le tracce dello stack goroutine.
  • GOTRACEBACK=single (l'impostazione predefinita) si comporta come descritto sopra.
  • GOTRACEBACK=all aggiunge tracce dello stack per tutte le goroutine create dall'utente.
  • GOTRACEBACK=system è come "tutti" ma aggiunge stack frame per le funzioni di runtime e mostra le goroutine create internamente dal runtime.
  • GOTRACEBACK=crashè come `` sistema '' ma si arresta in modo anomalo in un modo specifico del sistema operativo invece di uscire. Ad esempio, su sistemi Unix, il crash si verifica SIGABRTper attivare un core dump.

Ecco la documentazione

La variabile GOTRACEBACK controlla la quantità di output generata quando un programma Go non riesce a causa di un panico non recuperato o di una condizione di runtime imprevista.

Per impostazione predefinita, un errore stampa una traccia dello stack per la goroutine corrente, eliminando le funzioni interne al sistema di runtime, quindi esce con il codice di uscita 2. L'errore stampa le tracce dello stack per tutte le goroutine se non c'è goroutine corrente o l'errore è interno al tempo di esecuzione.

Per ragioni storiche, le impostazioni GOTRACEBACK 0, 1 e 2 sono sinonimi rispettivamente di none, all e system.

La funzione SetTraceback del pacchetto runtime / debug consente di aumentare la quantità di output in fase di esecuzione, ma non può ridurre la quantità inferiore a quella specificata dalla variabile di ambiente. Vedi https://golang.org/pkg/runtime/debug/#SetTraceback .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.