diff options
author | Anton Titov <[email protected]> | 2019-06-27 13:00:34 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2019-06-27 13:00:34 +0300 |
commit | ce7f331a5e6c6129331e06224865abdb1298584d (patch) | |
tree | 4fdf5b9158cf481ee77c408ea8d57d83a7e692f3 /cmd/rr/http | |
parent | 5b6e0a535fef745594a4966c724509dcda05b422 (diff) | |
parent | 1633d128309765536e7cbb176225926efda7a33c (diff) |
Merge pull request #168 from spiral/feature/metrics
Feature/metrics
Diffstat (limited to 'cmd/rr/http')
-rw-r--r-- | cmd/rr/http/metrics.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/cmd/rr/http/metrics.go b/cmd/rr/http/metrics.go new file mode 100644 index 00000000..21bbbaf1 --- /dev/null +++ b/cmd/rr/http/metrics.go @@ -0,0 +1,123 @@ +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) + } +} |