diff options
Diffstat (limited to 'cmd/rr/http')
-rw-r--r-- | cmd/rr/http/debug.go | 138 | ||||
-rw-r--r-- | cmd/rr/http/metrics.go | 123 | ||||
-rw-r--r-- | cmd/rr/http/reset.go | 53 | ||||
-rw-r--r-- | cmd/rr/http/workers.go | 100 |
4 files changed, 0 insertions, 414 deletions
diff --git a/cmd/rr/http/debug.go b/cmd/rr/http/debug.go deleted file mode 100644 index ae383e8d..00000000 --- a/cmd/rr/http/debug.go +++ /dev/null @@ -1,138 +0,0 @@ -package http - -import ( - "fmt" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/spiral/roadrunner" - rr "github.com/spiral/roadrunner/cmd/rr/cmd" - "github.com/spiral/roadrunner/cmd/util" - rrhttp "github.com/spiral/roadrunner/service/http" - "net" - "net/http" - "strings" - "time" -) - -func init() { - cobra.OnInitialize(func() { - if rr.Debug { - svc, _ := rr.Container.Get(rrhttp.ID) - if svc, ok := svc.(*rrhttp.Service); ok { - svc.AddListener((&debugger{logger: rr.Logger}).listener) - } - } - }) -} - -// listener provide debug callback for system events. With colors! -type debugger struct{ logger *logrus.Logger } - -// listener listens to http events and generates nice looking output. -func (s *debugger) listener(event int, ctx interface{}) { - if util.LogEvent(s.logger, event, ctx) { - // handler by default debug package - return - } - - // http events - switch event { - case rrhttp.EventResponse: - e := ctx.(*rrhttp.ResponseEvent) - s.logger.Info(util.Sprintf( - "<cyan+h>%s</reset> %s %s <white+hb>%s</reset> %s", - e.Request.RemoteAddr, - elapsed(e.Elapsed()), - statusColor(e.Response.Status), - e.Request.Method, - e.Request.URI, - )) - - case rrhttp.EventError: - e := ctx.(*rrhttp.ErrorEvent) - - if _, ok := e.Error.(roadrunner.JobError); ok { - s.logger.Info(util.Sprintf( - "<cyan+h>%s</reset> %s %s <white+hb>%s</reset> %s", - addr(e.Request.RemoteAddr), - elapsed(e.Elapsed()), - statusColor(500), - e.Request.Method, - uri(e.Request), - )) - } else { - s.logger.Info(util.Sprintf( - "<cyan+h>%s</reset> %s %s <white+hb>%s</reset> %s <red>%s</reset>", - addr(e.Request.RemoteAddr), - elapsed(e.Elapsed()), - statusColor(500), - e.Request.Method, - uri(e.Request), - e.Error, - )) - } - } -} - -func statusColor(status int) string { - if status < 300 { - return util.Sprintf("<green>%v</reset>", status) - } - - if status < 400 { - return util.Sprintf("<cyan>%v</reset>", status) - } - - if status < 500 { - return util.Sprintf("<yellow>%v</reset>", status) - } - - return util.Sprintf("<red>%v</reset>", status) -} - -func uri(r *http.Request) string { - if r.TLS != nil { - return fmt.Sprintf("https://%s%s", r.Host, r.URL.String()) - } - - return fmt.Sprintf("http://%s%s", r.Host, r.URL.String()) -} - -// fits duration into 5 characters -func elapsed(d time.Duration) string { - var v string - switch { - case d > 100*time.Second: - v = fmt.Sprintf("%.1fs", d.Seconds()) - case d > 10*time.Second: - v = fmt.Sprintf("%.2fs", d.Seconds()) - case d > time.Second: - v = fmt.Sprintf("%.3fs", d.Seconds()) - case d > 100*time.Millisecond: - v = fmt.Sprintf("%.0fms", d.Seconds()*1000) - case d > 10*time.Millisecond: - v = fmt.Sprintf("%.1fms", d.Seconds()*1000) - default: - v = fmt.Sprintf("%.2fms", d.Seconds()*1000) - } - - if d > time.Second { - return util.Sprintf("<red>{%v}</reset>", v) - } - - if d > time.Millisecond*500 { - return util.Sprintf("<yellow>{%v}</reset>", v) - } - - return util.Sprintf("<gray+hb>{%v}</reset>", v) -} - -func addr(addr string) string { - // otherwise, return remote address as is - if !strings.ContainsRune(addr, ':') { - return addr - } - - addr, _, _ = net.SplitHostPort(addr) - return addr -} diff --git a/cmd/rr/http/metrics.go b/cmd/rr/http/metrics.go deleted file mode 100644 index 21bbbaf1..00000000 --- a/cmd/rr/http/metrics.go +++ /dev/null @@ -1,123 +0,0 @@ -package http - -import ( - "github.com/prometheus/client_golang/prometheus" - "github.com/spf13/cobra" - rr "github.com/spiral/roadrunner/cmd/rr/cmd" - rrhttp "github.com/spiral/roadrunner/service/http" - "github.com/spiral/roadrunner/service/metrics" - "github.com/spiral/roadrunner/util" - "strconv" - "time" -) - -func init() { - cobra.OnInitialize(func() { - svc, _ := rr.Container.Get(metrics.ID) - mtr, ok := svc.(*metrics.Service) - if !ok || !mtr.Enabled() { - return - } - - ht, _ := rr.Container.Get(rrhttp.ID) - if ht, ok := ht.(*rrhttp.Service); ok { - collector := newCollector() - - // register metrics - mtr.MustRegister(collector.requestCounter) - mtr.MustRegister(collector.requestDuration) - mtr.MustRegister(collector.workersMemory) - - // collect events - ht.AddListener(collector.listener) - - // update memory usage every 10 seconds - go collector.collectMemory(ht, time.Second*10) - } - }) -} - -// listener provide debug callback for system events. With colors! -type metricCollector struct { - requestCounter *prometheus.CounterVec - requestDuration *prometheus.HistogramVec - workersMemory prometheus.Gauge -} - -func newCollector() *metricCollector { - return &metricCollector{ - requestCounter: prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "rr_http_request_total", - Help: "Total number of handled http requests after server restart.", - }, - []string{"status"}, - ), - requestDuration: prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "rr_http_request_duration_seconds", - Help: "HTTP request duration.", - }, - []string{"status"}, - ), - workersMemory: prometheus.NewGauge( - prometheus.GaugeOpts{ - Name: "rr_http_workers_memory_bytes", - Help: "Memory usage by HTTP workers.", - }, - ), - } -} - -// listener listens to http events and generates nice looking output. -func (c *metricCollector) listener(event int, ctx interface{}) { - // http events - switch event { - case rrhttp.EventResponse: - e := ctx.(*rrhttp.ResponseEvent) - - c.requestCounter.With(prometheus.Labels{ - "status": strconv.Itoa(e.Response.Status), - }).Inc() - - c.requestDuration.With(prometheus.Labels{ - "status": strconv.Itoa(e.Response.Status), - }).Observe(e.Elapsed().Seconds()) - - case rrhttp.EventError: - e := ctx.(*rrhttp.ErrorEvent) - - c.requestCounter.With(prometheus.Labels{ - "status": "500", - }).Inc() - - c.requestDuration.With(prometheus.Labels{ - "status": "500", - }).Observe(e.Elapsed().Seconds()) - } -} - -// collect memory usage by server workers -func (c *metricCollector) collectMemory(service *rrhttp.Service, tick time.Duration) { - started := false - for { - server := service.Server() - if server == nil && started { - // stopped - return - } - - started = true - - if workers, err := util.ServerState(server); err == nil { - sum := 0.0 - for _, w := range workers { - sum = sum + float64(w.MemoryUsage) - } - - c.workersMemory.Set(sum) - } - - time.Sleep(tick) - } -} diff --git a/cmd/rr/http/reset.go b/cmd/rr/http/reset.go deleted file mode 100644 index 3008848a..00000000 --- a/cmd/rr/http/reset.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2018 SpiralScout -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -package http - -import ( - "github.com/spf13/cobra" - rr "github.com/spiral/roadrunner/cmd/rr/cmd" - "github.com/spiral/roadrunner/cmd/util" -) - -func init() { - rr.CLI.AddCommand(&cobra.Command{ - Use: "http:reset", - Short: "Reload RoadRunner worker pool for the HTTP service", - RunE: reloadHandler, - }) -} - -func reloadHandler(cmd *cobra.Command, args []string) error { - client, err := util.RPCClient(rr.Container) - if err != nil { - return err - } - defer client.Close() - - util.Printf("<green>Restarting http worker pool</reset>: ") - - var r string - if err := client.Call("http.Reset", true, &r); err != nil { - return err - } - - util.Printf("<green+hb>done</reset>\n") - return nil -} diff --git a/cmd/rr/http/workers.go b/cmd/rr/http/workers.go deleted file mode 100644 index 4444b87f..00000000 --- a/cmd/rr/http/workers.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2018 SpiralScout -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -package http - -import ( - tm "github.com/buger/goterm" - "github.com/spf13/cobra" - rr "github.com/spiral/roadrunner/cmd/rr/cmd" - "github.com/spiral/roadrunner/cmd/util" - "github.com/spiral/roadrunner/service/http" - "net/rpc" - "os" - "os/signal" - "syscall" - "time" -) - -var ( - interactive bool - stopSignal = make(chan os.Signal, 1) -) - -func init() { - workersCommand := &cobra.Command{ - Use: "http:workers", - Short: "List workers associated with RoadRunner HTTP service", - RunE: workersHandler, - } - - workersCommand.Flags().BoolVarP( - &interactive, - "interactive", - "i", - false, - "render interactive workers table", - ) - - rr.CLI.AddCommand(workersCommand) - - signal.Notify(stopSignal, syscall.SIGTERM) - signal.Notify(stopSignal, syscall.SIGINT) -} - -func workersHandler(cmd *cobra.Command, args []string) (err error) { - defer func() { - if r, ok := recover().(error); ok { - err = r - } - }() - - client, err := util.RPCClient(rr.Container) - if err != nil { - return err - } - defer client.Close() - - if !interactive { - showWorkers(client) - return nil - } - - tm.Clear() - for { - select { - case <-stopSignal: - return nil - case <-time.NewTicker(time.Millisecond * 500).C: - tm.MoveCursor(1, 1) - showWorkers(client) - tm.Flush() - } - } -} - -func showWorkers(client *rpc.Client) { - var r http.WorkerList - if err := client.Call("http.Workers", true, &r); err != nil { - panic(err) - } - - util.WorkerTable(r.Workers).Render() -} |