diff --git a/httpx/assert.go b/httpx/assert.go new file mode 100644 index 00000000..6076a823 --- /dev/null +++ b/httpx/assert.go @@ -0,0 +1,27 @@ +package httpx + +import ( + "net/http" + + "github.com/urfave/negroni" +) + +func GetResponseMeta(w http.ResponseWriter) (status, size int) { + switch t := w.(type) { + case interface { + Status() int + Written() int64 + }: + return t.Status(), int(t.Written()) + case negroni.ResponseWriter: + return t.Status(), t.Size() + } + + if t, ok := w.(interface { + Status() int + }); ok { + return t.Status(), 0 + } + + return 0, 0 +} diff --git a/metricsx/middleware.go b/metricsx/middleware.go index de39c505..ee6fd54b 100644 --- a/metricsx/middleware.go +++ b/metricsx/middleware.go @@ -33,6 +33,8 @@ import ( "sync" "time" + "github.com/ory/x/httpx" + "google.golang.org/grpc" "google.golang.org/grpc/status" @@ -45,7 +47,6 @@ import ( "github.com/ory/x/resilience" "github.com/pborman/uuid" - "github.com/urfave/negroni" analytics "github.com/ory/analytics-go/v4" ) @@ -245,6 +246,11 @@ func (sw *Service) ObserveMemory() { } } +type negroniMiddleware interface { + Size() int + Status() int +} + // ServeHTTP is a middleware for sending meta information to segment. func (sw *Service) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { var start time.Time @@ -269,9 +275,7 @@ func (sw *Service) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http. query := sw.anonymizeQuery(r.URL.Query(), sw.salt) // Collecting request info - res := rw.(negroni.ResponseWriter) - stat := res.Status() - size := res.Size() + stat, size := httpx.GetResponseMeta(rw) if err := sw.c.Enqueue(analytics.Page{ UserId: sw.o.ClusterID, diff --git a/prometheusx/metrics.go b/prometheusx/metrics.go index b90e37bf..9bb08731 100644 --- a/prometheusx/metrics.go +++ b/prometheusx/metrics.go @@ -4,10 +4,11 @@ import ( "net/http" "strconv" + "github.com/ory/x/httpx" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/urfave/negroni" ) // Metrics prototypes @@ -106,20 +107,17 @@ func (h Metrics) instrumentHandlerStatusBucket(next http.Handler) http.HandlerFu return func(rw http.ResponseWriter, r *http.Request) { next.ServeHTTP(rw, r) - res, ok := rw.(negroni.ResponseWriter) - if !ok { - return - } + status, _ := httpx.GetResponseMeta(rw) statusBucket := "unknown" switch { - case res.Status() >= 200 && res.Status() <= 299: + case status >= 200 && status <= 299: statusBucket = "2xx" - case res.Status() >= 300 && res.Status() <= 399: + case status >= 300 && status <= 399: statusBucket = "3xx" - case res.Status() >= 400 && res.Status() <= 499: + case status >= 400 && status <= 499: statusBucket = "4xx" - case res.Status() >= 500 && res.Status() <= 599: + case status >= 500 && status <= 599: statusBucket = "5xx" } @@ -131,10 +129,9 @@ func (h Metrics) instrumentHandlerStatusBucket(next http.Handler) http.HandlerFu // Instrument will instrument any http.HandlerFunc with custom metrics func (h Metrics) Instrument(rw http.ResponseWriter, next http.HandlerFunc, endpoint string) http.HandlerFunc { labels := prometheus.Labels{} - res, ok := rw.(negroni.ResponseWriter) - if ok && res.Status() != 0 { - labels = prometheus.Labels{"code": strconv.Itoa(res.Status())} - } + status, _ := httpx.GetResponseMeta(rw) + + labels = prometheus.Labels{"code": strconv.Itoa(status)} wrapped := promhttp.InstrumentHandlerResponseSize(h.responseSize.MustCurryWith(labels), next) wrapped = promhttp.InstrumentHandlerCounter(h.totalRequests.MustCurryWith(labels), wrapped) wrapped = promhttp.InstrumentHandlerDuration(h.duration.MustCurryWith(labels), wrapped)