diff --git a/api/server/profiler.go b/api/server/profiler.go deleted file mode 100644 index d49be338c8..0000000000 --- a/api/server/profiler.go +++ /dev/null @@ -1,46 +0,0 @@ -package server - -import ( - "expvar" - "fmt" - "net/http" - "net/http/pprof" - - "github.com/gorilla/mux" -) - -const debugPathPrefix = "/debug/" - -func profilerSetup(mainRouter *mux.Router) { - var r = mainRouter.PathPrefix(debugPathPrefix).Subrouter() - r.HandleFunc("/vars", expVars) - r.HandleFunc("/pprof/", pprof.Index) - r.HandleFunc("/pprof/cmdline", pprof.Cmdline) - r.HandleFunc("/pprof/profile", pprof.Profile) - r.HandleFunc("/pprof/symbol", pprof.Symbol) - r.HandleFunc("/pprof/trace", pprof.Trace) - r.HandleFunc("/pprof/{name}", handlePprof) -} - -func handlePprof(w http.ResponseWriter, r *http.Request) { - var name string - if vars := mux.Vars(r); vars != nil { - name = vars["name"] - } - pprof.Handler(name).ServeHTTP(w, r) -} - -// Replicated from expvar.go as not public. -func expVars(w http.ResponseWriter, r *http.Request) { - first := true - w.Header().Set("Content-Type", "application/json; charset=utf-8") - fmt.Fprintln(w, "{") - expvar.Do(func(kv expvar.KeyValue) { - if !first { - fmt.Fprintln(w, ",") - } - first = false - fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value) - }) - fmt.Fprintln(w, "\n}") -} diff --git a/api/server/router/debug/debug.go b/api/server/router/debug/debug.go new file mode 100644 index 0000000000..b66ff3cf3a --- /dev/null +++ b/api/server/router/debug/debug.go @@ -0,0 +1,53 @@ +package debug + +import ( + "expvar" + "net/http" + "net/http/pprof" + + "github.com/docker/docker/api/server/httputils" + "github.com/docker/docker/api/server/router" + "golang.org/x/net/context" +) + +// NewRouter creates a new debug router +// The debug router holds endpoints for debug the daemon, such as those for pprof. +func NewRouter() router.Router { + r := &debugRouter{} + r.initRoutes() + return r +} + +type debugRouter struct { + routes []router.Route +} + +func (r *debugRouter) initRoutes() { + r.routes = []router.Route{ + router.NewGetRoute("/vars", frameworkAdaptHandler(expvar.Handler())), + router.NewGetRoute("/pprof/", frameworkAdaptHandlerFunc(pprof.Index)), + router.NewGetRoute("/pprof/cmdline", frameworkAdaptHandlerFunc(pprof.Cmdline)), + router.NewGetRoute("/pprof/profile", frameworkAdaptHandlerFunc(pprof.Profile)), + router.NewGetRoute("/pprof/symbol", frameworkAdaptHandlerFunc(pprof.Symbol)), + router.NewGetRoute("/pprof/trace", frameworkAdaptHandlerFunc(pprof.Trace)), + router.NewGetRoute("/pprof/{name}", handlePprof), + } +} + +func (r *debugRouter) Routes() []router.Route { + return r.routes +} + +func frameworkAdaptHandler(handler http.Handler) httputils.APIFunc { + return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + handler.ServeHTTP(w, r) + return nil + } +} + +func frameworkAdaptHandlerFunc(handler http.HandlerFunc) httputils.APIFunc { + return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + handler(w, r) + return nil + } +} diff --git a/api/server/router/debug/debug_routes.go b/api/server/router/debug/debug_routes.go new file mode 100644 index 0000000000..f2a72615a0 --- /dev/null +++ b/api/server/router/debug/debug_routes.go @@ -0,0 +1,13 @@ +package debug + +import ( + "net/http" + "net/http/pprof" + + "golang.org/x/net/context" +) + +func handlePprof(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + pprof.Handler(vars["name"]).ServeHTTP(w, r) + return nil +} diff --git a/api/server/server.go b/api/server/server.go index d402019113..e0f2d89d9a 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/server/middleware" "github.com/docker/docker/api/server/router" + "github.com/docker/docker/api/server/router/debug" "github.com/docker/docker/dockerversion" "github.com/gorilla/mux" "golang.org/x/net/context" @@ -148,13 +149,10 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc { // InitRouter initializes the list of routers for the server. // This method also enables the Go profiler if enableProfiler is true. -func (s *Server) InitRouter(enableProfiler bool, routers ...router.Router) { +func (s *Server) InitRouter(routers ...router.Router) { s.routers = append(s.routers, routers...) m := s.createMux() - if enableProfiler { - profilerSetup(m) - } s.routerSwapper = &routerSwapper{ router: m, } @@ -175,6 +173,13 @@ func (s *Server) createMux() *mux.Router { } } + debugRouter := debug.NewRouter() + s.routers = append(s.routers, debugRouter) + for _, r := range debugRouter.Routes() { + f := s.makeHTTPHandler(r.Handler()) + m.Path("/debug" + r.Path()).Handler(f) + } + err := errors.NewRequestNotFoundError(fmt.Errorf("page not found")) notFoundHandler := httputils.MakeErrorHandler(err) m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler) @@ -194,15 +199,3 @@ func (s *Server) Wait(waitChan chan error) { } waitChan <- nil } - -// DisableProfiler reloads the server mux without adding the profiler routes. -func (s *Server) DisableProfiler() { - s.routerSwapper.Swap(s.createMux()) -} - -// EnableProfiler reloads the server mux adding the profiler routes. -func (s *Server) EnableProfiler() { - m := s.createMux() - profilerSetup(m) - s.routerSwapper.Swap(m) -} diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index ad937ede7c..215f9c2d59 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -383,10 +383,8 @@ func (cli *DaemonCli) reloadConfig() { switch { case debugEnabled && !config.Debug: // disable debug debug.Disable() - cli.api.DisableProfiler() case config.Debug && !debugEnabled: // enable debug debug.Enable() - cli.api.EnableProfiler() } } @@ -536,7 +534,7 @@ func initRouter(opts routerOptions) { } } - opts.api.InitRouter(debug.IsEnabled(), routers...) + opts.api.InitRouter(routers...) } // TODO: remove this from cli and return the authzMiddleware