Commit e70e762b authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #1660 from mslipper/feature/proxy-method-metrics

Add proxy method metrics
parents e7159d5d 8cc824e5
---
'@eth-optimism/proxyd': minor
---
Updates proxyd to include additional error metrics.
...@@ -31,7 +31,8 @@ var ( ...@@ -31,7 +31,8 @@ var (
Name: "backend_requests_total", Name: "backend_requests_total",
Help: "Count of backend requests.", Help: "Count of backend requests.",
}, []string{ }, []string{
"name", "backend_name",
"method_name",
}) })
backendErrorsCtr = promauto.NewCounterVec(prometheus.CounterOpts{ backendErrorsCtr = promauto.NewCounterVec(prometheus.CounterOpts{
...@@ -39,7 +40,8 @@ var ( ...@@ -39,7 +40,8 @@ var (
Name: "backend_errors_total", Name: "backend_errors_total",
Help: "Count of backend errors.", Help: "Count of backend errors.",
}, []string{ }, []string{
"name", "backend_name",
"method_name",
}) })
backendPermanentErrorsCtr = promauto.NewCounterVec(prometheus.CounterOpts{ backendPermanentErrorsCtr = promauto.NewCounterVec(prometheus.CounterOpts{
...@@ -47,7 +49,18 @@ var ( ...@@ -47,7 +49,18 @@ var (
Name: "backend_permanent_errors_total", Name: "backend_permanent_errors_total",
Help: "Count of backend errors that mark a backend as offline.", Help: "Count of backend errors that mark a backend as offline.",
}, []string{ }, []string{
"name", "backend_name",
"method_name",
})
backendResponseTimeSummary = promauto.NewSummaryVec(prometheus.SummaryOpts{
Namespace: "proxyd",
Name: "backend_response_time_seconds",
Help: "Summary of backend response times broken down by backend and method name.",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
}, []string{
"backend_name",
"method_name",
}) })
) )
...@@ -113,7 +126,7 @@ func NewBackend(name, baseURL string, opts ...BackendOpt) *Backend { ...@@ -113,7 +126,7 @@ func NewBackend(name, baseURL string, opts ...BackendOpt) *Backend {
return backend return backend
} }
func (b *Backend) Forward(body []byte) (*RPCRes, error) { func (b *Backend) Forward(req *RPCReq) (*RPCRes, error) {
if time.Now().Unix()-atomic.LoadInt64(&b.lastPermError) < b.unhealthyRetryInterval { if time.Now().Unix()-atomic.LoadInt64(&b.lastPermError) < b.unhealthyRetryInterval {
return nil, ErrBackendOffline return nil, ErrBackendOffline
} }
...@@ -122,7 +135,7 @@ func (b *Backend) Forward(body []byte) (*RPCRes, error) { ...@@ -122,7 +135,7 @@ func (b *Backend) Forward(body []byte) (*RPCRes, error) {
// <= to account for the first attempt not technically being // <= to account for the first attempt not technically being
// a retry // a retry
for i := 0; i <= b.maxRetries; i++ { for i := 0; i <= b.maxRetries; i++ {
resB, err := b.doForward(body) resB, err := b.doForward(req)
if err != nil { if err != nil {
lastError = err lastError = err
log.Warn("backend request failed, trying again", "err", err, "name", b.Name) log.Warn("backend request failed, trying again", "err", err, "name", b.Name)
...@@ -140,40 +153,47 @@ func (b *Backend) Forward(body []byte) (*RPCRes, error) { ...@@ -140,40 +153,47 @@ func (b *Backend) Forward(body []byte) (*RPCRes, error) {
} }
atomic.StoreInt64(&b.lastPermError, time.Now().Unix()) atomic.StoreInt64(&b.lastPermError, time.Now().Unix())
backendPermanentErrorsCtr.WithLabelValues(b.Name).Inc() backendPermanentErrorsCtr.WithLabelValues(b.Name, req.Method).Inc()
return nil, wrapErr(lastError, "permanent error forwarding request") return nil, wrapErr(lastError, "permanent error forwarding request")
} }
func (b *Backend) doForward(body []byte) ([]byte, error) { func (b *Backend) doForward(rpcReq *RPCReq) ([]byte, error) {
req, err := http.NewRequest("POST", b.baseURL, bytes.NewReader(body)) body, err := json.Marshal(rpcReq)
if err != nil {
return nil, wrapErr(err, "error marshaling request in forward")
}
httpReq, err := http.NewRequest("POST", b.baseURL, bytes.NewReader(body))
if err != nil { if err != nil {
backendErrorsCtr.WithLabelValues(b.Name).Inc() backendErrorsCtr.WithLabelValues(b.Name, rpcReq.Method).Inc()
return nil, wrapErr(err, "error creating backend request") return nil, wrapErr(err, "error creating backend request")
} }
if b.authPassword != "" { if b.authPassword != "" {
req.SetBasicAuth(b.authUsername, b.authPassword) httpReq.SetBasicAuth(b.authUsername, b.authPassword)
} }
res, err := b.client.Do(req) timer := prometheus.NewTimer(backendResponseTimeSummary.WithLabelValues(b.Name, rpcReq.Method))
defer timer.ObserveDuration()
defer backendRequestsCtr.WithLabelValues(b.Name, rpcReq.Method).Inc()
res, err := b.client.Do(httpReq)
if err != nil { if err != nil {
backendErrorsCtr.WithLabelValues(b.Name).Inc() backendErrorsCtr.WithLabelValues(b.Name, rpcReq.Method).Inc()
return nil, wrapErr(err, "error in backend request") return nil, wrapErr(err, "error in backend request")
} }
if res.StatusCode != 200 { if res.StatusCode != 200 {
backendErrorsCtr.WithLabelValues(b.Name).Inc() backendErrorsCtr.WithLabelValues(b.Name, rpcReq.Method).Inc()
return nil, fmt.Errorf("response code %d", res.StatusCode) return nil, fmt.Errorf("response code %d", res.StatusCode)
} }
defer res.Body.Close() defer res.Body.Close()
resB, err := ioutil.ReadAll(io.LimitReader(res.Body, b.maxResponseSize)) resB, err := ioutil.ReadAll(io.LimitReader(res.Body, b.maxResponseSize))
if err != nil { if err != nil {
backendErrorsCtr.WithLabelValues(b.Name).Inc() backendErrorsCtr.WithLabelValues(b.Name, rpcReq.Method).Inc()
return nil, wrapErr(err, "error reading response body") return nil, wrapErr(err, "error reading response body")
} }
backendRequestsCtr.WithLabelValues(b.Name).Inc()
return resB, nil return resB, nil
} }
...@@ -183,10 +203,10 @@ type BackendGroup struct { ...@@ -183,10 +203,10 @@ type BackendGroup struct {
i int64 i int64
} }
func (b *BackendGroup) Forward(body []byte) (*RPCRes, error) { func (b *BackendGroup) Forward(rpcReq *RPCReq) (*RPCRes, error) {
var outRes *RPCRes var outRes *RPCRes
for _, back := range b.backends { for _, back := range b.backends {
res, err := back.Forward(body) res, err := back.Forward(rpcReq)
if err == ErrBackendOffline { if err == ErrBackendOffline {
log.Debug("skipping offline backend", "name", back.Name) log.Debug("skipping offline backend", "name", back.Name)
continue continue
......
...@@ -12,7 +12,6 @@ import ( ...@@ -12,7 +12,6 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"time"
) )
var ( var (
...@@ -22,17 +21,11 @@ var ( ...@@ -22,17 +21,11 @@ var (
Help: "Count of total HTTP requests.", Help: "Count of total HTTP requests.",
}) })
httpRequestDurationHisto = promauto.NewHistogram(prometheus.HistogramOpts{ httpRequestDurationSummary = promauto.NewSummary(prometheus.SummaryOpts{
Namespace: "proxyd", Namespace: "proxyd",
Name: "http_request_duration_histogram_seconds", Name: "http_request_duration_seconds",
Help: "Histogram of HTTP request durations.", Help: "Summary of HTTP request durations, in seconds.",
Buckets: []float64{ Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
0,
0.1,
0.25,
0.75,
1,
},
}) })
rpcRequestsCtr = promauto.NewCounterVec(prometheus.CounterOpts{ rpcRequestsCtr = promauto.NewCounterVec(prometheus.CounterOpts{
...@@ -142,7 +135,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) { ...@@ -142,7 +135,7 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
return return
} }
backendRes, err := group.Forward(body) backendRes, err := group.Forward(req)
if err != nil { if err != nil {
log.Error("error forwarding RPC request", "group", group.Name, "method", req.Method, "err", err) log.Error("error forwarding RPC request", "group", group.Name, "method", req.Method, "err", err)
rpcErrorsCtr.WithLabelValues("-32603").Inc() rpcErrorsCtr.WithLabelValues("-32603").Inc()
...@@ -181,9 +174,8 @@ func writeRPCError(w http.ResponseWriter, id *int, code int, msg string) { ...@@ -181,9 +174,8 @@ func writeRPCError(w http.ResponseWriter, id *int, code int, msg string) {
func instrumentedHdlr(h http.Handler) http.HandlerFunc { func instrumentedHdlr(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
httpRequestsCtr.Inc() httpRequestsCtr.Inc()
start := time.Now() timer := prometheus.NewTimer(httpRequestDurationSummary)
defer timer.ObserveDuration()
h.ServeHTTP(w, r) h.ServeHTTP(w, r)
dur := time.Since(start)
httpRequestDurationHisto.Observe(float64(dur) / float64(time.Second))
} }
} }
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