Не могу использовать инструмент go pprof с существующим сервером

У меня есть существующий http-сервер, который я хотел бы профилировать. Я включил _ "net/http/pprof"в мой импорт, и у меня уже работает http-сервер:

router := createRouter()
server := &http.Server {
    Addr:           ":8080",
    Handler:        router,
    ReadTimeout:    15*time.Second,
    WriteTimeout:   15*time.Second,
//  MaxHeaderBytes: 4096,
}

log.Fatal(server.ListenAndServe())

Когда я пытаюсь получить доступ к http://localhost:8080/debug/pprof/ я получаю 404 page not found,

Вот что я получаю при использовании go tool pprof на локальной машине:

userver@userver:~/Desktop/gotest$ go tool pprof http://192.168.0.27:8080/
Use of uninitialized value $prefix in concatenation (.) or string at /usr/lib/go/pkg/tool/linux_amd64/pprof line 3019.
Read http://192.168.0.27:8080/pprof/symbol
Failed to get the number of symbols from http://192.168.0.27:8080/pprof/symbol

userver@userver:~/Desktop/gotest$ go tool pprof http://localhost:8080/debug/pprof/profile
Read http://localhost:8080/debug/pprof/symbol
Failed to get the number of symbols from http://localhost:8080/debug/pprof/symbol

То же самое для удаленного клиента:

MacBookAir:~ apple$ go tool pprof http://192.168.0.27:8080/
Use of uninitialized value $prefix in concatenation (.) or string at /usr/local/Cellar/go/1.3.2/libexec/pkg/tool/darwin_amd64/pprof line 3027.
Read http://192.168.0.27:8080/pprof/symbol
Failed to get the number of symbols from http://192.168.0.27:8080/pprof/symbol

4 ответа

Решение

Это явно не упоминается в документации, но net/http/pprofтолько регистрирует свои обработчики http.DefaultServeMux,

Из источника:

func init() {
        http.Handle("/debug/pprof/", http.HandlerFunc(Index))
        http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
        http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
        http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
        http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}

Если вы не используете мультиплексор по умолчанию, вам просто нужно зарегистрировать любые / все те, которые вы хотите, на любом мультиплексоре, который вы используете, например, что-то вроде mymux.HandleFunc("…", pprof.Index), так далее.

В качестве альтернативы вы можете прослушивать отдельный порт (также, возможно, связанный только с localhost, если это необходимо) с мультиплексированием по умолчанию, как вы показали.

Если вы используете github.com/gorilla/mux.Router Вы можете просто передать любой запрос с префиксом /debug/ к http.DefaultServeMux,

router := mux.NewRouter()
router.PathPrefix("/debug/").Handler(http.DefaultServeMux)

Похоже, проблема была в *mux.Router позаимствованно из github.com/gorilla/mux который я использовал как Handler в моем http.Server пример.

Решение: просто запустите еще один сервер только для pprof:

server := &http.Server {
    Addr:           ":8080",
    Handler:        router,
    ReadTimeout:    15*time.Second,
    WriteTimeout:   15*time.Second,
}
go func() {
    log.Println(http.ListenAndServe(":6060", nil))
}()
log.Fatal(server.ListenAndServe())

Вот как можно использовать pprof в сочетании с мультиплексором Gorilla . Чтобы избежать ошибок HTTP 404, нам нужно явно указать маршрут для /debug/pprof/{cmd}потому что Gorilla не выполняет префиксную маршрутизацию:

      router := mux.NewRouter()
router.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
router.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
router.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
router.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
router.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
router.Handle("/debug/pprof/{cmd}", http.HandlerFunc(pprof.Index)) // special handling for Gorilla mux

err := http.ListenAndServe("127.0.0.1:9999", router)
log.Errorf("pprof server listen failed: %v", err) // note: http.ListenAndServe never returns nil
Другие вопросы по тегам