Commit dda4d163 authored by Alok Nerurkar's avatar Alok Nerurkar Committed by GitHub

API metrics - HTTP response code counts (#1600)

parent 84f54d73
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package api package api
import ( import (
"fmt"
"net/http" "net/http"
"time" "time"
...@@ -16,9 +17,10 @@ type metrics struct { ...@@ -16,9 +17,10 @@ type metrics struct {
// all metrics fields must be exported // all metrics fields must be exported
// to be able to return them by Metrics() // to be able to return them by Metrics()
// using reflection // using reflection
RequestCount prometheus.Counter RequestCount prometheus.Counter
ResponseDuration prometheus.Histogram ResponseDuration prometheus.Histogram
PingRequestCount prometheus.Counter PingRequestCount prometheus.Counter
ResponseCodeCounts *prometheus.CounterVec
} }
func newMetrics() metrics { func newMetrics() metrics {
...@@ -38,6 +40,15 @@ func newMetrics() metrics { ...@@ -38,6 +40,15 @@ func newMetrics() metrics {
Help: "Histogram of API response durations.", Help: "Histogram of API response durations.",
Buckets: []float64{0.01, 0.1, 0.25, 0.5, 1, 2.5, 5, 10}, Buckets: []float64{0.01, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},
}), }),
ResponseCodeCounts: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: m.Namespace,
Subsystem: subsystem,
Name: "response_code_count",
Help: "Response count grouped by status code",
},
[]string{"code", "method"},
),
} }
} }
...@@ -53,3 +64,50 @@ func (s *server) pageviewMetricsHandler(h http.Handler) http.Handler { ...@@ -53,3 +64,50 @@ func (s *server) pageviewMetricsHandler(h http.Handler) http.Handler {
s.metrics.ResponseDuration.Observe(time.Since(start).Seconds()) s.metrics.ResponseDuration.Observe(time.Since(start).Seconds())
}) })
} }
func (s *server) responseCodeMetricsHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
wrapper := newResponseWriter(w)
h.ServeHTTP(wrapper, r)
s.metrics.ResponseCodeCounts.WithLabelValues(
fmt.Sprintf("%d", wrapper.statusCode),
r.Method,
).Inc()
})
}
// UpgradedResponseWriter adds more functionality on top of ResponseWriter
type UpgradedResponseWriter interface {
http.ResponseWriter
http.Pusher
http.Hijacker
http.Flusher
// staticcheck SA1019 CloseNotifier interface is required by gorilla compress handler
// nolint:staticcheck
http.CloseNotifier // skipcq: SCC-SA1019
}
type responseWriter struct {
UpgradedResponseWriter
statusCode int
wroteHeader bool
}
func newResponseWriter(w http.ResponseWriter) *responseWriter {
// StatusOK is called by default if nothing else is called
uw := w.(UpgradedResponseWriter)
return &responseWriter{uw, http.StatusOK, false}
}
func (rw *responseWriter) Status() int {
return rw.statusCode
}
func (rw *responseWriter) WriteHeader(code int) {
if rw.wroteHeader {
return
}
rw.statusCode = code
rw.UpgradedResponseWriter.WriteHeader(code)
rw.wroteHeader = true
}
...@@ -177,6 +177,7 @@ func (s *server) setupRouting() { ...@@ -177,6 +177,7 @@ func (s *server) setupRouting() {
httpaccess.NewHTTPAccessLogHandler(s.logger, logrus.InfoLevel, s.tracer, "api access"), httpaccess.NewHTTPAccessLogHandler(s.logger, logrus.InfoLevel, s.tracer, "api access"),
handlers.CompressHandler, handlers.CompressHandler,
// todo: add recovery handler // todo: add recovery handler
s.responseCodeMetricsHandler,
s.pageviewMetricsHandler, s.pageviewMetricsHandler,
func(h http.Handler) http.Handler { func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment