Commit a2695a57 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #1995 from ethereum-optimism/inphi/proxyd-metrics

go/proxyd: Add request/response payload size metrics
parents 89eab8f7 025a3c0d
---
'@eth-optimism/proxyd': minor
---
Add request/response payload size metrics to proxyd
...@@ -2,10 +2,11 @@ package proxyd ...@@ -2,10 +2,11 @@ package proxyd
import ( import (
"context" "context"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"strconv" "strconv"
"strings" "strings"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
) )
const ( const (
...@@ -20,6 +21,8 @@ const ( ...@@ -20,6 +21,8 @@ const (
MethodUnknown = "unknown" MethodUnknown = "unknown"
) )
var PayloadSizeBuckets = []float64{10, 50, 100, 500, 1000, 5000, 10000, 100000, 1000000}
var ( var (
rpcRequestsTotal = promauto.NewCounter(prometheus.CounterOpts{ rpcRequestsTotal = promauto.NewCounter(prometheus.CounterOpts{
Namespace: MetricsNamespace, Namespace: MetricsNamespace,
...@@ -139,6 +142,25 @@ var ( ...@@ -139,6 +142,25 @@ var (
"source", "source",
}) })
requestPayloadSizesGauge = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: MetricsNamespace,
Name: "request_payload_sizes",
Help: "Gauge of client request payload sizes.",
Buckets: PayloadSizeBuckets,
}, []string{
"auth",
"method_name",
})
responsePayloadSizesGauge = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: MetricsNamespace,
Name: "response_payload_sizes",
Help: "Gauge of client response payload sizes.",
Buckets: PayloadSizeBuckets,
}, []string{
"auth",
})
rpcSpecialErrors = []string{ rpcSpecialErrors = []string{
"nonce too low", "nonce too low",
"gas price too high", "gas price too high",
...@@ -185,3 +207,11 @@ func MaybeRecordSpecialRPCError(ctx context.Context, backendName, method string, ...@@ -185,3 +207,11 @@ func MaybeRecordSpecialRPCError(ctx context.Context, backendName, method string,
} }
} }
} }
func RecordRequestPayloadSize(ctx context.Context, method string, payloadSize int) {
requestPayloadSizesGauge.WithLabelValues(GetAuthCtx(ctx), method).Observe(float64(payloadSize))
}
func RecordResponsePayloadSize(ctx context.Context, payloadSize int) {
responsePayloadSizesGauge.WithLabelValues(GetAuthCtx(ctx)).Observe(float64(payloadSize))
}
...@@ -116,13 +116,15 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) { ...@@ -116,13 +116,15 @@ func (s *Server) HandleRPC(w http.ResponseWriter, r *http.Request) {
"user_agent", r.Header.Get("user-agent"), "user_agent", r.Header.Get("user-agent"),
) )
req, err := ParseRPCReq(io.LimitReader(r.Body, s.maxBodySize)) bodyReader := &recordLenReader{Reader: io.LimitReader(r.Body, s.maxBodySize)}
req, err := ParseRPCReq(bodyReader)
if err != nil { if err != nil {
log.Info("rejected request with bad rpc request", "source", "rpc", "err", err) log.Info("rejected request with bad rpc request", "source", "rpc", "err", err)
RecordRPCError(ctx, BackendProxyd, MethodUnknown, err) RecordRPCError(ctx, BackendProxyd, MethodUnknown, err)
writeRPCError(ctx, w, nil, err) writeRPCError(ctx, w, nil, err)
return return
} }
RecordRequestPayloadSize(ctx, req.Method, bodyReader.Len)
group := s.rpcMethodMappings[req.Method] group := s.rpcMethodMappings[req.Method]
if group == "" { if group == "" {
...@@ -249,14 +251,17 @@ func writeRPCRes(ctx context.Context, w http.ResponseWriter, res *RPCRes) { ...@@ -249,14 +251,17 @@ func writeRPCRes(ctx context.Context, w http.ResponseWriter, res *RPCRes) {
if res.IsError() && res.Error.HTTPErrorCode != 0 { if res.IsError() && res.Error.HTTPErrorCode != 0 {
statusCode = res.Error.HTTPErrorCode statusCode = res.Error.HTTPErrorCode
} }
w.WriteHeader(statusCode) w.WriteHeader(statusCode)
enc := json.NewEncoder(w) ww := &recordLenWriter{Writer: w}
enc := json.NewEncoder(ww)
if err := enc.Encode(res); err != nil { if err := enc.Encode(res); err != nil {
log.Error("error writing rpc response", "err", err) log.Error("error writing rpc response", "err", err)
RecordRPCError(ctx, BackendProxyd, MethodUnknown, err) RecordRPCError(ctx, BackendProxyd, MethodUnknown, err)
return return
} }
httpResponseCodesTotal.WithLabelValues(strconv.Itoa(statusCode)).Inc() httpResponseCodesTotal.WithLabelValues(strconv.Itoa(statusCode)).Inc()
RecordResponsePayloadSize(ctx, ww.Len)
} }
func instrumentedHdlr(h http.Handler) http.HandlerFunc { func instrumentedHdlr(h http.Handler) http.HandlerFunc {
...@@ -291,3 +296,25 @@ func GetXForwardedFor(ctx context.Context) string { ...@@ -291,3 +296,25 @@ func GetXForwardedFor(ctx context.Context) string {
} }
return xff return xff
} }
type recordLenReader struct {
io.Reader
Len int
}
func (r *recordLenReader) Read(p []byte) (n int, err error) {
n, err = r.Reader.Read(p)
r.Len += n
return
}
type recordLenWriter struct {
io.Writer
Len int
}
func (w *recordLenWriter) Write(p []byte) (n int, err error) {
n, err = w.Writer.Write(p)
w.Len += n
return
}
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