From a2da88a6f3dfad2f1f1c906fbabf2e6afcc5bf2b Mon Sep 17 00:00:00 2001 From: Jim Zhang Date: Wed, 5 Jul 2023 19:07:53 -0400 Subject: [PATCH] Move debug server to a different port and routes Signed-off-by: Jim Zhang --- cmd/debugrouter.go | 66 +++++++++++++++++++++++++++++++ cmd/fabconnect.go | 21 +++++++--- cmd/fabconnect_test.go | 18 +++++++++ internal/rest/router.go | 7 ---- mocks/fabric/client/rpc_client.go | 12 +++--- 5 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 cmd/debugrouter.go diff --git a/cmd/debugrouter.go b/cmd/debugrouter.go new file mode 100644 index 0000000..65d1d14 --- /dev/null +++ b/cmd/debugrouter.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "net/http" + "net/http/pprof" + runtimepprof "runtime/pprof" + + "github.com/julienschmidt/httprouter" + "github.com/rs/cors" + log "github.com/sirupsen/logrus" +) + +type debugRouter struct { + router *httprouter.Router +} + +func NewDebugRouter() *debugRouter { + r := httprouter.New() + cors.Default().Handler(r) + return &debugRouter{ + router: r, + } +} + +func (d *debugRouter) addRoutes() { + d.router.GET("/debug/pprof/cmdline", d.cmdline) + d.router.GET("/debug/pprof/profile", d.profile) + d.router.GET("/debug/pprof/symbol", d.symbol) + d.router.GET("/debug/pprof/trace", d.trace) + d.router.GET("/debug/pprof/goroutines", d.goroutines) + d.router.GET("/debug/pprof/", d.index) +} + +func (d *debugRouter) cmdline(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + log.Infof("--> %s %s", req.Method, req.URL) + pprof.Cmdline(res, req) +} + +func (d *debugRouter) profile(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + log.Infof("--> %s %s", req.Method, req.URL) + pprof.Profile(res, req) +} + +func (d *debugRouter) symbol(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + log.Infof("--> %s %s", req.Method, req.URL) + + pprof.Symbol(res, req) +} + +func (d *debugRouter) trace(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + log.Infof("--> %s %s", req.Method, req.URL) + + pprof.Trace(res, req) +} + +func (d *debugRouter) index(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + log.Infof("--> %s %s", req.Method, req.URL) + + pprof.Index(res, req) +} + +func (d *debugRouter) goroutines(res http.ResponseWriter, req *http.Request, params httprouter.Params) { + log.Infof("--> %s %s", req.Method, req.URL) + + _ = runtimepprof.Lookup("goroutine").WriteTo(res, 1) +} diff --git a/cmd/fabconnect.go b/cmd/fabconnect.go index 7e79f72..1983a28 100644 --- a/cmd/fabconnect.go +++ b/cmd/fabconnect.go @@ -21,6 +21,7 @@ import ( "fmt" "net/http" "strings" + "time" "gopkg.in/yaml.v2" @@ -94,15 +95,23 @@ func newRootCmd() (*cobra.Command, *conf.RESTGatewayConf) { initLogging(rootConfig.DebugLevel) + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { if rootConfig.DebugPort > 0 { + router := NewDebugRouter() + router.addRoutes() + debugServer := &http.Server{Addr: fmt.Sprintf("127.0.0.1:%d", rootConfig.DebugPort), Handler: router.router, ReadHeaderTimeout: 30 * time.Second} go func() { - log.Debugf("Debug HTTP endpoint listening on localhost:%d: %s", rootConfig.DebugPort, http.ListenAndServe(fmt.Sprintf("localhost:%d", rootConfig.DebugPort), nil)) + _ = debugServer.ListenAndServe() }() - } + log.Infof("Debug HTTP endpoint listening on 127.0.0.1:%d", rootConfig.DebugPort) - return nil - }, - RunE: func(cmd *cobra.Command, args []string) error { + defer func() { + log.Infof("Shutting down the debug server") + _ = debugServer.Close() + }() + } err := startServer(restGatewayConf, restGateway) if err != nil { return err @@ -112,7 +121,7 @@ func newRootCmd() (*cobra.Command, *conf.RESTGatewayConf) { } rootCmd.Flags().IntVarP(&rootConfig.DebugLevel, "debug", "d", 1, "0=error, 1=info, 2=debug") - rootCmd.Flags().IntVarP(&rootConfig.DebugPort, "debugPort", "Z", 6060, "Port for pprof HTTP endpoints (localhost only)") + rootCmd.Flags().IntVarP(&rootConfig.DebugPort, "debugPort", "Z", 0, "Port for pprof HTTP endpoints (localhost only)") rootCmd.Flags().BoolVarP(&rootConfig.PrintYAML, "print-yaml-confg", "Y", false, "Print YAML config snippet and exit") rootCmd.Flags().StringVarP(&rootConfig.Filename, "configfile", "f", "", "Configuration file, must be one of .yml, .yaml, or .json") conf.CobraInit(rootCmd, restGatewayConf) diff --git a/cmd/fabconnect_test.go b/cmd/fabconnect_test.go index 07a6499..568c03a 100644 --- a/cmd/fabconnect_test.go +++ b/cmd/fabconnect_test.go @@ -207,3 +207,21 @@ func TestKafkaSuccess(t *testing.T) { assert.Equal([]string{"broker1", "broker2"}, restGatewayConf.Kafka.Brokers) test.Teardown(tmpdir) } + +func TestDebugServer(t *testing.T) { + assert := assert.New(t) + + tmpdir, _ := test.Setup() + rootCmd, _ := newRootCmd() + rootCmd.RunE = runNothing + args := []string{ + "-f", path.Join(tmpdir, "config.json"), + "--debugPort", "6060", + } + rootCmd.SetArgs(args) + os.Unsetenv("FC_HTTP_PORT") + err := rootCmd.Execute() + assert.NoError(err) + assert.Equal(6060, rootConfig.DebugPort) + test.Teardown(tmpdir) +} diff --git a/internal/rest/router.go b/internal/rest/router.go index 68a4ff6..a270a04 100644 --- a/internal/rest/router.go +++ b/internal/rest/router.go @@ -20,7 +20,6 @@ import ( "encoding/json" "fmt" "net/http" - "runtime/pprof" "strings" "github.com/hyperledger/firefly-fabconnect/internal/auth" @@ -102,7 +101,6 @@ func (r *router) addRoutes() { r.httpRouter.GET("/ws", r.wsHandler) r.httpRouter.GET("/status", r.statusHandler) - r.httpRouter.POST("/pprof", r.dumpGoRoutines) } func (r *router) newAccessTokenContextHandler() http.Handler { @@ -448,11 +446,6 @@ func (r *router) resetSubscription(res http.ResponseWriter, req *http.Request, p marshalAndReply(res, req, result) } -func (r *router) dumpGoRoutines(res http.ResponseWriter, req *http.Request, params httprouter.Params) { - log.Infof("--> %s %s", req.Method, req.URL) - _ = pprof.Lookup("goroutine").WriteTo(res, 1) -} - func restAsyncReply(res http.ResponseWriter, req *http.Request, asyncResponse *messages.AsyncSentMsg) { resBytes, _ := json.Marshal(asyncResponse) status := 202 // accepted diff --git a/mocks/fabric/client/rpc_client.go b/mocks/fabric/client/rpc_client.go index 5bc043d..dff59ce 100644 --- a/mocks/fabric/client/rpc_client.go +++ b/mocks/fabric/client/rpc_client.go @@ -38,19 +38,19 @@ func (_m *RPCClient) Invoke(channelId string, signer string, chaincodeName strin var r0 *client.TxReceipt var r1 error - if rf, ok := ret.Get(0).(func(string, string, string, string, []string, bool) (*client.TxReceipt, error)); ok { - return rf(channelId, signer, chaincodeName, method, args, isInit) + if rf, ok := ret.Get(0).(func(string, string, string, string, []string, map[string]string, bool) (*client.TxReceipt, error)); ok { + return rf(channelId, signer, chaincodeName, method, args, transientMap, isInit) } - if rf, ok := ret.Get(0).(func(string, string, string, string, []string, bool) *client.TxReceipt); ok { - r0 = rf(channelId, signer, chaincodeName, method, args, isInit) + if rf, ok := ret.Get(0).(func(string, string, string, string, []string, map[string]string, bool) *client.TxReceipt); ok { + r0 = rf(channelId, signer, chaincodeName, method, args, transientMap, isInit) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*client.TxReceipt) } } - if rf, ok := ret.Get(1).(func(string, string, string, string, []string, bool) error); ok { - r1 = rf(channelId, signer, chaincodeName, method, args, isInit) + if rf, ok := ret.Get(1).(func(string, string, string, string, []string, map[string]string, bool) error); ok { + r1 = rf(channelId, signer, chaincodeName, method, args, transientMap, isInit) } else { r1 = ret.Error(1) }