Skip to content

Commit

Permalink
fix: panic when negroni middleware method is missing (#418)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr authored Oct 24, 2021
1 parent ceab011 commit bdd5bc1
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 17 deletions.
27 changes: 27 additions & 0 deletions httpx/assert.go
Original file line number Diff line number Diff line change
@@ -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
}
12 changes: 8 additions & 4 deletions metricsx/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import (
"sync"
"time"

"github.com/ory/x/httpx"

"google.golang.org/grpc"
"google.golang.org/grpc/status"

Expand All @@ -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"
)
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
23 changes: 10 additions & 13 deletions prometheusx/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
}

Expand All @@ -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)
Expand Down

0 comments on commit bdd5bc1

Please sign in to comment.