diff options
-rw-r--r-- | cmd/rr/cmd/root.go | 8 | ||||
-rw-r--r-- | cmd/rr/debug/debugger.go | 28 | ||||
-rw-r--r-- | cmd/rr/http/reset.go | 6 | ||||
-rw-r--r-- | cmd/rr/http/workers.go | 61 | ||||
-rw-r--r-- | cmd/rr/util/cprint.go (renamed from cmd/rr/utils/cprint.go) | 2 | ||||
-rw-r--r-- | cmd/rr/util/list.go | 58 | ||||
-rw-r--r-- | service/http/rpc.go | 33 | ||||
-rw-r--r-- | util/state.go | 62 |
8 files changed, 149 insertions, 109 deletions
diff --git a/cmd/rr/cmd/root.go b/cmd/rr/cmd/root.go index 4ab37967..aabfcdea 100644 --- a/cmd/rr/cmd/root.go +++ b/cmd/rr/cmd/root.go @@ -24,7 +24,7 @@ import ( "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/spiral/roadrunner/cmd/rr/utils" + "github.com/spiral/roadrunner/cmd/rr/util" "github.com/spiral/roadrunner/service" "os" "path/filepath" @@ -51,7 +51,7 @@ var ( Use: "rr", SilenceErrors: true, SilenceUsage: true, - Short: utils.Sprintf( + Short: util.Sprintf( "<green>RoadRunner, PHP Application Server:</reset>\nVersion: <yellow+hb>%s</reset>, %s", Version, BuildTime, @@ -83,7 +83,7 @@ func (w *ViperWrapper) Unmarshal(out interface{}) error { // This is called by main.main(). It only needs to happen once to the CLI. func Execute() { if err := CLI.Execute(); err != nil { - utils.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err) + util.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err) os.Exit(1) } } @@ -100,7 +100,7 @@ func init() { if cfg := initConfig(cfgFile, []string{"."}, ".rr"); cfg != nil { if err := Container.Init(cfg); err != nil { - utils.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err) + util.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err) os.Exit(1) } } diff --git a/cmd/rr/debug/debugger.go b/cmd/rr/debug/debugger.go index ed9a1a56..5b1d586b 100644 --- a/cmd/rr/debug/debugger.go +++ b/cmd/rr/debug/debugger.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/sirupsen/logrus" "github.com/spiral/roadrunner" - "github.com/spiral/roadrunner/cmd/rr/utils" + "github.com/spiral/roadrunner/cmd/rr/util" rrhttp "github.com/spiral/roadrunner/service/http" "net/http" "strings" @@ -24,7 +24,7 @@ func (s *debugger) listener(event int, ctx interface{}) { switch event { case rrhttp.EventResponse: e := ctx.(*rrhttp.ResponseEvent) - s.logger.Info(utils.Sprintf( + s.logger.Info(util.Sprintf( "<cyan+h>%s</reset> %s <white+hb>%s</reset> %s", e.Request.RemoteAddr, statusColor(e.Response.Status), @@ -35,14 +35,14 @@ func (s *debugger) listener(event int, ctx interface{}) { e := ctx.(*rrhttp.ErrorEvent) if _, ok := e.Error.(roadrunner.JobError); ok { - s.logger.Info(utils.Sprintf( + s.logger.Info(util.Sprintf( "%s <white+hb>%s</reset> %s", statusColor(500), e.Request.Method, uri(e.Request), )) } else { - s.logger.Info(utils.Sprintf( + s.logger.Info(util.Sprintf( "%s <white+hb>%s</reset> %s <red>%s</reset>", statusColor(500), e.Request.Method, @@ -55,13 +55,13 @@ func (s *debugger) listener(event int, ctx interface{}) { switch event { case roadrunner.EventWorkerKill: w := ctx.(*roadrunner.Worker) - s.logger.Warning(utils.Sprintf( + s.logger.Warning(util.Sprintf( "<white+hb>worker.%v</reset> <yellow>killed</red>", *w.Pid, )) case roadrunner.EventWorkerError: err := ctx.(roadrunner.WorkerError) - s.logger.Error(utils.Sprintf( + s.logger.Error(util.Sprintf( "<white+hb>worker.%v</reset> <red>%s</reset>", *err.Worker.Pid, err.Caused, @@ -71,7 +71,7 @@ func (s *debugger) listener(event int, ctx interface{}) { // outputs switch event { case roadrunner.EventStderrOutput: - s.logger.Warning(utils.Sprintf( + s.logger.Warning(util.Sprintf( "<yellow>%s</reset>", strings.Trim(string(ctx.([]byte)), "\r\n"), )) @@ -80,15 +80,15 @@ func (s *debugger) listener(event int, ctx interface{}) { // rr server events switch event { case roadrunner.EventServerFailure: - s.logger.Error(utils.Sprintf("<red>server is dead</reset>")) + s.logger.Error(util.Sprintf("<red>server is dead</reset>")) } // pool events switch event { case roadrunner.EventPoolConstruct: - s.logger.Debug(utils.Sprintf("<cyan>new worker pool</reset>")) + s.logger.Debug(util.Sprintf("<cyan>new worker pool</reset>")) case roadrunner.EventPoolError: - s.logger.Error(utils.Sprintf("<red>%s</reset>", ctx)) + s.logger.Error(util.Sprintf("<red>%s</reset>", ctx)) } //s.logger.Warning(event, ctx) @@ -96,18 +96,18 @@ func (s *debugger) listener(event int, ctx interface{}) { func statusColor(status int) string { if status < 300 { - return utils.Sprintf("<green>%v</reset>", status) + return util.Sprintf("<green>%v</reset>", status) } if status < 400 { - return utils.Sprintf("<cyan>%v</reset>", status) + return util.Sprintf("<cyan>%v</reset>", status) } if status < 500 { - return utils.Sprintf("<yellow>%v</reset>", status) + return util.Sprintf("<yellow>%v</reset>", status) } - return utils.Sprintf("<red>%v</reset>", status) + return util.Sprintf("<red>%v</reset>", status) } // uri fetches full uri from request in a form of string (including https scheme if TLS connection is enabled). diff --git a/cmd/rr/http/reset.go b/cmd/rr/http/reset.go index 3bc089ec..f1129eef 100644 --- a/cmd/rr/http/reset.go +++ b/cmd/rr/http/reset.go @@ -24,7 +24,7 @@ import ( "errors" "github.com/spf13/cobra" rr "github.com/spiral/roadrunner/cmd/rr/cmd" - "github.com/spiral/roadrunner/cmd/rr/utils" + "github.com/spiral/roadrunner/cmd/rr/util" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/rpc" ) @@ -49,13 +49,13 @@ func reloadHandler(cmd *cobra.Command, args []string) error { } defer client.Close() - utils.Printf("<green>restarting http worker pool</reset>: ") + util.Printf("<green>restarting http worker pool</reset>: ") var r string if err := client.Call("http.Reset", true, &r); err != nil { return err } - utils.Printf("<green+hb>done</reset>\n") + util.Printf("<green+hb>done</reset>\n") return nil } diff --git a/cmd/rr/http/workers.go b/cmd/rr/http/workers.go index b03c273f..3c3e9987 100644 --- a/cmd/rr/http/workers.go +++ b/cmd/rr/http/workers.go @@ -23,19 +23,15 @@ package http import ( "errors" tm "github.com/buger/goterm" - "github.com/dustin/go-humanize" - "github.com/olekukonko/tablewriter" - "github.com/shirou/gopsutil/process" "github.com/spf13/cobra" rr "github.com/spiral/roadrunner/cmd/rr/cmd" - "github.com/spiral/roadrunner/cmd/rr/utils" + "github.com/spiral/roadrunner/cmd/rr/util" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/http" rrpc "github.com/spiral/roadrunner/service/rpc" "net/rpc" "os" "os/signal" - "strconv" "syscall" "time" ) @@ -108,58 +104,5 @@ func showWorkers(client *rpc.Client) { panic(err) } - tw := tablewriter.NewWriter(os.Stdout) - tw.SetHeader([]string{"PID", "Status", "Execs", "Memory", "Created"}) - tw.SetColMinWidth(0, 7) - tw.SetColMinWidth(1, 9) - tw.SetColMinWidth(2, 7) - tw.SetColMinWidth(3, 7) - tw.SetColMinWidth(4, 18) - - for _, w := range r.Workers { - tw.Append([]string{ - strconv.Itoa(w.Pid), - renderStatus(w.Status), - renderJobs(w.NumJobs), - renderMemory(w.Pid), - renderAlive(time.Unix(0, w.Created)), - }) - } - - tw.Render() -} - -func renderStatus(status string) string { - switch status { - case "inactive": - return utils.Sprintf("<yellow>inactive</reset>") - case "ready": - return utils.Sprintf("<cyan>ready</reset>") - case "working": - return utils.Sprintf("<green>working</reset>") - case "stopped": - return utils.Sprintf("<red>stopped</reset>") - case "errored": - return utils.Sprintf("<red>errored</reset>") - } - - return status -} - -func renderJobs(number int64) string { - return humanize.Comma(int64(number)) -} - -func renderAlive(t time.Time) string { - return humanize.RelTime(t, time.Now(), "ago", "") -} - -func renderMemory(pid int) string { - p, _ := process.NewProcess(int32(pid)) - i, err := p.MemoryInfo() - if err != nil { - return err.Error() - } - - return humanize.Bytes(i.RSS) + util.WorkerTable(r.Workers).Render() } diff --git a/cmd/rr/utils/cprint.go b/cmd/rr/util/cprint.go index 020975ec..0985de62 100644 --- a/cmd/rr/utils/cprint.go +++ b/cmd/rr/util/cprint.go @@ -1,4 +1,4 @@ -package utils +package util import ( "fmt" diff --git a/cmd/rr/util/list.go b/cmd/rr/util/list.go new file mode 100644 index 00000000..4094ce44 --- /dev/null +++ b/cmd/rr/util/list.go @@ -0,0 +1,58 @@ +package util + +import ( + rrutil "github.com/spiral/roadrunner/util" + "github.com/olekukonko/tablewriter" + "os" + "strconv" + "github.com/dustin/go-humanize" + "time" +) + +// WorkerTable renders table with information about rr server workers. +func WorkerTable(workers []*rrutil.State) *tablewriter.Table { + tw := tablewriter.NewWriter(os.Stdout) + tw.SetHeader([]string{"PID", "Status", "Execs", "Memory", "Created"}) + tw.SetColMinWidth(0, 7) + tw.SetColMinWidth(1, 9) + tw.SetColMinWidth(2, 7) + tw.SetColMinWidth(3, 7) + tw.SetColMinWidth(4, 18) + + for _, w := range workers { + tw.Append([]string{ + strconv.Itoa(w.Pid), + renderStatus(w.Status), + renderJobs(w.NumJobs), + humanize.Bytes(w.MemoryUsage), + renderAlive(time.Unix(0, w.Created)), + }) + } + + return tw +} + +func renderStatus(status string) string { + switch status { + case "inactive": + return Sprintf("<yellow>inactive</reset>") + case "ready": + return Sprintf("<cyan>ready</reset>") + case "working": + return Sprintf("<green>working</reset>") + case "stopped": + return Sprintf("<red>stopped</reset>") + case "errored": + return Sprintf("<red>errored</reset>") + } + + return status +} + +func renderJobs(number int64) string { + return humanize.Comma(int64(number)) +} + +func renderAlive(t time.Time) string { + return humanize.RelTime(t, time.Now(), "ago", "") +} diff --git a/service/http/rpc.go b/service/http/rpc.go index 9dfe718e..08b3f262 100644 --- a/service/http/rpc.go +++ b/service/http/rpc.go @@ -2,6 +2,7 @@ package http import ( "github.com/pkg/errors" + "github.com/spiral/roadrunner/util" ) type rpcServer struct{ svc *Service } @@ -9,22 +10,7 @@ type rpcServer struct{ svc *Service } // WorkerList contains list of workers. type WorkerList struct { // Workers is list of workers. - Workers []Worker `json:"workers"` -} - -// Worker provides information about specific worker. -type Worker struct { - // Pid contains process id. - Pid int `json:"pid"` - - // Status of the worker. - Status string `json:"status"` - - // Number of worker executions. - NumJobs int64 `json:"numExecs"` - - // Created is unix nano timestamp of worker creation time. - Created int64 `json:"created"` + Workers []*util.State `json:"workers"` } // Reset resets underlying RR worker pool and restarts all of it's workers. @@ -38,20 +24,11 @@ func (rpc *rpcServer) Reset(reset bool, r *string) error { } // Workers returns list of active workers and their stats. -func (rpc *rpcServer) Workers(list bool, r *WorkerList) error { +func (rpc *rpcServer) Workers(list bool, r *WorkerList) (err error) { if rpc.svc == nil || rpc.svc.srv == nil { return errors.New("http server is not running") } - for _, w := range rpc.svc.rr.Workers() { - state := w.State() - r.Workers = append(r.Workers, Worker{ - Pid: *w.Pid, - Status: state.String(), - NumJobs: state.NumExecs(), - Created: w.Created.UnixNano(), - }) - } - - return nil + r.Workers, err = util.ServerState(rpc.svc.rr) + return err } diff --git a/util/state.go b/util/state.go new file mode 100644 index 00000000..3984d72d --- /dev/null +++ b/util/state.go @@ -0,0 +1,62 @@ +package util + +import ( + "github.com/shirou/gopsutil/process" + "github.com/spiral/roadrunner" + "errors" +) + +// State provides information about specific worker. +type State struct { + // Pid contains process id. + Pid int `json:"pid"` + + // Status of the worker. + Status string `json:"status"` + + // Number of worker executions. + NumJobs int64 `json:"numExecs"` + + // Created is unix nano timestamp of worker creation time. + Created int64 `json:"created"` + + // MemoryUsage holds the information about worker memory usage in bytes. + // Values might vary for different operating systems and based on RSS. + MemoryUsage uint64 `json:"memoryUsage"` +} + +// WorkerState creates new worker state definition. +func WorkerState(w *roadrunner.Worker) (*State, error) { + p, _ := process.NewProcess(int32(*w.Pid)) + i, err := p.MemoryInfo() + if err != nil { + return nil, err + } + + return &State{ + Pid: *w.Pid, + Status: w.State().String(), + NumJobs: w.State().NumExecs(), + Created: w.Created.UnixNano(), + MemoryUsage: i.RSS, + }, nil +} + +// ServerState returns list of all worker states of a given rr server. +func ServerState(rr *roadrunner.Server) ([]*State, error) { + if rr == nil { + return nil, errors.New("rr server is not running") + } + + result := make([]*State, 0) + for _, w := range rr.Workers() { + state, err := WorkerState(w) + if err != nil { + return nil, err + } + + result = append(result, state) + } + + return result, nil +} |