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 @@
package api
import (
"fmt"
"net/http"
"time"
......@@ -16,9 +17,10 @@ type metrics struct {
// all metrics fields must be exported
// to be able to return them by Metrics()
// using reflection
RequestCount prometheus.Counter
ResponseDuration prometheus.Histogram
PingRequestCount prometheus.Counter
RequestCount prometheus.Counter
ResponseDuration prometheus.Histogram
PingRequestCount prometheus.Counter
ResponseCodeCounts *prometheus.CounterVec
}
func newMetrics() metrics {
......@@ -38,6 +40,15 @@ func newMetrics() metrics {
Help: "Histogram of API response durations.",
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 {
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() {
httpaccess.NewHTTPAccessLogHandler(s.logger, logrus.InfoLevel, s.tracer, "api access"),
handlers.CompressHandler,
// todo: add recovery handler
s.responseCodeMetricsHandler,
s.pageviewMetricsHandler,
func(h http.Handler) http.Handler {
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