grafana/pkg/middleware/request_metrics.go
Carl Bergquist b0b46991ec
Metrics: Add gauge for requests currently in flight (#22168)
Add gauge for requests currently in flight.

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
2020-02-19 18:29:47 +01:00

221 lines
4.1 KiB
Go

package middleware
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/prometheus/client_golang/prometheus"
"gopkg.in/macaron.v1"
)
var (
httpRequestsInFlight prometheus.Gauge
)
func init() {
httpRequestsInFlight = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "http_request_in_flight",
Help: "A gauge of requests currently being served by Grafana.",
},
)
prometheus.MustRegister(httpRequestsInFlight)
}
// RequestMetrics is a middleware handler that instruments the request
func RequestMetrics(handler string) macaron.Handler {
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
rw := res.(macaron.ResponseWriter)
now := time.Now()
httpRequestsInFlight.Inc()
defer httpRequestsInFlight.Dec()
c.Next()
status := rw.Status()
code := sanitizeCode(status)
method := sanitizeMethod(req.Method)
metrics.MHttpRequestTotal.WithLabelValues(handler, code, method).Inc()
duration := time.Since(now).Nanoseconds() / int64(time.Millisecond)
metrics.MHttpRequestSummary.WithLabelValues(handler, code, method).Observe(float64(duration))
if strings.HasPrefix(req.RequestURI, "/api/datasources/proxy") {
countProxyRequests(status)
} else if strings.HasPrefix(req.RequestURI, "/api/") {
countApiRequests(status)
} else {
countPageRequests(status)
}
}
}
func countApiRequests(status int) {
switch status {
case 200:
metrics.MApiStatus.WithLabelValues("200").Inc()
case 404:
metrics.MApiStatus.WithLabelValues("404").Inc()
case 500:
metrics.MApiStatus.WithLabelValues("500").Inc()
default:
metrics.MApiStatus.WithLabelValues("unknown").Inc()
}
}
func countPageRequests(status int) {
switch status {
case 200:
metrics.MPageStatus.WithLabelValues("200").Inc()
case 404:
metrics.MPageStatus.WithLabelValues("404").Inc()
case 500:
metrics.MPageStatus.WithLabelValues("500").Inc()
default:
metrics.MPageStatus.WithLabelValues("unknown").Inc()
}
}
func countProxyRequests(status int) {
switch status {
case 200:
metrics.MProxyStatus.WithLabelValues("200").Inc()
case 404:
metrics.MProxyStatus.WithLabelValues("400").Inc()
case 500:
metrics.MProxyStatus.WithLabelValues("500").Inc()
default:
metrics.MProxyStatus.WithLabelValues("unknown").Inc()
}
}
func sanitizeMethod(m string) string {
switch m {
case "GET", "get":
return "get"
case "PUT", "put":
return "put"
case "HEAD", "head":
return "head"
case "POST", "post":
return "post"
case "DELETE", "delete":
return "delete"
case "CONNECT", "connect":
return "connect"
case "OPTIONS", "options":
return "options"
case "NOTIFY", "notify":
return "notify"
default:
return strings.ToLower(m)
}
}
// If the wrapped http.Handler has not set a status code, i.e. the value is
// currently 0, santizeCode will return 200, for consistency with behavior in
// the stdlib.
func sanitizeCode(s int) string {
switch s {
case 100:
return "100"
case 101:
return "101"
case 200, 0:
return "200"
case 201:
return "201"
case 202:
return "202"
case 203:
return "203"
case 204:
return "204"
case 205:
return "205"
case 206:
return "206"
case 300:
return "300"
case 301:
return "301"
case 302:
return "302"
case 304:
return "304"
case 305:
return "305"
case 307:
return "307"
case 400:
return "400"
case 401:
return "401"
case 402:
return "402"
case 403:
return "403"
case 404:
return "404"
case 405:
return "405"
case 406:
return "406"
case 407:
return "407"
case 408:
return "408"
case 409:
return "409"
case 410:
return "410"
case 411:
return "411"
case 412:
return "412"
case 413:
return "413"
case 414:
return "414"
case 415:
return "415"
case 416:
return "416"
case 417:
return "417"
case 418:
return "418"
case 500:
return "500"
case 501:
return "501"
case 502:
return "502"
case 503:
return "503"
case 504:
return "504"
case 505:
return "505"
case 428:
return "428"
case 429:
return "429"
case 431:
return "431"
case 511:
return "511"
default:
return strconv.Itoa(s)
}
}