Tengo experiencia en Java y me encanta usar la señal QUIT para inspeccionar el volcado de subprocesos de Java.
¿Cómo dejar que Golang imprima todos los rastros de la pila de goroutines?
Tengo experiencia en Java y me encanta usar la señal QUIT para inspeccionar el volcado de subprocesos de Java.
¿Cómo dejar que Golang imprima todos los rastros de la pila de goroutines?
Respuestas:
Para imprimir el seguimiento de la pila para la goroutine actual , use PrintStack()
fromruntime/debug
.
PrintStack imprime con error estándar el seguimiento de pila devuelto por Stack.
Por ejemplo:
import(
"runtime/debug"
)
...
debug.PrintStack()
Para imprimir el seguimiento de la pila para todas las rutinas gor, use Lookup
y WriteTo
from 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.
Cada perfil tiene un nombre único. Algunos perfiles están predefinidos:
goroutine - seguimientos de pila de todos los goroutines actuales
del montón - una muestra de todas las asignaciones del montón
threadcreate - seguimientos de pila que llevaron a la creación de nuevas hebras de SO
bloquear - seguimientos de pila que llevaron al bloqueo de primitivas de sincronización
Por ejemplo:
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
Stack
. "Stack devuelve un seguimiento de pila formateado de la goroutine que la llama. Para cada rutina, incluye la información de la línea fuente y el valor de la PC, luego intenta descubrir, para las funciones Go, la función o método que llama y el texto de la línea que contiene el invocación."
Hay una interfaz HTTP para el runtime/pprof
paquete mencionado en la respuesta de Intermernet. Importe el paquete net / http / pprof para registrar un controlador HTTP para /debug/pprof
:
import _ "net/http/pprof"
import _ "net/http"
Inicie un oyente HTTP si aún no tiene uno:
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
Luego, apunte un navegador a http://localhost:6060/debug/pprof
para un menú, o http://localhost:6060/debug/pprof/goroutine?debug=2
para un volcado de pila de goroutine completo.
También hay otras cosas divertidas que puede aprender sobre su código en ejecución de esta manera. Consulte la publicación del blog para ver ejemplos y más detalles: http://blog.golang.org/profiling-go-programs
Para imitar el comportamiento de Java de stack-dump en SIGQUIT pero aún dejando el programa en ejecución:
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])
}
}()
Al igual que en Java, SIGQUIT se puede utilizar para imprimir un seguimiento de la pila de un programa Go y sus gorutinas.
Sin embargo, una diferencia clave es que, de forma predeterminada, el envío de SIGQUIT a los programas Java no los termina, mientras que los programas Go sí lo hacen.
Este enfoque no requiere ningún cambio de código para imprimir un seguimiento de la pila de todas las rutinas de programas existentes.
La variable de entorno GOTRACEBACK ( consulte la documentación del paquete de tiempo de ejecución ) controla la cantidad de salida generada. Por ejemplo, para incluir todas las goroutines, establezca GOTRACEBACK = all.
La impresión del seguimiento de la pila se desencadena por una condición de tiempo de ejecución inesperada (señal no controlada), originalmente documentada en esta confirmación , que la hace disponible al menos desde Go 1.1.
Alternativamente, si modificar el código fuente es una opción, vea otras respuestas.
Tenga en cuenta que en un terminal Linux, SIGQUIT se puede enviar convenientemente con la combinación de teclas Ctrl+ \.
Puede usar runtime.Stack para obtener el seguimiento de la pila de todas las goroutines:
buf := make([]byte, 1<<16)
runtime.Stack(buf, true)
fmt.Printf("%s", buf)
De la documentación:
func Stack(buf []byte, all bool) int
Stack formatea un seguimiento de pila de la goroutine que llama en buf y devuelve el número de bytes escritos en buf. Si todo es cierto, los formatos de pila apilan los rastros de todas las demás goroutines en buf después del rastro de la goroutine actual.
string(buf)
aquí, fmt.Printf("%s", buf)
y fmt.Printf("%s", string(buf))
haga exactamente lo mismo (vea los documentos para el fmt
paquete); la única diferencia aquí es que la string
versión copiará los bytes buf
innecesariamente
Presione CTRL + \
(Si lo ejecuta en una terminal y solo quiere matar su programa y volcar las rutinas de ir, etc.)
Encontré esta pregunta buscando la secuencia de teclas. Solo quería una forma rápida y fácil de saber si mi programa tiene una fuga de rutinas :)
En los sistemas * NIX (incluido OSX) envían una señal de cancelación SIGABRT
:
pkill -SIGABRT program_name
Es necesario usar la longitud devuelta por runtime.Stack()
para evitar imprimir un montón de líneas vacías después del seguimiento de la pila. La siguiente función de recuperación imprime una traza muy bien formateada:
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]))
}
De forma predeterminada, presione las ^\
teclas ( CTRL + \ ) para volcar los rastros de pila de todas las goroutines.
De lo contrario, para un control más granular, puede usar panic
. La forma sencilla a partir de Go 1.6+ :
go func() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGQUIT)
<-s
panic("give me the stack")
}()
Luego, ejecute su programa así:
# Press ^\ to dump the stack traces of all the user-created goroutines
$ GOTRACEBACK=all go run main.go
Si también desea imprimir go runtime goroutines:
$ GOTRACEBACK=system go run main.go
Aquí están todas las opciones de GOTRACEBACK:
GOTRACEBACK=none
omite por completo los seguimientos de la pila de goroutine.GOTRACEBACK=single
(el predeterminado) se comporta como se describe arriba.GOTRACEBACK=all
agrega seguimientos de pila para todas las goroutines creadas por el usuario.GOTRACEBACK=system
es como "todos" pero agrega marcos de pila para funciones en tiempo de ejecución y muestra las rutinas creadas internamente por el tiempo de ejecución.GOTRACEBACK=crash
es como `` sistema '' pero se bloquea de una manera específica del sistema operativo en lugar de salir. Por ejemplo, en los sistemas Unix, el bloqueo se produce SIGABRT
para desencadenar un volcado del núcleo.La variable GOTRACEBACK controla la cantidad de salida generada cuando un programa Go falla debido a un pánico no recuperado o una condición de tiempo de ejecución inesperada.
De forma predeterminada, una falla imprime un seguimiento de pila para la goroutine actual, eliminando las funciones internas del sistema de tiempo de ejecución y luego sale con el código de salida 2. La falla imprime rastros de pila para todas las goroutines si no hay ninguna goroutine actual o la falla es interno al tiempo de ejecución.
Por razones históricas, los valores 0, 1 y 2 de GOTRACEBACK son sinónimos de none, all y system, respectivamente.
La función SetTraceback del paquete en tiempo de ejecución / depuración permite aumentar la cantidad de salida en tiempo de ejecución, pero no puede reducir la cantidad por debajo de la especificada por la variable de entorno. Consulte https://golang.org/pkg/runtime/debug/#SetTraceback .