Skip to content

Commit

Permalink
rpcserver: add server name
Browse files Browse the repository at this point in the history
  • Loading branch information
dvush committed Oct 30, 2024
1 parent 85a729f commit a80f258
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 35 deletions.
32 changes: 17 additions & 15 deletions rpcserver/jsonrpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type Methods map[string]any
type JSONRPCHandlerOpts struct {
// Logger, can be nil
Log *slog.Logger
// Server name. Used to separate logs and metrics when having multiple servers in one binary.
ServerName string
// Max size of the request payload
MaxRequestBodySizeBytes int64
// If true payload signature from X-Flashbots-Signature will be verified
Expand Down Expand Up @@ -121,10 +123,10 @@ func (h *JSONRPCHandler) writeJSONRPCResponse(w http.ResponseWriter, response js
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
if h.Log != nil {
h.Log.Error("failed to marshall response", slog.Any("error", err))
h.Log.Error("failed to marshall response", slog.Any("error", err), slog.String("serverName", h.ServerName))
}
http.Error(w, errMarshalResponse, http.StatusInternalServerError)
incInternalErrors()
incInternalErrors(h.ServerName)
return
}
}
Expand All @@ -150,19 +152,19 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

defer func() {
incRequestCount(methodForMetrics)
incRequestDuration(methodForMetrics, time.Since(startAt).Milliseconds())
incRequestCount(methodForMetrics, h.ServerName)
incRequestDuration(methodForMetrics, time.Since(startAt).Milliseconds(), h.ServerName)
}()

if r.Method != http.MethodPost {
http.Error(w, errMethodNotAllowed, http.StatusMethodNotAllowed)
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}

if r.Header.Get("Content-Type") != "application/json" {
http.Error(w, errWrongContentType, http.StatusUnsupportedMediaType)
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}

Expand All @@ -171,7 +173,7 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err != nil {
msg := fmt.Sprintf("request body is too big, max size: %d", h.MaxRequestBodySizeBytes)
h.writeJSONRPCError(w, nil, CodeInvalidRequest, msg)
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}

Expand All @@ -180,7 +182,7 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
signer, err := signature.Verify(signatureHeader, body)
if err != nil {
h.writeJSONRPCError(w, nil, CodeInvalidRequest, err.Error())
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}
ctx = context.WithValue(ctx, signerKey{}, signer)
Expand All @@ -190,13 +192,13 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var req jsonRPCRequest
if err := json.Unmarshal(body, &req); err != nil {
h.writeJSONRPCError(w, nil, CodeParseError, err.Error())
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}

if req.JSONRPC != "2.0" {
h.writeJSONRPCError(w, req.ID, CodeParseError, "invalid jsonrpc version")
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}
if req.ID != nil {
Expand All @@ -205,7 +207,7 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
default:
h.writeJSONRPCError(w, req.ID, CodeParseError, "invalid id type")
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}
}
Expand All @@ -228,7 +230,7 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if origin != "" {
if len(origin) > maxOriginIDLength {
h.writeJSONRPCError(w, req.ID, CodeInvalidRequest, "x-flashbots-origin header is too long")
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}
ctx = context.WithValue(ctx, originKey{}, origin)
Expand All @@ -239,7 +241,7 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
method, ok := h.methods[req.Method]
if !ok {
h.writeJSONRPCError(w, req.ID, CodeMethodNotFound, "method not found")
incIncorrectRequest()
incIncorrectRequest(h.ServerName)
return
}
methodForMetrics = req.Method
Expand All @@ -248,14 +250,14 @@ func (h *JSONRPCHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
result, err := method.call(ctx, req.Params)
if err != nil {
h.writeJSONRPCError(w, req.ID, CodeCustomError, err.Error())
incRequestErrorCount(methodForMetrics)
incRequestErrorCount(methodForMetrics, h.ServerName)
return
}

marshaledResult, err := json.Marshal(result)
if err != nil {
h.writeJSONRPCError(w, req.ID, CodeInternalError, err.Error())
incInternalErrors()
incInternalErrors(h.ServerName)
return
}

Expand Down
41 changes: 21 additions & 20 deletions rpcserver/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,46 @@ import (
"github.com/VictoriaMetrics/metrics"
)

var (
// incremented when user made incorrect request
incorrectRequestCounter = metrics.NewCounter("goutils_rpcserver_incorrect_request_total")
// incremented when server has a bug (e.g. can't marshall response)
internalErrorsCounter = metrics.NewCounter("goutils_rpcserver_internal_errors_total")
)

const (
// we use unknown method label for methods that server does not support because otherwise
// users can create arbitrary number of metrics
unknownMethodLabel = "unknown"

// incremented when user made incorrect request
incorrectRequestCounter = `goutils_rpcserver_incorrect_request_total{server_name="%s"}`

// incremented when server has a bug (e.g. can't marshall response)
internalErrorsCounter = `goutils_rpcserver_internal_errors_total{server_name="%s"}`

// incremented when request comes in
requestCountLabel = `goutils_rpcserver_request_count{method="%s"}`
requestCountLabel = `goutils_rpcserver_request_count{method="%s",server_name="%s"}`
// incremented when handler method returns JSONRPC error
errorCountLabel = `goutils_rpcserver_error_count{method="%s"}`
errorCountLabel = `goutils_rpcserver_error_count{method="%s",server_name="%s"}`
// total duration of the request
requestDurationLabel = `goutils_rpcserver_request_duration_milliseconds{method="%s"}`
requestDurationLabel = `goutils_rpcserver_request_duration_milliseconds{method="%s",server_name="%s"}`
)

func incRequestCount(method string) {
l := fmt.Sprintf(requestCountLabel, method)
func incRequestCount(method, serverName string) {
l := fmt.Sprintf(requestCountLabel, method, serverName)
metrics.GetOrCreateCounter(l).Inc()
}

func incIncorrectRequest() {
incorrectRequestCounter.Inc()
func incIncorrectRequest(serverName string) {
l := fmt.Sprintf(incorrectRequestCounter, serverName)
metrics.GetOrCreateCounter(l).Inc()
}

func incRequestErrorCount(method string) {
l := fmt.Sprintf(errorCountLabel, method)
func incRequestErrorCount(method, serverName string) {
l := fmt.Sprintf(errorCountLabel, method, serverName)
metrics.GetOrCreateCounter(l).Inc()
}

func incRequestDuration(method string, duration int64) {
l := fmt.Sprintf(requestDurationLabel, method)
func incRequestDuration(method string, duration int64, serverName string) {
l := fmt.Sprintf(requestDurationLabel, method, serverName)
metrics.GetOrCreateSummary(l).Update(float64(duration))
}

func incInternalErrors() {
internalErrorsCounter.Inc()
func incInternalErrors(serverName string) {
l := fmt.Sprintf(internalErrorsCounter, serverName)
metrics.GetOrCreateCounter(l).Inc()
}

0 comments on commit a80f258

Please sign in to comment.