Как я могу сбросить все стеки процесса Go, не убивая его?

Процесс Go запущен. Я хочу

  1. выгрузить трассировку стека для каждой из своих программ
  2. извне, вне зависимости от того, что я добавляю в его исходный код
  3. не убивая его.

Как я могу это сделать?

Это должно быть легко - функция была запрошена: 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 затем используется для форматирования трассировки стека в подготовленный буфер (если он больше, чем буфер, он будет усечен), а затем печатается.