Как я могу сбросить все стеки процесса Go, не убивая его?
Процесс Go запущен. Я хочу
- выгрузить трассировку стека для каждой из своих программ
- извне, вне зависимости от того, что я добавляю в его исходный код
- не убивая его.
Как я могу это сделать?
Это должно быть легко - функция была запрошена: https://code.google.com/p/go/issues/detail?id=2516 и, согласно заключению этого потока, реализована. Это было более двух лет назад. Но ни ветка проблемы, ни коммит не содержат подсказок о том, как вызвать эту функцию.
Запрос функции упомянул SIGQUIT как сигнал, который JVM принимает для вызова соответствующей функции. Но SIGQUIT не является ответом; по крайней мере, на go1.2 SIGQUIT выполняет # 1 и # 2, но также убивает процесс.
Кто-то задал здесь связанный вопрос некоторое время назад: Как вывести дампы из стека goroutine?
но они четко не просили № 2 или № 3, ни один из ответов не соответствует № 2, и они приняли ответ, который не соответствует № 2. Так что это другой вопрос.
Ответы
Ответ 1
Если вы используете net/http, вы можете получить доступ к goroutines через обработчики отладки. Если вы посмотрите на следующий источник
http://golang.org/src/pkg/runtime/pprof/pprof.go
Вы увидите профиль goroutineProfile
в строке 62. Этот профиль выписывается через writeGoroutine
. Если writeGoroutine вызывается с помощью debug >= 2, он выписывает все goroutines.
Вы должны иметь возможность curl http://localhost:<port>/debug/pprof/goroutine?debug=2
получить все goroutines, сбрасываемые. К сожалению, я не видел ссылок на обработчики сигналов, которые вызывают этот код, но вы можете посмотреть ссылки на то, как pprof использует runtime.Stack
в исходном коде, чтобы реализовать это сами довольно легко.
Ответ 2
Вы можете настроить такой обработчик, используя код примерно так:
import (
"fmt"
"os"
"os/signal"
"runtime"
"syscall"
)
func main() {
sigChan := make(chan os.Signal)
go func() {
stacktrace := make([]byte, 8192)
for _ = range sigChan {
length := runtime.Stack(stacktrace, true)
fmt.Println(string(stacktrace[:length]))
}
}()
signal.Notify(sigChan, syscall.SIGQUIT)
...
}
Сигнал SIGQUIT
теперь будет пойман и отправлен на данный канал. Функция runtime.Stack
затем используется для форматирования трассировки стека в подготовленный буфер (если он больше, чем буфер, он будет усечен), а затем печатается.